Widersprüchliche Rechenergebnisse



  • Ich würde einen Erfahrenen mal bitten, sich das hier kurz anzugucken. Dadurch bin ich damals auf die Lösung des Problems, bzw eher gesagt, warum das so ist, gekommen.

    http://www.tutorials.de/c-c/381980-problem-gleitkommatypen-assoziativgesetz.html#post1975101



  • Ist jetzt nur eine Vermutung, aber evtl. wird die Addition im letzten Fall einfach wegoptimiert, da sinnlos. Also hast du da evtl. einfach nur

    std::cout << a << std::endl;
    

    stehen.

    Im vorherigen Fall müssen die Additionen aber tatsächlich durchgeführt werden, weil du ein Zwischenergebnis ausgibst, da kann nicht optimiert werden.

    Ist nur eine Vermutung, klingt für mich aber plausibel. 🙂


  • Mod

    mantiz schrieb:

    Ist jetzt nur eine Vermutung, aber evtl. wird die Addition im letzten Fall einfach wegoptimiert, da sinnlos.

    Nein, Fließkommaoperationen können in der Regel nicht wegoptimiert werden, da die Regeln sehr kompliziert sind. Siehe eben dieses Beispiel, wieso das nicht einfach alles weggekürzt werden kann. Es ist schon immer wieder für eine Überraschung gut, wenn gewisse Operationen zur Compilezeit durchgeführt werden (das könnte hier übrigens tatsächlich passieren, wenn man die Optimierungen anschaltet), weil die dann auch gerne mal mit anderer Präzision durchgeführt werden als man das erwarten würde (z.B. mit 64-Bit-Genauigkeit, anstatt mit 80-Bit). Ich habe oben schon genau erklärt, was vermutlich passiert.



  • climits schrieb:

    Also 1.19209e-07 ist in der "recheninternen Repräsentation" einmal die Mantisse 1.19209 sowie der Exponent e-07, sowie die jeweiligen Vorzeichen bits der beiden.

    Nö - Dein PC denkt binär, nicht dezimal

    climits schrieb:

    für die binäre Darstellung aller Werte müsst ich mich erst mal ne Weile hinhocken.

    rechne mal 2^-23 aus 😉



  • Wobei ich aber nicht sehe, wo hier die cancellation zum Tragen kommt. s1 = a+b = 1.0000001234567 gibt ja gerundet auf 6 Nachkommstellen wieder 1.000000. s1 + c = 1.000000 - 1.000000 müsste ja dann 0 ergeben ???

    Edit
    @ Walter
    Oh eh, verblüffend 😃



  • Rechne deinen Code z.B. mal mit setprecision(20), dann wirst du erkennen, dass bei den bei den ersten ausgegebenen Werten auf den letzten Nachkommastellen ein Unterschied ist, obwohl nur 1 subtrahiert wurde



  • xStrykex schrieb:

    http://www.tutorials.de/c-c/381980-problem-gleitkommatypen-assoziativgesetz.html#post1975101

    wenn du die nicht geltende assoziativität meinst ist das nichts neues. dass es ungeneuigkeiten gibt beim rechnen mit gleitkomma zahlen lernt men sehr schnell. dass man diesem "phänomen" einen name gibt bzw. es mit fehlender assoziativiät ausdrückt kam bei uns dann im ersten semester in der programmier vorlesung

    kleines beispiel:

    float x = 2304.0f;
    float y = -4096.0f;
    float z = 4096.001953125f;
    
    float e1 = x*(y+z);
    float e2 = x*y + x*z;
    
    cout << e1 << " == " << e2 << " (laut der Mathematik!)" << endl;
    


  • climits schrieb:

    die 1.234567e-7 kann ich nachvollziehen.

    .. glaub' ich nicht. Ersetze mal Zeile 13 durch

    std::cout << b+c+a << std::endl;
    

  • Mod

    Hier noch was zum Spielen:
    http://www.binaryconvert.com/index.html



  • whuups, wo sind denn die ganzen Antworten hergekommen?
    Ich glaub ich muss das dann wirklich erstmal rein binär machen, damit es Sinn ergibt. Danke für die vielen Antworten. Muss ich mal alles durchgehen



  • naja, übertreiben muss mans nicht.

    versuch einfach mal die 3.75 binär darzustellen (da reichen 8bit locker aus)
    und danach fängst du mal die 3.6 an...



  • SeppJ schrieb:

    mantiz schrieb:

    Ist jetzt nur eine Vermutung, aber evtl. wird die Addition im letzten Fall einfach wegoptimiert, da sinnlos.

    Nein, Fließkommaoperationen können in der Regel nicht wegoptimiert werden, da die Regeln sehr kompliziert sind. Siehe eben dieses Beispiel, wieso das nicht einfach alles weggekürzt werden kann. Es ist schon immer wieder für eine Überraschung gut, wenn gewisse Operationen zur Compilezeit durchgeführt werden (das könnte hier übrigens tatsächlich passieren, wenn man die Optimierungen anschaltet), weil die dann auch gerne mal mit anderer Präzision durchgeführt werden als man das erwarten würde (z.B. mit 64-Bit-Genauigkeit, anstatt mit 80-Bit). Ich habe oben schon genau erklärt, was vermutlich passiert.

    Ok, auch wenn es nicht wegoptimiert wird, so ergibt sich durch die rechts-assioziativität von "+", dass erst "b+c" gerechnet wird, was "0" ergibt, also bleibt nur "a" übrig, was von den Auswirkungen her das gleiche ist. 🙂

    Hab's jetzt nur mal schnell im Taschenrechner nachvollzogen, wenn ich "a+b" auf 8 Nachkommastellen abschneide und anschließend "+c", also "-1" rechne, dann lande ich bei "1,19...e-7". Die Nachkommastellen unterscheiden sich zwar noch, aber mir ist das Ergebnis nah genug dran. Dann würde ich das also auf die rechts-assioziativität schieben. 😉


  • Mod

    mantiz schrieb:

    Hab's jetzt nur mal schnell im Taschenrechner nachvollzogen, wenn ich "a+b" auf 8 Nachkommastellen abschneide und anschließend "+c", also "-1" rechne, dann lande ich bei "1,19...e-7". Die Nachkommastellen unterscheiden sich zwar noch, aber mir ist das Ergebnis nah genug dran. Dann würde ich das also auf die rechts-assioziativität schieben. 😉

    Tja, nur leider kommt bei c + b + a auch 1.23457e-07 heraus:
    http://ideone.com/RAuLpg



  • Ok, ich gebe auf. 😉

    Bei "c + a + b" tritt der "Fehler" übrigens auf: http://ideone.com/OOQr41


  • Mod

    mantiz schrieb:

    Ok, ich gebe auf. 😉

    Bei "c + a + b" tritt der "Fehler" übrigens auf: http://ideone.com/OOQr41

    Und deswegen muss man immer genau aufpassen, welche Größenordnungen bei Zahlen zu erwarten sind und wie man daher seine Ausdrücke genau aufschreibt. Numerik ist nicht einfach.



  • Hab das Problem mit der numerischen Auslöschung jetzt weitgehend hinterstiegen. Der ganze Rest mit fehlender Assoziativität und so weiter ist dann aber scheinbar doch noch etwas komplizierter.
    Um hier noch auf einzelne Posts einzugehen:

    Werner_logoff schrieb:

    climits schrieb:

    die 1.234567e-7 kann ich nachvollziehen.

    .. glaub' ich nicht. Ersetze mal Zeile 13 durch

    std::cout << b+c+a << std::endl;
    

    Kommt bei mir wieder das selbe, also 1.234567e-7 raus, was aber auch nicht verwunderlich ist denn auch hier..

    mantiz schrieb:

    Bei "c + a + b" tritt der "Fehler" übrigens auf: http://ideone.com/OOQr41

    Tritt der Fehler bei mir nicht auf, bzw. ich kriege wieder 1.234567e-7 statt 1.19209e-07 ausgegeben. Keine Ahnung woran das liegt. Vielleicht weil ich einen AMD nutze? Mit Rechenarchitektur kenn ich mich nun überhaupt nicht aus.
    Wundern tut es mich aber dass es zumindest bei mantiz und auf der Internetseite tatsächlich einen Unterschied macht, ob man nun a+b+c oder c+a+b rechnet. Da wird in einem Fall dann wie SeppJ meinte, wohl das "Rechenwerk" mit 80 bit genutzt (oder SSE, x87...) und im anderem Fall aus irgendwelchen Gründen nicht.


Anmelden zum Antworten