Ich habe kürzlich ein Haskell-Tutorial durchlaufen und dieses Verhalten bemerkt, als ich einige einfache Haskell-Ausdrücke in der interaktiven ghci
-Shell ausprobierte:
Weiß jemand, warum das so ist?
Weil 1.1
und 3.3
Fließkommazahlen sind. Dezimalbrüche wie .1 oder .3 sind in einer binären Gleitkommazahl nicht exakt darstellbar. .1 bedeutet 1/10. Um das im Binärformat zu repräsentieren, wo jede Bruchzahl 1/2 n (1/2, 1/4, 1/8, usw.) darstellt, würden Sie eine unendliche Anzahl von Ziffern, 0.000110011, benötigen. unendlich oft wiederholen.
Das ist genau das gleiche Problem wie etwa 1/3 in Basis 10. In Basis 10 benötigen Sie unendlich viele Ziffern, .33333 ... für immer, um genau 1/3 darzustellen. In der Basis 10 arbeitest du normalerweise rund um etwas wie .33. Aber wenn Sie drei Kopien davon addieren, erhalten Sie .99, nicht 1.
Weitere Informationen zu diesem Thema finden Sie unter Was jeder Informatiker über Fließkomma-Arithmetik wissen sollte .
Um rationale Zahlen in Haskell genauer darzustellen, können Sie immer den rationalen Datentyp Ratio
verwenden ; gekoppelt mit bignums (beliebig große ganze Zahlen, Integer
in Haskell, im Gegensatz zu Int
, die eine feste Größe haben) als Typ für Zähler und Nenner können Sie beliebig genaue rationale Zahlen darstellen, jedoch mit einer deutlich geringeren Geschwindigkeit als Gleitkommazahl Nummern, die hardwaremäßig implementiert und auf Geschwindigkeit optimiert sind.
Fließkommazahlen sind eine Optimierung für wissenschaftliche und numerische Berechnungen, bei denen die Genauigkeit für hohe Geschwindigkeit abgewogen wird. Dadurch können Sie in kurzer Zeit eine große Anzahl von Berechnungen durchführen, solange Sie wissen, wie gerundet wird und wie es funktioniert beeinflusst Ihre Berechnungen.
Sieht wie ein typisches Problem mit Gleitkommafehlern aus.
Siehe Was ist ein einfaches Beispiel für Gleitkommazahlen? / Rundungsfehler?
Es hat damit zu tun, wie IEEE Fließkommazahlen funktionieren.
1.1 wird als 1.1000000000000001 in Gleitkommazahl dargestellt, 3.3 wird als 3.2999999999999998 dargestellt.
Also 1.1 + 1.1 + 1.1 ist eigentlich
1.1000000000000001 + 1.1000000000000001 + 1.1000000000000001 = 3.3000000000000003
Welche, wie Sie sehen können, ist tatsächlich größer als 3,2999999999999998.
Die übliche Problemumgehung besteht darin, entweder die Gleichheit nicht auszuwerten oder zu prüfen, ob eine Zahl innerhalb des Ziels liegt +/- ein kleines Epsilon (was die Genauigkeit definiert, die Sie benötigen).
Beispiel: Wenn beide wahr sind, dann ist die Summe gleich "3,3" (innerhalb des zulässigen Fehlers).
%Vor%Wenige Gleitkommazahlen können exakt mit der IEEE 754-Darstellung ausgedrückt werden, so dass sie immer ein wenig aus sind.
Im Allgemeinen sollten Sie Floats nicht auf Gleichheit (aus den oben genannten Gründen) vergleichen. Der einzige Grund, an den ich denken kann, ist, wenn Sie sagen wollen: "Hat sich dieser Wert verändert?" Zum Beispiel "if (newskore / = oldscore)" dann etwas unternehmen. Das ist in Ordnung, solange Sie nicht das Ergebnis zweier separater Berechnungen vergleichen, um zu überprüfen, ob sie gleich sind (denn dann könnten sie sogar mathematisch zusammenfallen).
Tags und Links haskell floating-accuracy ghci