Ich möchte a
auf 13,95 gerundet werden .
>>> a
13.949999999999999
>>> round(a, 2)
13.949999999999999
Die round
Funktion funktioniert nicht wie erwartet.
python
floating-point
rounding
precision
ShadowRanger
quelle
quelle
Antworten:
Sie stoßen auf das alte Problem mit Gleitkommazahlen, bei denen nicht alle Zahlen exakt dargestellt werden können. Die Befehlszeile zeigt Ihnen nur die vollständige Gleitkommaform aus dem Speicher.
Bei der Gleitkommadarstellung ist Ihre gerundete Version dieselbe Zahl. Da Computer binär sind, speichern sie Gleitkommazahlen als Ganzzahl und teilen sie dann durch eine Zweierpotenz, sodass 13,95 auf ähnliche Weise wie 125650429603636838 / (2 ** 53) dargestellt werden.
Zahlen mit doppelter Genauigkeit haben eine Genauigkeit von 53 Bit (16 Stellen) und reguläre Gleitkommazahlen eine Genauigkeit von 24 Bit (8 Stellen). Der Gleitkommatyp in Python verwendet die doppelte Genauigkeit , um die Werte zu speichern.
Zum Beispiel,
Wenn Sie nur zwei Dezimalstellen benötigen (um beispielsweise einen Währungswert anzuzeigen), haben Sie einige bessere Möglichkeiten:
quelle
"%.2f" % round(a,2)
Sie nicht nur in printf, sondern auch in solchen Dingen wiestr()
float
) nur die nächste verfügbare Annäherung an die Dezimalzahl ist (die Sie als Mensch kennen). Es gibt keinen solchen (endlich darstellbaren) Binärwert wie 0,245. Es existiert einfach nicht und kann mathematisch nicht existieren. Der Binärwert, der 0,245 am nächsten kommt, ist etwas kleiner als 0,245, daher rundet er natürlich ab. Ebenso gibt es keine 0,225 in Binärform, aber der Binärwert, der 0,225 am nächsten kommt, ist etwas größer als 0,225, also rundet er natürlich auf.Decimal
, und dies war eine der in dieser Antwort vorgestellten Lösungen. Die andere bestand darin, Ihre Mengen in Ganzzahlen umzuwandeln und Ganzzahlarithmetik zu verwenden. Beide Ansätze tauchten auch in anderen Antworten und Kommentaren auf.Es gibt neue Formatspezifikationen, String-Formatspezifikation Mini-Sprache :
Sie können das Gleiche tun wie:
Hinweis 1: Das obige gibt eine Zeichenfolge zurück. Um als Float zu erhalten, wickeln Sie einfach mit
float(...)
:Anmerkung 2: Das Umwickeln mit
float()
ändert nichts:quelle
'{0:,.2f}'.format(1333.949999999)
welche drucken'1,333.95'
.float()
;float("{0:.2f}".format(13.9499999))
f"Result is {result:.2f}"
Die integrierte Funktion
round()
funktioniert in Python 2.7 oder höher einwandfrei.Beispiel:
Lesen Sie die Dokumentation .
quelle
round(2.16, 1)
geben ,2.2
warum Python nur bietentruncate
func>>> round(2.675, 2) 2.67
docs.python.org/2/tutorial/floatingpoint.htmlNote The behavior of round() for floats can be surprising: for example, round(2.675, 2) gives 2.67 instead of the expected 2.68. This is not a bug: it’s a result of the fact that most decimal fractions can’t be represented exactly as a float.
Ich bin der Meinung, dass der einfachste Ansatz darin besteht, die
format()
Funktion zu verwenden.Zum Beispiel:
Dies erzeugt eine Gleitkommazahl als Zeichenfolge, die auf zwei Dezimalstellen gerundet ist.
quelle
Verwenden
anstatt
Weil letzteres zu Ausgabefehlern führen kann, wenn versucht wird, mehrere Variablen auszugeben (siehe Kommentare).
quelle
Die meisten Zahlen können in Floats nicht genau dargestellt werden. Wenn Sie die Zahl runden möchten, weil dies für Ihre mathematische Formel oder Ihren Algorithmus erforderlich ist, möchten Sie runden verwenden. Wenn Sie die Anzeige nur auf eine bestimmte Genauigkeit beschränken möchten, verwenden Sie nicht einmal rund und formatieren Sie sie einfach als diese Zeichenfolge. (Wenn Sie es mit einer alternativen Rundungsmethode anzeigen möchten und es Tonnen gibt, müssen Sie die beiden Ansätze mischen.)
Und schließlich, wenn auch am wichtigsten, wenn Sie genaue Mathematik wollen, dann wollen Sie überhaupt keine Floats. Das übliche Beispiel ist der Umgang mit Geld und das Speichern von 'Cent' als Ganzzahl.
quelle
Versuchen Sie den folgenden Code:
quelle
round
Funktion zu verwenden. Zum anderen bleibt das ursprüngliche Problem des OP bestehen, da diese Lösung immer noch Gleitkomma verwendet, selbst für die "korrigierte" Version dieser "Lösung".round
Funktion (die in der Frage verwendet wurde).round()
nicht wie das erwähnte OP funktioniert.TLDR;)
Das Rundungsproblem der Eingabe / Ausgabe wurde durch Python 2.7.0 und 3.1 endgültig gelöst .
Eine korrekt gerundete Zahl kann reversibel hin und her konvertiert werden:
str -> float() -> repr() -> float() ...
oderDecimal -> float -> str -> Decimal
Ein Dezimaltyp ist für die Speicherung nicht mehr erforderlich.
(Natürlich kann es erforderlich sein, ein Ergebnis der Addition oder Subtraktion gerundeter Zahlen zu runden, um die akkumulierten Fehler des letzten Bits zu beseitigen. Eine explizite Dezimalarithmetik kann immer noch praktisch sein, aber eine Konvertierung in eine Zeichenfolge durch
str()
(dh mit Rundung auf 12 gültige Ziffern) ) ist normalerweise gut genug, wenn keine extreme Genauigkeit oder keine extreme Anzahl aufeinanderfolgender arithmetischer Operationen erforderlich ist.)Unendlicher Test :
Dokumentation
Siehe die Versionshinweise Python 2.7 - Andere Sprachänderungen im vierten Absatz:
Das damit verbundene Problem
Weitere Informationen: Die Formatierung
float
vor Python 2.7 war ähnlich der aktuellennumpy.float64
. Beide Typen verwenden dieselbe 64-Bit- IEEE 754- Doppelgenauigkeit mit 52-Bit-Mantisse. Ein großer Unterschied besteht darin, dassnp.float64.__repr__
häufig mit einer übermäßigen Dezimalzahl formatiert wird, sodass kein Bit verloren gehen kann, aber zwischen 13.949999999999999 und 13.950000000000001 keine gültige IEEE 754-Nummer vorhanden ist. Das Ergebnis ist nicht schön und die Konvertierungrepr(float(number_as_string))
ist mit numpy nicht umkehrbar. Auf der anderen Seite:float.__repr__
ist so formatiert, dass jede Ziffer wichtig ist; Die Reihenfolge ist lückenlos und die Konvertierung ist reversibel. Einfach: Wenn Sie möglicherweise eine numpy.float64-Nummer haben, konvertieren Sie diese in normales float, um sie für Menschen und nicht für numerische Prozessoren zu formatieren. Andernfalls ist mit Python 2.7+ nichts mehr erforderlich.quelle
float
(doppelte Genauigkeit) und normalround
, nicht numpy.double und seine Konvertierung in einen String. Eine einfache Python-Rundung kann wirklich nicht besser durchgeführt werden als in Python 2.7. Die meisten Antworten wurden vor 2.7 geschrieben, sind jedoch veraltet, obwohl sie ursprünglich sehr gut waren. Dies ist der Grund meiner Antwort.1
, außer während des "allmählichen Unterlaufs".a*b
vsb*a
. Danke für die Links - Nostalgie.Bei Python <3 (z. B. 2.6 oder 2.7) gibt es zwei Möglichkeiten.
Beachten Sie jedoch, dass für Python-Versionen über 3 (z. B. 3.2 oder 3.3) Option zwei bevorzugt wird .
Für weitere Informationen zu Option 2 empfehle ich diesen Link zur Formatierung von Zeichenfolgen aus der Python-Dokumentation .
Für weitere Informationen zu Option 1 reicht dieser Link aus und enthält Informationen zu den verschiedenen Flags .
Referenz: Konvertieren Sie die Gleitkommazahl in eine bestimmte Genauigkeit und kopieren Sie sie in eine Zeichenfolge
quelle
numvar=12.456
, dann"{:.2f}".format(numvar)
ergibt sich12.46
aber"{:2i}".format(numvar)
ein Fehler und ich erwarte12
.Sie können das Ausgabeformat ändern:
quelle
Niemand hier scheint es bisher erwähnt zu haben, also lassen Sie mich ein Beispiel im F-String / Template-String-Format von Python 3.6 geben, das ich für sehr ordentlich halte:
Es funktioniert auch gut mit längeren Beispielen, mit Operatoren und ohne Parens:
quelle
Sie können den Formatoperator verwenden , um den Wert in Python auf 2 Dezimalstellen zu runden:
quelle
In Python 2.7:
quelle
output
hat genau den gleichen Wert wiea
, so dass Sie genauso gutprint a
anstelleprint output
der letzten Zeile geschrieben haben könnten .13.95
. Aber so tutprint a
, für diesen bestimmten Werta
, in Python 2.7, so ist es nicht wirklich klar , was der Punkt des Formatierungsschrittes war.a == output
den Code anzuzeigen, den Sie anzeigen? Es gibtTrue
für mich und ich vermute, dass es auch für Sie tut.Das Python-Tutorial enthält einen Anhang mit dem Namen Gleitkomma-Arithmetik: Probleme und Einschränkungen . Lies es. Es erklärt, was passiert und warum Python sein Bestes gibt. Es gibt sogar ein Beispiel, das zu Ihrem passt. Lassen Sie mich ein bisschen zitieren:
Eine Alternative und Lösung für Ihre Probleme wäre die Verwendung des
decimal
Moduls.quelle
Wie @Matt hervorhob, bietet Python 3.6 F-Strings und sie können auch verschachtelte Parameter verwenden :
welches angezeigt wird
result: 2.35
quelle
Es macht genau das, was Sie ihm gesagt haben und funktioniert richtig. Lesen Sie mehr über Gleitkomma-Verwirrung und versuchen Sie stattdessen möglicherweise Dezimalobjekte .
quelle
Verwenden Sie eine Kombination aus Dezimalobjekt und round () -Methode.
quelle
Zum Fixieren des Gleitkommas in typdynamischen Sprachen wie Python und JavaScript verwende ich diese Technik
Sie können Decimal auch wie folgt verwenden:
quelle
getcontext().prec = 6
funktioniert nur für den Funktionsumfang oder für alle Orte?Ergebnisse:
quelle
quelle
Was ist mit einer Lambda-Funktion wie dieser:
Auf diese Weise können Sie einfach Folgendes tun:
und bekomme
quelle
Es ist einfach wie 1,2,3:
Verwenden Sie das Dezimalmodul für eine schnelle, korrekt gerundete Dezimal-Gleitkomma-Arithmetik:
d = Dezimal (10000000.0000009)
Rundung erreichen:
wird Ergebnisse mit
Decimal('10000000.00')
ODER
PS: Kritik an anderen: Formatierung ist keine Rundung.
quelle
Um eine Zahl auf eine Auflösung zu runden, ist der folgende Weg der beste, der mit jeder Auflösung funktionieren kann (0,01 für zwei Dezimalstellen oder sogar andere Schritte):
quelle
numpy.round
Genauigkeit / Präzision herrührt. Daher muss es vor der Multiplikation mit der Auflösung als int definiert werden. Ich habe den Code aktualisiert. Danke für das!numpy.float64
Ergebnis von np.round in zu konvertierenfloat
oder einfach zu verwendenround(value, 2)
. Zwischen 13.949999999999999 (= 1395/100) und 3.950000000000001 (= 1395 * .01) existiert keine gültige IEEE 754-Nummer. Warum denkst du, dass deine Methode die beste ist? Der ursprüngliche Wert 13.949999999999999289 (= Wert = rund (Wert, 2)) ist noch genauer als Ihr 13.95000000000000178 (gedruckt von np.float96). Weitere Informationen auch für numpy wurden jetzt zu meiner Antwort hinzugefügt, die Sie wahrscheinlich versehentlich abgelehnt haben. Es ging ursprünglich nicht um Numpy.int
Ihnen auchfloat
für @szeitlin Beispiel verwendet werden kann. Vielen Dank für Ihren zusätzlichen Kommentar. (Sorry, aber ich habe dich nicht abgelehnt)lambda x, n: int (x * 10 n + .5) / 10 n arbeitet seit vielen Jahren in vielen Sprachen für mich .
quelle
Die Methode, die ich benutze, ist das Schneiden von Strings. Es ist relativ schnell und einfach.
Konvertieren Sie zuerst den Float in eine Zeichenfolge und wählen Sie die gewünschte Länge aus.
In der obigen einzelnen Zeile haben wir den Wert in eine Zeichenfolge konvertiert und die Zeichenfolge dann nur auf die ersten vier Ziffern oder Zeichen (einschließlich) beschränkt.
Ich hoffe, das hilft!
quelle