# Problem beim Subtrahieren eines Double von einem Double



## ajva (8. Apr 2008)

Hallo. 

Was mache ich falsch wenn ich ein Double des Wertes 3.5 von einem Double des Wertes 3.9 abziehe und statt 0.4 Folgendes erhalte?

3.9 - 3.5 = 0.3999999999999999

Die Doubles habe ich mittels Double.parseDouble() aus einem String gefischt.

Danke schonmal fürs lesen.


----------



## Marco13 (8. Apr 2008)

Im allgemeinen haben Kommazahlen ein beschränkte genauigkeit. Einige Zahlen können nicht exakt dargestellt werden, so ähnlich wie man 1.0/3.0 im Dezimalsystem nicht genau darstellen kann (weil es periodisch ist).

http://docs.sun.com/source/806-3568/ncg_goldberg.html

EDIT: Genaugenommen können _fast alle_ Zahlen nicht genau dargestellt werden. Erschreckend, eigentlich  :shock: :wink:


----------



## ajva (8. Apr 2008)

Danke für Deine Antwort Marco13.

Richtig. 0.33333 != 1/3. Das ist mir klar und da wäre ich mit einer Rundung auf ein paar Kommastellen auch zufrieden. Aber in meinem Programm wird grundsätzlich mit nicht mehr als einer Stelle hinter dem Komma gerechet und es wird immer nur eine Differenz berechnet. 

Und meines Erachtens kann 3.9 - 3.5 im Dezimalsystem dargestellt werden. Und zwar so: 0.4 ;-)

Ich kann die beiden beteiligten Zahlen mit 10 multiplizieren und das Ergebnis durch 10 teilen. Dann habe ich die 0.4. Aber das muss doch auch ohne diesen "Aufwand" gehen.


----------



## SlaterB (8. Apr 2008)

diese Behauptung ist haltlos, da Computer kein Dezimalsystem verwenden,
und selbst wenn man sich noch die Mühe machen würde, fürs Binärsystem nachzuschauen,
dann reicht auch das nicht,
denn es kann immer noch sein (was der Fall ist), dass die Zahl im double ganz anders gespeichert wird,
da muss 2^1000 reinpassen wie auch 2^-1000,
die paar Bits dieses Datentyps sind ziemlich beansprucht, da musst du verzeichen, dass bestimmte Spezialfälle Probleme machen

ein viel interessanteres Argument ist, dass du andererseits mit
double d = 0.4;
die 0.4 korrekt ohne Rundungsprobleme speichern kannst 

warum dass so ist habe ich auch noch nicht ganz verstanden oder vergesse es immer wieder 
Details stehen im verlinkten Dokument


----------



## Marco13 (8. Apr 2008)

Wie SlaterB schon gesagt hat, mögen Computer das Dezimalsystem nicht so. Vermutlich, weil sie keine 10 Finger haben, sondern nur einen Stecker, mit dem sie an der Steckdose hängen - oder eben nicht :wink:

Etwas weniger tiefgehend, dafür aber "übersichtlicher" wird die Darstellung von Floating-Point-Zahlen z.B. hier beschrieben: http://en.wikipedia.org/wiki/IEEE_floating-point_standard

@SlaterB: Der Grund dafür, dass der Fehler bei x=3.9-3.5 auftritt, aber NICHT bei x=0.4 (und auch NICHT bei x=0.9-0.5 :!: ) ist, wenn ich mich nicht irre, das was als "Cancellation" bezeichnet wird. GANZ grob: Die Zahlen, die voneinander abgezogen werden, sind so groß, und die Differenz so klein, dass für die _Darstellung_ der Differenz "andere" Bits benötigt würden, als für ihre _Berechnung_. (Wirklich, SEHR grob  :roll: )

Besonders deutlich sieht man das, wenn man sich mal die Bits anguckt:

```
class DoubleTest3
{
    public static void main(String args[])
    {
        double a = 0.4; // Das gewünschte Ergebnis
        double b = 1.9 - 1.5; // Der Exponent dieser beiden Zahlen ist größer als der Exponent des gewünschten Ergebnisses
        double c = 0.9 - 0.5; // Der Exponent dieser beiden Zahlen ist der gleiche wie der Exponent des gewünschten Ergebnisses
        System.out.println(a);
        System.out.println(b);
        System.out.println(c);

        System.out.println(Long.toBinaryString(Double.doubleToLongBits(a)));
        System.out.println(Long.toBinaryString(Double.doubleToLongBits(b)));
        System.out.println(Long.toBinaryString(Double.doubleToLongBits(c)));

    }
}
```
Ausgabe:

```
0.4
0.3999999999999999
0.4
11111111011001100110011001100110011001100110011001100110011010
11111111011001100110011001100110011001100110011001100110011000 <- Da ist ein Bit verloren gegangen
11111111011001100110011001100110011001100110011001100110011010
```


EDIT: Damit das nicht falsch rüberkommt: Die Zahl "0.4" ist - wenn ich mich nicht täusche - NICHT genau darstellbar. Dass sie im ersten und dritten Fall "genau" asgegeben wird, ist vielmehr eine "Nettigkeit" der Methode, die eine double-Zahl wie 0.4 in einen String umwandelt, der dann ausgegeben werden kann!


----------



## ajva (8. Apr 2008)

Ok, vielen Dank. Ich war inzwischen auch beim IEEE-754-Wikipediaeintrag gelandet. Ich war nicht (mehr) damit vertraut, wie double im Speicher des Rechners dargestellt werden. Gelernt habe ich das mal, aber das ist ne Weile her. 

Sehr anschaulich: http://www.h-schmidt.net/FloatApplet/IEEE754de.html


Jetzt kann ich allein weitermachen :###


----------

