Eclipse Verschiedene Ergebnisse bei Berechnung eines double-Werts

Red*Star

Mitglied
Hallo zusammen,

falls mir jemand für folgendes eine Erklärung geben kann, würde ich mich freuen:

Im angehängten Screenshot (die wichtigen Zeilen habe ich euch rot eingekreist) berechne ich frac auf zwei verschiedene Arten und Weisen:
Entweder direkt aus halfX.getDuration() (-> Wert landet in "frac2"), oder mit einem klitzekleinen Umweg über die Variablen val1 und val2 (-> Wert landet in "frac").

Die Frage ist ganz einfach: Wieso ist das Ergebnis unterschiedlich (siehe Debugger oben)?

getDuration() liefert einen long-Wert (Dauer in Milliseconds) zurück, bei dem habe ich auch überprüft, dass da wirklich 148 bzw. 216 Tage drinstehen. So oder so: M.E. sind die beiden Codestücke semantisch identisch...
Dass unterschiedliche Auswertungsreihenfolgen bei double/float nicht zu identischen Ergebnissen führen, ist mir natürlich auch klar - aber das ist ja gerade der Punkt: Hier gibt es ja eben keine unterschiedliche Auswertungsreihenfolge...

Das einzige, was ich mir noch denken könnte, wäre, dass der Debugger mir Müll ausgibt, das wäre dann aber jetzt auch das erste Mal.

Kennt jemand des Rätsels Lösung? Ist ein recht altes eclipse, vielleicht ist auch das noch eine mögliche Fehlerquelle...

(Bevor irgendwelche Kommentare über grottenschlechten Code-Style kommen: Ja, ich weiß 😉. Er sieht so schlimm aus, weil ich gerade ziemlich rumgehacked habe, um dieses "lustige" Problem einzukreisen.)
 

Anhänge

  • screenshot_java_eclipse_cut.png
    screenshot_java_eclipse_cut.png
    60,2 KB · Aufrufe: 61
Nun, man müßte sich mal mit
javap -c DasProgram.class
den bytecode ansehen. Die JVM arbeitet stack-basiert, d.h. was da wann ausgewertet wird, ist nicht so leicht zu sagen. Dazu kommt noch, dass Prozessoren intern AFAIK mit 80 bit rechnen, auch wenn es nur um 64bit-Werte geht. Aber das ist eher Halbwissen. Schau' mal was rauskommt, wenn du deine Klasse als
public class strictfp DieKlasse
deklarierst.
 
Ich vermute, dass das an der auswertungsreihenfolge liegt.

haben wir z.B. folgendes:
Java:
double small1 = 1.8355854432e-20;
double small2 = 1.4755467546766e-20;
double big1 = 5.5643634737346;
double big2 = 10.235525238257253;

Jetzt ist es für die genauigkeit ein unterschied, ob du
Java:
double result1 = (small1 * small2) * (big1*big2);
rechnest, oder
Java:
double result2 = ((small1 * big1) * small2) * big2;
rechnest.

Danach ist dann
result1 == 1.5425995658095722E-38
result2 == 1.5425995658095724E-38

Der grund ist, dass beim verrehnen von fließpunktzahlen, bei denen die größenordnungen verschieden sind, einige stellen "verworfen" werden müssen.
Wenn du zuerst die zahlen mit ähnlichen größenordnungen verrechnest und am ende den rest multiplizierst, dann sollte das ergebnis genauer sein.
Ich vermute aber, dass der compiler die reihenfolge ändern darf.

Hier kann man die Abweichung sehen:
Ideone.com | Online Java Compiler & Debugging Tool
 
Hast du dir meinen Code angesehen, P@u1 ? 😉 Rein vom Code her ist die Reihenfolge identisch, der einzige Unterschied ist, dass ich die Ergebnisse der Konvertierungsaktion von long in double zwischenspeichere - sprich dein Argument ist zwar generell richtig, aber passt nicht auf meinen Code.

@Marco13: Die Disassemblierung hab ich mir nicht angeschaut, aber die strictfp-Variante hab ich mal probiert. Danke, das hat es "gefixed" (sofern man das bei floating point values so nennen kann). Laut Computeralgebraprogramm ist die numerische Approximation auf 10 Stellen von 148/216 gleich 0.6851851851, genau das kommt jetzt auch in beiden Fällen raus. Man lernt wirklich nie aus 😉. Warum das jetzt vorher ungenauer war, wenn auf der FPU intern u.U. mit höherer Genauigkeit gerechnet wurde, bleibt mir aber schleierhaft 😉.
 

Neue Themen


Zurück
Oben