Warum ist Fließkomma-Arithmetik in C # ungenau?

10

Warum druckt das folgende Programm, was es druckt?

%Vor%

Ausgabe ist

%Vor%     
Prankster 15.04.2009, 22:12
quelle

3 Antworten

32

Fließkommazahl hat nur so viele Stellen der Genauigkeit. Wenn Sie f1 == f2 sehen, liegt das daran, dass jeder Unterschied mehr Genauigkeit erfordert, als ein 32-Bit-Float darstellen kann.

Ich empfehle das Lesen von Was jeder Informatiker über Floating Point lesen sollte

    
Michael 15.04.2009, 22:15
quelle
5

Die Hauptsache ist, dass dies nicht nur .Net ist: Es ist eine Einschränkung des zugrunde liegenden Systems, das fast jede Sprache zur Darstellung verwendet ein Float im Speicher. Die Präzision geht nur so weit.

Sie können auch Spaß mit relativ einfachen Zahlen haben, wenn Sie berücksichtigen, dass es nicht einmal die Basis zehn ist. 0.1 ist beispielsweise eine sich wiederholende Dezimalzahl, wenn sie in Binärform dargestellt wird.

    
Joel Coehoorn 15.04.2009 23:17
quelle
3

In diesem speziellen Fall liegt das daran, dass .09 und .999999 im Binärformat nicht mit exakter Genauigkeit dargestellt werden können (ähnlich kann 1/3 nicht mit exakter Genauigkeit im Dezimalformat dargestellt werden). Zum Beispiel ist 0.111111111111111111101111 Basis 2 0.999998986721038818359375 Basis 10. Hinzufügen von 1 zum vorherigen Binärwert, 0.11111111111111111111 Basis 2 ist 0.99999904632568359375 Basis 10. Es gibt keinen Binärwert für genau 0.999999. Die Gleitkomma-Genauigkeit ist auch durch den Raum begrenzt, der zum Speichern des Exponenten und des Bruchteils der Mantisse reserviert ist. Wie Integer-Typen kann Gleitkommazahlen ihren Bereich überlaufen lassen, obwohl ihr Bereich größer als ganze Bereiche ist.

Ausführen dieses Bits von C ++ - Code im Xcode-Debugger,

float myFloat = 0.1;

zeigt an, dass myFloat den Wert 0.100000001 erhält. Es ist ausgeschaltet von 0,000000001. Nicht viel, aber wenn die Berechnung mehrere arithmetische Operationen hat, kann die Ungenauigkeit zusammengefügt werden.

Imho eine sehr gute Erklärung von Fließkomma ist in Kapitel 14 von Einführung in Computer-Organisation mit x86-64 Assembly Language & amp; GNU / Linux von Bob Plantz von der California State University in Sonoma (im Ruhestand) Ссылка . Das Folgende basiert auf diesem Kapitel.

Fließkomma ist wie eine wissenschaftliche Notation, bei der ein Wert als eine gemischte Zahl größer oder gleich 1.0 und kleiner als 2.0 (die Mantisse) gespeichert wird, mal eine andere Zahl als eine Potenz (der Exponent). Fließkomma verwendet Basis 2 anstatt Basis 10, aber in dem einfachen Modell, das Plantz gibt, benutzt er Basis 10, um der Übersichtlichkeit willen. Stellen Sie sich ein System vor, in dem zwei Speicherpositionen für die Mantisse verwendet werden, eine Position für das Vorzeichen des Exponenten * (0 für + und 1 für -) und eine Position für den Exponenten. Fügen Sie jetzt 0,93 und 0,91 hinzu. Die Antwort ist 1.8, nicht 1.84.

9311 steht für 0,93 oder 9,3 mal 10 für -1.

9111 entspricht 0,91 oder 9,1 mal 10 dem -1.

Die genaue Antwort ist 1,84 oder 1,84 mal 10 zur 0, was 18400 wäre, wenn wir 5 Positionen hätten, aber mit nur vier Positionen ist die Antwort 1800 oder 1,8 mal 10 zur Null oder 1,8. Natürlich können Fließkomma-Datentypen mehr als vier Speicherpositionen verwenden, aber die Anzahl der Positionen ist immer noch begrenzt.

Nicht nur ist die Genauigkeit durch den Raum begrenzt, sondern "eine exakte Darstellung von Bruchzahlen im Binärsystem ist auf Summen von inversen Zweierpotenzen beschränkt" (Plantz, aaO).

0,1100110 (binär) = 0,89843750 (dezimal)

0,111100111 (binär) = 0,90234375 (dezimal)

Es gibt keine exakte Darstellung von 0.9 Dezimal im Binärformat. Selbst wenn du den Bruchteil mehr Orte wegbringst, funktioniert das nicht, da du 1100 für immer rechts wiederholen musst.

  

Anfänger sehen Fließkommaarithmetik oft mehr   genau als ganze Zahl. Es stimmt, dass sogar zwei sehr große hinzugefügt werden   Integer können einen Überlauf verursachen. Multiplikation macht es noch wahrscheinlicher   Das Ergebnis wird sehr groß sein und somit überlaufen. Und wenn benutzt   Bei zwei Ganzzahlen verursacht der Operator / in C / C ++ den Bruchteil   verloren sein. Allerdings haben ... Gleitkommadarstellungen ihre eigenen   Ungenauigkeiten. (Plantz, op. Cit.)

* Im Fließkomma werden sowohl das Vorzeichen der Zahl als auch das Vorzeichen des Exponenten dargestellt.

    
Jim 04.04.2015 19:48
quelle

Tags und Links