lehmann21: Java rechnet falsch!

System.out.println(1.1 * 100);

=> 110.00000000000001

Bei Nachforschungen über dieses unerwartete Ergebnis habe ich folgendes Dokument gefunden:
http://www.cs.berkeley.edu/~wkahan/JAVAhurt.pdf

und siehe da:
Java implementiert IEE754 nicht korrekt bzw. vollständig und verrechnet sich dadurch bei Gleitkommazahlberechnungen.

BUH!

  1. Hallo,

    System.out.println(1.1 * 100);

    => 110.00000000000001

    Das wird dir vermutlich bei jeder Sprache/Library, die IEE754 verwendet,
    passieren. Eine Erklärung, die ich auf die Schnelle für genau dein Zahl-
    Beispiel gefunden habe, gibt es z.B. in der Python-Doku:
    http://www.python.org/doc/2.4.4/whatsnew/node9.html

    Java implementiert IEE754 nicht korrekt bzw. vollständig und verrechnet sich dadurch bei Gleitkommazahlberechnungen.

    Ich habe den Artikel nicht gelesen. Möglich, daß Java das nicht tut.
    (Ich halte es persönlich für eher unwahrscheinlich, aber ok.) Dein
    Beispiel hat jedenfalls damit nichts zu tun.

    BUH!

    ...

    Gruß
    Slyh

    1. Java implementiert IEE754 nicht korrekt bzw. vollständig und verrechnet sich dadurch bei Gleitkommazahlberechnungen.

      Ich habe den Artikel nicht gelesen. Möglich, daß Java das nicht tut.
      (Ich halte es persönlich für eher unwahrscheinlich, aber ok.) Dein
      Beispiel hat jedenfalls damit nichts zu tun.

      Mein Beispiel hat vielleicht doch damit zutun:
      Komischerweise ist nämlich die Darstellung von 1,1; 1,1 * 10 und 1,1 * 1000 korrekt - der Fehler hängt also nicht (nur) von der Darstellung bestimmter Zahlen sondern von den ausgeführten arithmetischen Operation ab. Um solche Ungenauigkeiten zu verhindern, sieht IEEE754 eine Rundung der Werte vor. Schlampt hier Java eventuell genauso, wie bei der Typumwandlung von Gleitkommazahlen zu Ganzzahlen (Nachkommastellen werden einfach abgeschnitten)?

      1. Hallo,

        Mein Beispiel hat vielleicht doch damit zutun:
        Komischerweise ist nämlich die Darstellung von 1,1; 1,1 * 10 und 1,1 * 1000 korrekt - der Fehler hängt also nicht (nur) von der Darstellung bestimmter Zahlen sondern von den ausgeführten arithmetischen Operation ab.

        Wie dem von mir verlinkten Dokument zu entnehmen ist, kann die Ausgabe(!)
        tatsächlich "korrekt" sein. Die interne Repräsentation von 1.1 bleibt
        aber nunmal die gleiche.

        Um solche Ungenauigkeiten zu verhindern, sieht IEEE754 eine Rundung der Werte vor. Schlampt hier Java eventuell genauso, wie bei der Typumwandlung von Gleitkommazahlen zu Ganzzahlen (Nachkommastellen werden einfach abgeschnitten)?

        Letzteres ist eine Konvention. Das ist keine Schlamperei, sondern
        Absicht und in jeder mir bekannten Sprache so umgesetzt. (Das hat
        sicherlich auch damit zu tun, daß aus einem 5/2 bei Ganzzahlrechnung
        eben auch nicht 3, sondern 2 wird. Und das ist seit den ersten
        Prozessoren so. Wieso sollte es bei Casts anders sein?)

        Gruß
        Slyh

      2. Hej,

        Schlampt hier Java eventuell genauso, wie bei der Typumwandlung von Gleitkommazahlen zu Ganzzahlen (Nachkommastellen werden einfach abgeschnitten)?

        Wie sollte denn deines Erachtens ein Cast von z.B. double auf int sonst vorgenommen werden? Das was du Schlamperei nennst wird weitläufig als "round-towards-zero" bezeichnet, entspricht AFAIR der IEE_E_754 und ist in der Java-Spec so festgelegt.

        Beste Grüße
        Biesterfeld

        --
        Art.1: Et es wie et es
        Art.2: Et kütt wie et kütt
        Art.3: Et hätt noch immer jot jejange
        Das Kölsche Grundgesetz
    2. Ich habe den Artikel nicht gelesen. Möglich, daß Java das nicht tut.
      (Ich halte es persönlich für eher unwahrscheinlich, aber ok.) Dein
      Beispiel hat jedenfalls damit nichts zu tun.

      ok, überzeugt: mit C/C++ kommt das selbe raus:

      printf("%.17g\n", 1.1 * 100);

      => 110.00000000000001