Warum sagt Ghci, dass 1.1 + 1.1 + 1.1 3.3 wahr ist?

8

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:

%Vor%

Weiß jemand, warum das so ist?

    
Frerich Raabe 10.01.2010, 21:14
quelle

7 Antworten

36

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.

    
Brian Campbell 10.01.2010, 21:22
quelle
13

Weil Fließkommazahlen nicht genau sind (wikipedia)

    
YuppieNetworking 10.01.2010 21:17
quelle
13

Sie können Fließkommafehler in Haskell mit rationalen Typen vermeiden:

%Vor%

Natürlich zahlen Sie eine Leistung für die erhöhte Genauigkeit.

    
daf 10.01.2010 21:34
quelle
6

Sieht wie ein typisches Problem mit Gleitkommafehlern aus.

Siehe Was ist ein einfaches Beispiel für Gleitkommazahlen? / Rundungsfehler?

    
micahtan 10.01.2010 21:16
quelle
6

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%     
Seth 10.01.2010 21:23
quelle
5

Wenige Gleitkommazahlen können exakt mit der IEEE 754-Darstellung ausgedrückt werden, so dass sie immer ein wenig aus sind.

    
Ignacio Vazquez-Abrams 10.01.2010 21:17
quelle
1

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).

    
mgiuca 17.06.2010 00:58
quelle

Tags und Links