Warum wird meine Nummer falsch gerundet?

7

Das fühlt sich an wie die Art von Code, der nur in situ versagt, aber ich werde versuchen, ihn in ein Code-Snippet zu verwandeln, das darstellt, was ich sehe.

%Vor%

Nach dem Durchlaufen des Codes, i == 269 und i2 == 268. Was passiert hier, um den Unterschied zu erklären?

    
izb 24.03.2010, 16:43
quelle

5 Antworten

15

Float Mathe kann mit höherer Genauigkeit als angekündigt durchgeführt werden. Aber sobald Sie es in float f speichern, geht diese zusätzliche Präzision verloren. Du verlierst diese Genauigkeit nicht in der zweiten Methode, bis du das Ergebnis natürlich auf int skalierst.

Bearbeiten: Siehe diese Frage Warum unterscheidet sich die Fließkomma-Genauigkeit in C #, wenn sie durch Klammern getrennt und durch Anweisungen getrennt ist? für eine bessere Erklärung, als ich wahrscheinlich angegeben habe.

    
Anthony Pegram 24.03.2010, 16:45
quelle
4

Weil Fließkommavariablen nicht unendlich genau sind. Verwenden Sie eine Dezimalzahl, wenn Sie diese Genauigkeit benötigen.

Andere Rundungsmodi können ebenfalls auf dieses Problem einwirken, aber das Genauigkeitsproblem ist das, das Sie gerade ausführen hier hinein, AFAIK.

    
technophile 24.03.2010 16:45
quelle
2

Fließkommazahl hat eine begrenzte Genauigkeit und basiert auf binär statt dezimal. Die Dezimalzahl 13.45 kann im binären Fließkomma nicht genau dargestellt werden, also wird abgerundet. Die Multiplikation mit 20 übertreibt den Genauigkeitsverlust noch weiter. An diesem Punkt haben Sie 268.999 ... - nicht 269 - daher wird die Umwandlung in Integer auf 268 gekürzt.

Um auf die nächste Ganzzahl zu runden, können Sie versuchen, 0.5 hinzuzufügen, bevor Sie zurück in Ganzzahl konvertieren.

Für "perfekte" Arithmetik könnten Sie versuchen, einen Dezimal- oder Rational-numerischen Typ zu verwenden - ich glaube, C # hat Bibliotheken für beide, aber ich bin mir nicht sicher. Diese werden jedoch langsamer sein.

BEARBEITEN - Ich habe bisher einen "Dezimal" -Typ gefunden, aber keinen rationalen - ich könnte mich irren, dass es verfügbar ist. Der Dezimal-Fließkommawert ist ungenau, genau wie binär, aber es ist die Art von Ungenauigkeit, an die wir gewöhnt sind, so dass es weniger überraschende Ergebnisse gibt.

    
Steve314 24.03.2010 16:53
quelle
1

Ersetzen durch

%Vor%

und sehen Sie, ob Sie die gleiche Antwort bekommen.

    
Martin 24.03.2010 16:48
quelle
1

Ich möchte eine andere Erklärung anbieten.

Hier ist der Code, den ich kommentiert habe (ich habe in die Erinnerung geschaut, um die Floats zu analysieren):

%Vor%

Sehen wir uns die Berechnungen genauer an:

  • f = 1101.01110011001100110011 * 10100 = 100001100.111111111111111 111

    Der Teil nach dem Leerzeichen ist die Bits 25-27, die bewirken, dass das Bit 24 aufgerundet wird und somit der ganze Wert auf 269

    aufgerundet wird
  • int i2 = (int) (myFloat * myConstInt)

    myfloat wird auf doppelte Genauigkeit für die Berechnung erweitert (0s werden angehängt): 1101.011100110011001100110000000000000000000000000000000

    myfloat * 20 = 100001100.11111111111111111100000000000000000000000000

    Bits 54 und darüber hinaus sind 0, also wird keine Rundung gemacht: Die Umwandlung ergibt die Ganzzahl 268.

    (Eine ähnliche Erklärung würde funktionieren, wenn die erweiterte Genauigkeit verwendet wird.)

UPDATE: Ich habe meine Antwort verfeinert und einen ausführlichen Artikel mit dem Titel When Floats Don 'geschrieben. t benehmen sich wie schwimmt

    
Rick Regan 25.03.2010 19:33
quelle