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.
Ich möchte ein Programm schreiben (Konsole), welches eine Wertetabelle für eine Funktion ausgibt (hier x²). Startwert, Endwert und Schrittweite sollen eingegeben werden. Alle Variablen wurden als double gekennzeichnet - als Ergebnis bekomme ich dies (siehe Bild).
Java:
public class wertetabelle {
public static void main(String[] args) {
double startwert;
double endwert;
double schrittweite;
double funktionswert;
System.out.print("Gib den Startwert ein: ");
startwert = Input.readDouble();
System.out.print("Gib den Endwert ein: ");
endwert = Input.readDouble();
System.out.print("Gib die Schrittweite ein: ");
schrittweite = Input.readDouble();
for (double i = startwert; i <= endwert; i += schrittweite) {
funktionswert = i*i;
System.out.println("\t " + i + "\t | " + funktionswert);
}
}
}
Weshalb gibt es diese Ungenauigkeiten? Wie kann ich das abstellen?
In diesem Fall geht es vermutlich nicht um die Genauigkeit. Es gibt nur SEHR wenige Fälle, wo double nicht genau genug ist. Vermutlich geht es nur um die "häßliche" Ausgabe. Siehe String#format bzw. Formatter (Java 2 Platform SE 5.0)
Gleichzeitig.
Das Problem ist, dass bestimte Zahlen mit double einfach nicht genau dargestellt werden können, so wie z.B. 1/3 im dezimalsystem nicht genau dargestellt werden kann, sondern nur als 0.3333333333333333333333333333333333333333.... Siehe auch Gleitkommazahl ? Wikipedia und hunderte(!) Forenbeiträge hier.
Gleitkommazahlen sind prinzipiell ungenau, und eine der Ungenauigkeiten im Umgang mit Dezimalzahlen ist mit ihrer Basis begründet: Dezimalzahlen (das sagt schon das Wort) haben die Basis 10, Binärzahlen haben die Basis 2. Da double und float zu Letzterem gehören, können sie nur Zahlen exakt aufnehmen, deren Binärdarstellung endlich und auf eine bestimmte Anzahl von Binärziffern (bei double höchstens 53, bei float höchstens 24) begrenzt ist.
Die Zahl 0.2 zur Basis 10 hat aber zur Basis 2 eine unendliche periodische Ziffernfolge, deswegen können weder float noch double diese Zahl verlustfrei aufnehmen.
"Abstellen" in dem Sinne kann man das nicht. Man kann nur anders rechnen (z.B. mit anderer Skalierung, gemeinen Brüchen oder Implementierungen wie BigDecimal) oder, wenn das erlaubt und möglich ist, intern mit diesen Fehlern weiterrechnen und lediglich zur Anzeige auf passende Genauigkeiten runden.
10.0 "beliebig" genau
0.2 ist auch "beliebig" genau
und doch zeigt sich schon nach der zweiten Substraktion eine Abweichung die viel grösser als zu erwarten ist obwohl auch der Wert 9.6 "beliebig" genau dargestellt werden kann, wie unten gezeigt wird.
PS: bitte nicht über "beliebig" diskutieren damit möchte ich nur sagen, dass es viel genauer als die Abweichung ist.
Im Binärsystem ist 0.2 ein periodischer Dezimalbruch, und damit (intern) nicht beliebig genau. (Wenn ich mich nicht verrechnet habe ist 0,2=0,00101001010010100101...).
Den Fehler sieht man erst, wenn er durch Berechnungen angehäuft hat. Du kannst in deinem Test d2 ja mal den Wert 0,03125 geben. Diese Zahl kann man im Binärsystem exakt darstellen.
Der Ausgabe-Algorithmus rundet ja auch bzw. benutzt eine gerundete Darstellung. Und am Anfang ist der Unterschied zum exakten Wert eben zu gering, um aufzufallen.