Ich möchte a
auf 13,95 gerundet werden .
>>> a
13.949999999999999
>>> round(a, 2)
13.949999999999999
Die round
Funktion funktioniert nicht wie erwartet.
Ich möchte a
auf 13,95 gerundet werden .
>>> a
13.949999999999999
>>> round(a, 2)
13.949999999999999
Die round
Funktion funktioniert nicht wie erwartet.
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,
>>> 125650429603636838/(2**53)
13.949999999999999
>>> 234042163/(2**24)
13.949999988079071
>>> a = 13.946
>>> print(a)
13.946
>>> print("%.2f" % a)
13.95
>>> round(a,2)
13.949999999999999
>>> print("%.2f" % round(a, 2))
13.95
>>> print("{:.2f}".format(a))
13.95
>>> print("{:.2f}".format(round(a, 2)))
13.95
>>> print("{:.15f}".format(round(a, 2)))
13.949999999999999
Wenn Sie nur zwei Dezimalstellen benötigen (um beispielsweise einen Währungswert anzuzeigen), haben Sie einige bessere Möglichkeiten:
"%.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:
"{:.2f}".format(13.949999999999999)
Hinweis 1: Das obige gibt eine Zeichenfolge zurück. Um als Float zu erhalten, wickeln Sie einfach mit float(...)
:
float("{:.2f}".format(13.949999999999999))
Anmerkung 2: Das Umwickeln mit float()
ändert nichts:
>>> x = 13.949999999999999999
>>> x
13.95
>>> g = float("{:.2f}".format(x))
>>> g
13.95
>>> x == g
True
>>> h = round(x, 2)
>>> h
13.95
>>> x == h
True
'{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:
>>> round(14.22222223, 2)
14.22
Lesen Sie die Dokumentation .
round(2.16, 1)
geben , 2.2
warum Python nur bieten truncate
func
>>> round(2.675, 2) 2.67
docs.python.org/2/tutorial/floatingpoint.html
Note 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:
a = 13.949999999999999
format(a, '.2f')
13.95
Dies erzeugt eine Gleitkommazahl als Zeichenfolge, die auf zwei Dezimalstellen gerundet ist.
Verwenden
print"{:.2f}".format(a)
anstatt
print"{0:.2f}".format(a)
Weil letzteres zu Ausgabefehlern führen kann, wenn versucht wird, mehrere Variablen auszugeben (siehe Kommentare).
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.)
>>> "%.2f" % 3.14159
'3.14'
>>> "%.2f" % 13.9499999
'13.95'
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.
Versuchen Sie den folgenden Code:
>>> a = 0.99334
>>> a = int((a * 100) + 0.5) / 100.0 # Adding 0.5 rounds it up
>>> print a
0.99
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.
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() ...
oder Decimal -> 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 :
import random
from decimal import Decimal
for x in iter(random.random, None): # Verify FOREVER that rounding is fixed :-)
assert float(repr(x)) == x # Reversible repr() conversion.
assert float(Decimal(repr(x))) == x
assert len(repr(round(x, 10))) <= 12 # Smart decimal places in repr() after round.
if x >= 0.1: # Implicit rounding to 12 significant digits
assert str(x) == repr(round(x, 12)) # by str() is good enough for small errors.
y = 1000 * x # Decimal type is excessive for shopping
assert str(y) == repr(round(y, 12 - 3)) # in a supermaket with Python 2.7+ :-)
Siehe die Versionshinweise Python 2.7 - Andere Sprachänderungen im vierten Absatz:
Konvertierungen zwischen Gleitkommazahlen und Zeichenfolgen werden jetzt auf den meisten Plattformen korrekt gerundet . Diese Konvertierungen finden an vielen verschiedenen Stellen statt: str () auf Floats und komplexen Zahlen; die Float- und komplexen Konstruktoren; numerische Formatierung; Serialisierung und De-Serialisierung Schwimmer und komplexe Zahlen mit der
marshal
,pickle
undjson
Module; Parsen von Float- und imaginären Literalen in Python-Code; und Umwandlung von Dezimal in Gleitkomma.In diesem Zusammenhang gibt die repr () einer Gleitkommazahl x jetzt ein Ergebnis zurück, das auf der kürzesten Dezimalzeichenfolge basiert, die bei korrekter Rundung (mit Rundungshalb-zu-Gerade-Rundungsmodus) garantiert auf x zurückrundet. Zuvor wurde eine Zeichenfolge basierend auf der Rundung von x auf 17 Dezimalstellen angegeben.
Weitere Informationen: Die Formatierung float
vor Python 2.7 war ähnlich der aktuellen numpy.float64
. Beide Typen verwenden dieselbe 64-Bit- IEEE 754- Doppelgenauigkeit mit 52-Bit-Mantisse. Ein großer Unterschied besteht darin, dass np.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 Konvertierung repr(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.
float
(doppelte Genauigkeit) und normal round
, 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
vs b*a
. Danke für die Links - Nostalgie.
Bei Python <3 (z. B. 2.6 oder 2.7) gibt es zwei Möglichkeiten.
# Option one
older_method_string = "%.9f" % numvar
# Option two (note ':' before the '.9f')
newer_method_string = "{:.9f}".format(numvar)
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 .
numvar=12.456
, dann "{:.2f}".format(numvar)
ergibt sich 12.46
aber "{:2i}".format(numvar)
ein Fehler und ich erwarte 12
.
Sie können das Ausgabeformat ändern:
>>> a = 13.95
>>> a
13.949999999999999
>>> print "%.2f" % a
13.95
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:
>>> f'{a:.2f}'
Es funktioniert auch gut mit längeren Beispielen, mit Operatoren und ohne Parens:
>>> print(f'Completed in {time.time() - start:.2f}s')
Sie können den Formatoperator verwenden , um den Wert in Python auf 2 Dezimalstellen zu runden:
print(format(14.4499923, '.2f')) // output is 14.45
In Python 2.7:
a = 13.949999999999999
output = float("%0.2f"%a)
print output
output
hat genau den gleichen Wert wie a
, so dass Sie genauso gut print a
anstelle print output
der letzten Zeile geschrieben haben könnten .
13.95
. Aber so tut print a
, für diesen bestimmten Wert a
, 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 gibt True
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:
>>> 0.1 0.10000000000000001
Sie könnten versucht sein, die
round()
Funktion zu verwenden, um sie auf die erwartete einzelne Ziffer zurückzuschneiden. Das macht aber keinen Unterschied:>>> round(0.1, 1) 0.10000000000000001
Das Problem ist, dass der für gespeicherte binäre Gleitkommawert
“0.1”
bereits die bestmögliche binäre Annäherung an1/10
war. Ein erneuter Rundungsversuch kann ihn also nicht verbessern: Er war bereits so gut wie es nur geht.Eine andere Konsequenz ist, dass, da dies
0.1
nicht genau ist1/10
, die Summierung von zehn Werten von0.1
möglicherweise auch nicht genau ergibt1.0
:>>> sum = 0.0 >>> for i in range(10): ... sum += 0.1 ... >>> sum 0.99999999999999989
Eine Alternative und Lösung für Ihre Probleme wäre die Verwendung des decimal
Moduls.
Wie @Matt hervorhob, bietet Python 3.6 F-Strings und sie können auch verschachtelte Parameter verwenden :
value = 2.34558
precision = 2
width = 4
print(f'result: {value:{width}.{precision}f}')
welches angezeigt wird result: 2.35
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 .
Verwenden Sie eine Kombination aus Dezimalobjekt und round () -Methode.
Python 3.7.3
>>> from decimal import Decimal
>>> d1 = Decimal (13.949999999999999) # define a Decimal
>>> d1
Decimal('13.949999999999999289457264239899814128875732421875')
>>> d2 = round(d1, 2) # round to 2 decimals
>>> d2
Decimal('13.95')
Zum Fixieren des Gleitkommas in typdynamischen Sprachen wie Python und JavaScript verwende ich diese Technik
# For example:
a = 70000
b = 0.14
c = a * b
print c # Prints 980.0000000002
# Try to fix
c = int(c * 10000)/100000
print c # Prints 980
Sie können Decimal auch wie folgt verwenden:
from decimal import *
getcontext().prec = 6
Decimal(1) / Decimal(7)
# Results in 6 precision -> Decimal('0.142857')
getcontext().prec = 28
Decimal(1) / Decimal(7)
# Results in 28 precision -> Decimal('0.1428571428571428571428571429')
getcontext().prec = 6
funktioniert nur für den Funktionsumfang oder für alle Orte?
from decimal import Decimal
def round_float(v, ndigits=2, rt_str=False):
d = Decimal(v)
v_str = ("{0:.%sf}" % ndigits).format(round(d, ndigits))
if rt_str:
return v_str
return Decimal(v_str)
Ergebnisse:
Python 3.6.1 (default, Dec 11 2018, 17:41:10)
>>> round_float(3.1415926)
Decimal('3.14')
>>> round_float(3.1445926)
Decimal('3.14')
>>> round_float(3.1455926)
Decimal('3.15')
>>> round_float(3.1455926, rt_str=True)
'3.15'
>>> str(round_float(3.1455926))
'3.15'
Was ist mit einer Lambda-Funktion wie dieser:
arred = lambda x,n : x*(10**n)//1/(10**n)
Auf diese Weise können Sie einfach Folgendes tun:
arred(3.141591657,2)
und bekomme
3.14
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:
d.quantize(Decimal('0.01'))
wird Ergebnisse mit Decimal('10000000.00')
def round_decimal(number, exponent='0.01'):
decimal_value = Decimal(number)
return decimal_value.quantize(Decimal(exponent))
ODER
def round_decimal(number, decimal_places=2):
decimal_value = Decimal(number)
return decimal_value.quantize(Decimal(10) ** -decimal_places)
PS: Kritik an anderen: Formatierung ist keine Rundung.
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):
>>> import numpy as np
>>> value = 13.949999999999999
>>> resolution = 0.01
>>> newValue = int(np.round(value/resolution))*resolution
>>> print newValue
13.95
>>> resolution = 0.5
>>> newValue = int(np.round(value/resolution))*resolution
>>> print newValue
14.0
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 konvertieren float
oder einfach zu verwenden round(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 auch float
für @szeitlin Beispiel verwendet werden kann. Vielen Dank für Ihren zusätzlichen Kommentar. (Sorry, aber ich habe dich nicht abgelehnt)
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.
float = str(float)[:5]
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!