casten....
-
Ich möchte ein Programm schreiben, daß eine float-Zahl in Vorzeichen, Mantisse und Exponent aufdröselt. Beim Berechnen des Exponenten habe ich ein Problem:
Da es keinen 2er-log gibt, berechne ich diesen mit dem log zur Basis e. Mit: log(a)/log(e) erhalte ich das gewünschte Ergebnis (in der Theorie!). Für einen Wert von a = 11,25 müßte ein Exponent von 3 herauskommen. Das Programm (s.u. errechnet aber 2! Ich vermute, daß es irgendwas mit dem casten zu tun hat, da Zeile 3 (im Abschnitt "Exponent") 3,459 ausspuckt. (Also zumindest ein annährnd richtiger Wert. Exakt wäre 3,49185...)Vielen Dank für die Hilfe....
P.S.: OS ist Linux, Compiler gcc
#include <stdio.h> #include <math.h> int main() { float a; a = 11,25; unsigned int m; // Mantisse int e; // Exponent int s; // Sign // *** Vorzeichen - Flag *** if (a<0) s = 1; else s = 0; // *** Exponent ************ printf("log(abs(a)) = %f\n", log(abs(a))); // Zeile 1 printf("log(2) = %f\n", log(2)); // Zeil 2 printf("log(abs(a))/log(2) = %f\n", log(abs(a))/log(2)); // Zeile 3 printf("log(abs(a))/log(2) = %d\n", ((int) log(abs(a))/log(2))); // Zeile 4 test = (int) log(abs(a))/log(2); // Zeile 5 printf("test = %d\n", test); // Zeile 6 e = (int) log(abs(a))/log(2); // Zeile 7 // *** Mantisse ************ printf("2^e = %f\n", pow(2,e)); printf("a/2^e = %f\n", a/pow(2,e)); m = ((a/pow(2,e))-1)*8388608; return 0; }
-
toolen schrieb:
a = 11,25;
Das Dezimaltrennzeichen ist ein Punkt, kein Komma.
-
- Peinlich -
Ändert aber an dem Problem nichtsGruß
-
toolen schrieb:
Mit: log(a)/log(e) erhalte ich das gewünschte Ergebnis (in der Theorie!).
Wie kommst du darauf? log(e) ist 1.
Den Logarithmus zur Basis 2 ermittelst du, indem du den natürlichen Logarithmus durch den natürlichen Logarithmus von 2 teilst:
double log2a = log(a) / log(2);
Nachtrag. Bei:
e = (int) log(abs(a))/log(2)
wandelst du nur den Teil log(abs(a)) nach int um, nicht das Ergebnis der Division.
-
puh, ok. Nochmal ein Fehler.
aber nur in der Erklärung. Im code (z.B. Zeile 7, Exponent-Teil) ist es richtig:
log(abs(a))/log(2)
Gruß
-
Bingo!
dat war et! Vielen Dank!
-
Tja zu früh gefreut...
#include <stdio.h> #include <math.h> #define NEIN 0 #define JA 1 void darst_bin(unsigned int zahl); int main() { int debug=JA; float a; a = 11.25; unsigned long m; // Mantisse unsigned long e; // Exponent unsigned long s; // Sign int feld[16]; printf("**********************************\n\n"); printf("* Umzuwandelnde Zahl = %f \n\n", a); printf("**********************************\n"); // *** Vorzeichen - Flag *** if (a<0) s = 1; else s = 0; if(debug) printf("**DEBUG**:\n Sign-Flag = %u\n", s); // *** Exponent ************ e = 127 + (int) (log(abs(a))/log(2)); if(debug) printf("**DEBUG**:\n Exponent = %u\n", e); darst_bin(e); // *** Mantisse ************ printf("Mantisse = %u\n", (unsigned int) (((abs(a)/pow(2,e-127))-1)*pow(2,23))); m = (unsigned int) (((abs(a)/pow(2,e-127))-1)*pow(2,23)); if(debug) printf("**DEBUG**:\n Mantisse = %u\n", m); darst_bin(m); return 0; } void darst_bin(unsigned int zahl) { int count; printf("%u (10) = ", zahl); for (count=23; count >= 0; count--) { if (zahl / (int) pow(2,count)) { zahl = zahl % (int) pow(2,count); printf("1"); } else printf("0"); } printf(" (2)\n"); }
Das Problem ist jetzt, daß zum Beispiel bei der Umwandlung von 11,25 (wie im Quellcode angegeben), die Mantisse mit 3145728 berechnet wird. Tatsächlich ist laut
[url]
http://de.wikipedia.org/wiki/Gleitkommazahl#Berechnung_einer_IEEE_single_Gleitkommazahl_.2832-Bit-Gleitkommazahl.29
[/url]
die Mantisse 3407872. Mein Taschenrechner meint das gleiche. Es muss also an dem Quellcode hier liegen. Um zu verhindern, daß die Zahlen abgeschnitten werden, habe ich die Mantisse als unsigned long deklariert.Ich würde mich freuen, wenn mir jemand helfen könnte.
Viele Grüße, toolen
P.S: die Formeldn für die Berechnung der Mantisse und dem Exponenten habe ich ebenfalls von o.g. Link
-
In C gibt abs immer int zurück. Nimm fabs.
-
toolen schrieb:
Ich möchte ein Programm schreiben, daß eine float-Zahl in Vorzeichen, Mantisse und Exponent aufdröselt. Beim Berechnen des Exponenten habe ich ein Problem:
Also wenn es dir nur um das "Aufdröseln" geht, warum berechnest du die Werte überhaupt? Du kannst sie ja aus dem Float direkt rausziehen. Das wäre schneller und einfacher.
-
Hallo,
@TactX: Angenommen, ich habe eine Variable a:
float a = -11,75;
Wie erhalte ich dann das 1., 2., 3.,.... Bit?
Ein float - Pointer auf die Variable kann es ja nicht sein, oder?Gruß, toolen
-
Ausnahmsweise mal fertiger Code:
#include <stdio.h> int main(void){ unsigned int *fakefloat; float zahl; unsigned int mant; // Mantisse unsigned int expo; // Exponent unsigned int sign; // Sign zahl=11.25; // Wir nehmen an, dass sizeof(unsigned int)==sizeof(float) fakefloat=&zahl; // Spuckt natuerlich eine Warnung aus // Ueber Bitshifts und Bitmasken ziehen wir die einzelnen Komponenten raus sign = *fakefloat >> 31; expo = *fakefloat >> 23 & 0x7FFFFFFF; mant = *fakefloat & 0x7FFFFF; printf("Sign = %u\nExpo = %u\nMant = %u\n", sign, expo, mant); return 0; }
-
Herzlichen Dank für die Antwort,
eine Frage noch, die mich etwas verunsichert:
würde es nicht reichen, anstatt:
expo = *fakefloat >> 23 & 0x7FFFFFFF;
folgendes zu schreiben:
expo = *fakefloat >> 23 & 0xFF;
Der Exponent wird ja nur mit 8 Bit dargestellt.
Kann man den gcc anweisen, Warnungen nicht anzuzeigen?
Gruß und nochmal Danke!
-
Jo, du hast vollkommen recht. 0x7FFFFFFF ist falsch (bring bei negativem Vorzeichen einen falschen Exponenten).
Die Warnung kannst du durch einen Cast unterdrücken:
fakefloat=(unsigned int *)&zahl;
EDIT: 0x7FFFFFFF wäre korrekt, wenn man zuerst die Verundung und dann erst die Shifterei gemacht hätte. Hab das irgendwie verwechselt.