Ich stelle mir vor, dass dies eine klassische Gleitkomma-Präzisionsfrage ist, aber ich versuche, mich mit diesem Ergebnis zu beschäftigen, das 1//0.01
in Python 3.7.5 ausgeführt wird 99
.
Ich stelle mir vor, es ist ein erwartetes Ergebnis, aber gibt es eine Möglichkeit zu entscheiden, wann die Verwendung sicherer ist int(1/f)
als 1//f
?
round()
und nie//
oder verwendet wirdint()
. Die verknüpfte Frage zum Float-Vergleich hat nichts mit Abschneiden und keiner so einfachen Lösung zu tun.Antworten:
Wenn dies eine Division mit reellen Zahlen
1//0.01
wäre , wäre dies genau 100. Da es sich jedoch um Gleitkomma-Näherungen handelt,0.01
ist sie etwas größer als 1/100, was bedeutet, dass der Quotient etwas kleiner als 100 ist. Es ist dieser Wert, der dann auf dem Boden liegt bis 99.quelle
Die Gründe für dieses Ergebnis sind wie von Ihnen angegeben und werden in Ist Gleitkomma-Mathematik gebrochen? und viele andere ähnliche Fragen und Antworten.
Wenn Sie die Anzahl der Dezimalstellen von Zähler und Nenner kennen, ist es zuverlässiger, diese Zahlen zuerst zu multiplizieren, damit sie als Ganzzahlen behandelt werden können, und dann eine Ganzzahldivision für sie durchzuführen:
In Ihrem Fall
1//0.01
sollte also zuerst auf1*100//(0.01*100)
100 umgerechnet werden .In extremeren Fällen können immer noch "unerwartete" Ergebnisse erzielt werden. Möglicherweise müssen Sie
round
Zähler und Nenner aufrufen, bevor Sie die Ganzzahldivision ausführen:Wenn es jedoch darum geht, mit festen Dezimalstellen (Geld, Cent) zu arbeiten, sollten Sie in Betracht ziehen, mit Cent als Einheit zu arbeiten , damit alle Arithmetik als Ganzzahlarithmetik ausgeführt werden kann, und dabei nur in / von der Hauptwährungseinheit (Dollar) konvertieren I / O.
Oder verwenden Sie alternativ eine Bibliothek für Dezimalstellen wie Dezimalstellen , die:
quelle
Was Sie berücksichtigen müssen, ist, dass
//
es sich um denfloor
Operator handelt, und als solcher sollten Sie zunächst denken, dass Sie die gleiche Wahrscheinlichkeit haben, in 100 zu fallen wie in 99 (*) (da die Operation100 ± epsilon
mitepsilon>0
vorausgesetzt wird, dass die Chancen genau 100,00 betragen ..0 sind extrem niedrig.)Sie können das gleiche tatsächlich mit einem Minuszeichen sehen,
und Sie sollten als (un) überrascht sein.
Auf der anderen Seite
int(-1/.01)
führt zuerst die Division durch und wendet dann dieint()
in der Zahl an, die kein Boden ist, sondern eine Kürzung in Richtung 0 ! was bedeutet, dass in diesem Falldaher,
Eine Rundung würde jedoch das IHR erwartete Ergebnis für diesen Operator ergeben, da der Fehler für diese Zahlen wiederum gering ist.
(*) Ich sage nicht, dass die Wahrscheinlichkeit gleich ist, ich sage nur, dass a priori, wenn Sie eine solche Berechnung mit schwebender Arithmetik durchführen, eine Schätzung dessen ist, was Sie erhalten.
quelle
Gleitkommazahlen können die meisten Dezimalzahlen nicht genau darstellen. Wenn Sie also ein Gleitkomma-Literal eingeben, erhalten Sie tatsächlich eine Annäherung an dieses Literal. Die Annäherung kann größer oder kleiner als die von Ihnen eingegebene Zahl sein.
Sie können den genauen Wert einer Gleitkommazahl anzeigen, indem Sie sie in Dezimal oder Bruch umwandeln.
Wir können den Bruch-Typ verwenden, um den Fehler zu finden, der durch unser ungenaues Literal verursacht wird.
Wir können auch herausfinden, wie detailliert Gleitkommazahlen mit doppelter Genauigkeit um 100 sind, indem wir nextafter von numpy verwenden.
Daraus können wir schließen, dass die nächste Gleitkommazahl
1/0.01000000000000000020816681711721685132943093776702880859375
tatsächlich genau 100 ist.Der Unterschied zwischen
1//0.01
undint(1/0.01)
ist die Rundung. 1 // 0,01 rundet das genaue Ergebnis in einem einzigen Schritt auf die nächste ganze Zahl ab. Wir erhalten also ein Ergebnis von 99.int (1 / 0.01) hingegen rundet in zwei Schritten, zuerst rundet es das Ergebnis auf die nächste Gleitkommazahl mit doppelter Genauigkeit (genau 100), dann rundet es diese Gleitkommazahl auf die nächste Ganzzahl (dh) wieder genau 100).
quelle
int(0.9) == 0
undint(-0.9) == 0
Wenn Sie Folgendes ausführen
Die Ausgabe wird sein:
Auf diese Weise wird es intern dargestellt, sodass eine Abrundung
//
ergibt99
quelle
Decimal(0.01)
Sie zu spät sind, hat sich der Fehler bereits eingeschlichen, bevor Sie anrufenDecimal
. Ich bin mir nicht sicher, wie dies eine Antwort auf die Frage ist ... Sie müssen zuerst eine genaue 0,01 mit berechnenDecimal(1) / Decimal(100)
, wie ich in meiner Antwort gezeigt habe.