32 Stimmen

Rundungsfehler?

In meinem Kurs wird mir das gesagt:

Kontinuierliche Werte werden im Speicher nur annähernd dargestellt, weshalb bei Berechnungen mit Fließkommazahlen Rundungsfehler auftreten. Dabei handelt es sich um winzige Abweichungen in den Bitmustern; daher ist der Test e==f unsicher ist, wenn e y f sind Schwimmer.

Bezogen auf Java.

Ist das wahr? Ich habe Vergleichsanweisungen verwendet mit double s und float s und hatten noch nie Rundungsprobleme. In einem Lehrbuch habe ich noch nie etwas Ähnliches gelesen. Die virtuelle Maschine trägt dem doch sicher Rechnung?

65voto

Chris Vest Punkte 8512

Das ist wahr.

Dies ist eine inhärente Beschränkung der Darstellung von Fließkommawerten im Speicher in einer endlichen Anzahl von Bits.

Dieses Programm gibt zum Beispiel "false" aus:

public class Main {
  public static void main(String[] args) {
    double a = 0.7;
    double b = 0.9;
    double x = a + 0.1;
    double y = b - 0.1;
    System.out.println(x == y);
  }
}

Anstelle eines exakten Vergleichs mit "==" entscheidet man sich normalerweise für ein gewisses Maß an Genauigkeit und fragt, ob die Zahlen "nahe genug" sind:

System.out.println(Math.abs(x - y) < 0.0001);

29voto

Ben Schwehn Punkte 4459

Dies gilt für Java genauso wie für jede andere Sprache, die Fließkomma verwendet. Es liegt in der Konzeption der Darstellung von Fließkommawerten in der Hardware begründet.

Weitere Informationen über Fließkommazahlen:

Was jeder Informatiker über Fließkommaarithmetik wissen sollte

11voto

duffymo Punkte 298898

Ja, die exakte Darstellung von 0,1 zur Basis 2 ist dasselbe wie der Versuch, 1/3 exakt zur Basis 10 darzustellen.

4voto

laginimaineb Punkte 8115

Das ist immer so. Es gibt einige Zahlen, die mit der Fließkommadarstellung nicht genau dargestellt werden können. Nehmen wir zum Beispiel Pi. Wie würden Sie eine Zahl mit unendlich vielen Ziffern in einem endlichen Speicher darstellen? Daher sollten Sie beim Vergleich von Zahlen prüfen, ob die Differenz zwischen ihnen kleiner als ein gewisses Epsilon ist. Außerdem gibt es mehrere Klassen, die Ihnen helfen können, eine größere Genauigkeit zu erreichen, wie z. B. BigDecimal und BigInteger.

4voto

Loren Pechtel Punkte 8729

Es ist richtig. Beachten Sie, dass Java nichts damit zu tun hat, das Problem liegt in der Fließkommamathematik in ANY Sprache.

Bei Problemen im Klassenzimmer kommt man oft damit durch, aber in der realen Welt wird das nicht funktionieren. Manchmal funktioniert es auch nicht im Klassenzimmer.

Ein Vorfall aus der Schulzeit, der lange zurückliegt. Der Lehrer eines Einführungskurses wies ein Problem für die Abschlussprüfung zu, das für viele der besseren Schüler ein echtes Problem darstellte - es funktionierte nicht und sie wussten nicht, warum. (Ich habe das als Laborassistent gesehen, ich war nicht in der Klasse.) Schließlich begannen einige, mich um Hilfe zu bitten, und nach einigem Nachforschen kam das Problem ans Licht: Sie waren nie über die inhärente Ungenauigkeit der Fließkommamathematik unterrichtet worden.

Es gab zwei grundsätzliche Herangehensweisen an dieses Problem, eine Brute-Force-Methode (die in diesem Fall zufällig funktionierte, da sie jedes Mal dieselben Fehler verursachte) und eine elegantere Methode (die verschiedene Fehler verursachte und nicht funktionierte.) Jeder, der die elegante Methode ausprobierte, stieß auf eine Mauer, ohne eine Ahnung zu haben, warum. Ich half einigen von ihnen und fügte einen Kommentar ein, in dem ich erklärte, warum das so war, und dass er sich bei Fragen an mich wenden sollte.

Natürlich erfahre ich im nächsten Semester von ihm, dass ich die gesamte Abteilung mit einem einfachen kleinen Programm in den Ruin getrieben habe:

10 X = 3000000
20 X = X + 1
30 If X < X + 1 goto 20
40 Print "X = X + 1"

Entgegen der Meinung aller Lehrer in der Abteilung, ist dies WILL terminieren. Der 3-Millionen-Seed ist einfach dazu da, dass er schneller beendet wird. (Falls Sie die Grundlagen nicht kennen: Es gibt hier keine Spielereien, sondern nur die Ausschöpfung der Genauigkeit von Fließkommazahlen).

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X