float und double komisch ungenau !!



  • Hi,

    hab gerade mal folgendes eingegeben:

    float a=0.05f;
    double b=0.05;
    

    und hab dann debugged.
    Nach der Ausführung bekomme ich im Debugger angezeigt:

    a=0.050000001
    b=0.050000000000000003

    Wie jetzt das ? warum ist die letzte Ziffer nicht 0 ?
    (math.h eingebunden)
    Ich frage das, weil ein 0.03 = 0.029999999999 ist und mir irgendwie in die
    Suppe spuckt. Was geht hier ab ? ein atof funktioniert übrigens auch sehr
    komisch mit diesen ungenauen Werten was sehr schlecht für die Benutzereingabe ist.

    Um jeden Hinweiss dankbar, kann mit der Suche leider nichts entsprechendes finden.

    Gruß
    thenoname



  • Das Problem ist, dass 0,05 wahrscheinlich nicht genau dargestellt werden kann. Ich hab's jetzt nicht bis ins letzte Bit nachgerechnet, wird aber so sein. Nach IEEE wird ein double in 1 Bit Vorzeichen, 8 Bit Exponent(Bias 127) und 23 Bit Mantisse (Binär) kodiert. Dabei wird die Mantisse (binär) auf z.B. 1,1010... genormt, also immer 1,..., die 1 vor dem Komma wird dann weggelassen und nur die Nachkommastellen kodiert.
    Bei 0,05 würde das so aussehen:

    Dezimal   Binär
    0,5       0,1
    0,25      0,01
    0,125     0,001
    0,0625    0,0001
    0,03125   0,00001  (passen)
    0,015625  0,000001 (passen)
    ...
    

    0.5, 0.25 und 0.125 kann man nicht nehmen, weil diese bereits die erste Nachkommastelle füllen, was bei 0.05 nicht sein darf. 0.0625 ist größer als 0.05, wird also auch ausgelassen, also beginnt man bei der nächsten und addiert so lange, wie das Ergebnis nicht größer wird also die Zahl, die man sucht. Hier erhält man für die beiden Potenzen (von oben, die passen):
    0,000011
    Normiert: 1,1 (Exponent -5)

    Kodiert also:
    0|01111010|10000000000000000000000

    Wenn man nun zurückrechnet, dann holt man sich das Vorzeichen, das ist 0, also positiv, den Exponent, der ist hier als 122 kodiert, Bias ist 127, also 122-127=-5 und bei der Mantisse denkt man sich eine 1 davor, erhält also 1,1(binär).

    Dann rechnet man:
    1,1 * 2^(-5) = 0,000011 (binär) = 0,046875 (dezimal).

    Daher kommen die Unstimmigkeiten. Ich bin jetzt nur bis zur 6. Nachkommastelle (binär) gegangen, wenn man wirklich bis zur 23. geht, dann entstehen noch Überträge etc., die das Ergebnis dann ziemlich genau werden lassen, aber halt nicht 100%-ig.

    Daher sollte man auch nie zwei doubles beispielsweise mit "==" vergleichen.

    Bei Float weiß ich nicht genau, wie's kodiert wird, aber da gibt es aus ähnlichen Gründen Ungenauigkeiten.



  • Eine einfachere Grobprüfung: Die Zahl als (gekürzten) Bruch darstellen. Ist der Nenner eine Potenz von 2, passt's, sonst nicht.

    0.05 = 1/20. Zwanzig ist keine Potenz von 2 -> passt nicht.



  • wen du es genau haben wilst must du eine DECIMAL klaße nutzen^^

    PS was hat das mit WinAPI zu tun!



  • strummelbunzi schrieb:

    [...] klaße [...]

    Ja klar ... 🙄

    @MFK: Danke für den Hinweis der Grobprüfung. 🙂



  • Danke erstmal für die vielen Antworten,
    das mit der Klasse DECIMAL probier ich doch gleich mal aus.

    strummelbunzi schrieb:

    PS was hat das mit WinAPI zu tun!

    -> hatte leider keine Ahnung wohin damit 😉

    Hat die Klasse DECIMAL auch sowas wie atof ?
    Damit ich meine Editboxen übergeben kann ?

    Mist, ich seh gerade das DECIMAL gar kein 0.05 nimmt ??
    Habt ihr ein Beispiel dafür ?



  • Dieser Thread wurde von Moderator/in Jochen Kalmbach aus dem Forum WinAPI in das Forum ANSI C verschoben.

    Im Zweifelsfall bitte auch folgende Hinweise beachten:
    C/C++ Forum :: FAQ - Sonstiges :: Wohin mit meiner Frage?

    Dieses Posting wurde automatisch erzeugt.


Anmelden zum Antworten