Du verwendest einen veralteten Browser. Es ist möglich, dass diese oder andere Websites nicht korrekt angezeigt werden. Du solltest ein Upgrade durchführen oder ein alternativer Browser verwenden.
Problem beim Subtrahieren eines Double von einem Double
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).
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.
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
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:
@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:
Code:
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:
Code:
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!
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.