round() in Python scheint nicht zu sein Rundung richtig
-
09-06-2019 - |
Frage
Die Dokumentation für die round() Funktion besagt, dass es eine Zahl ist, und die Positionen der Vergangenheit der Dezimalstelle zu Runden.So ist es sollte tun Sie dies:
n = 5.59
round(n, 1) # 5.6
Aber in Wirklichkeit, die gute alte floating point Seltsamkeit schleicht und Sie erhalten:
5.5999999999999996
Für die Zwecke der UI, I need to display 5.6
.Ich stocherte im Internet und fand einige Dokumentation dass dies abhängig ist meine Implementierung von Python.Leider, dies geschieht sowohl auf meinem Windows-dev-Maschine, und jede Linux-server die ich ausprobiert habe. Siehe auch hier.
Kurz meine eigene Bibliothek Runde, gibt es eine Möglichkeit, um dieses?
Lösung
Ich kann die Art und Weise nicht helfen, es ist gespeichert, aber zumindest die Formatierung korrekt funktioniert:
'%.1f' % round(n, 1) # Gives you '5.6'
Andere Tipps
Die Formatierung korrekt funktioniert auch ohne zu Runde mit:
"%.1f" % n
Wenn Sie das Dezimal-Modul, das Sie ohne die Verwendung der ‚runden‘ Funktion annähern können. Hier ist, was ich für die Rundung insbesondere unter Verwendung von beim Schreiben Geld Anwendungen:
Decimal(str(16.2)).quantize(Decimal('.01'), rounding=ROUND_UP)
Dies wird eine Dezimalzahl zurück, die 16.20 ist.
round(5.59, 1)
funktioniert gut. Das Problem ist, dass 5.6 kann nicht genau in Punkt binärer Fließ dargestellt werden.
>>> 5.6
5.5999999999999996
>>>
Wie Vinko sagt, können Sie String-Formatierung für die Anzeige zu tun Runden.
Python hat einen Modul für Dezimalarithmetik , wenn Sie das brauchen.
Sie erhalten '5.6', wenn Sie statt nur str(round(n, 1))
do round(n, 1)
.
Sie können den Datentyp auf eine ganze Zahl wechseln:
>>> n = 5.59
>>> int(n * 10) / 10.0
5.5
>>> int(n * 10 + 0.5)
56
Und dann die Nummer angezeigt wird durch das Gebietsschema des Dezimaltrennzeichens eingefügt wird.
Allerdings Jimmys Antwort ist besser.
Gleitkomma-Mathematik ist anfällig für leichte, aber ärgerlich, Präzision Ungenauigkeiten. Wenn Sie mit Integer- oder festen Punkt arbeiten können, werden Sie garantiert Präzision werden.
Werfen Sie einen Blick auf die Dezimal-Modul
Dezimal „basiert auf einem Fließkomma Modell, das mit Menschen entworfen wurde, im Auge, und notwendigerweise ein von größter Bedeutung Leitprinzip - Computer müssen eine arithmetische liefern das funktioniert in der gleichen Weise wie die Arithmetik, dass die Menschen lernen, Schule.“- Auszug aus dem Dezimalsystem Arithmetik-Spezifikation.
und
Dezimalzahlen können dargestellt werden genau. Im Gegensatz dazu mögen Zahlen 1.1 und 2.2 haben keine genaue Darstellungen in binären Fließ Punkt. Endanwender würden typischerweise nicht erwarten 1.1 + 2.2 angezeigt werden als 3,3000000000000003 wie es binäre Gleitkomma tut mit.
Dezimal bietet die Art von Operationen, die es einfach machen, Anwendungen zu schreiben, die Floating-Point-Operationen erfordern und auch muß diese Ergebnisse in einem für Menschen lesbares Format präsentieren, zum Beispiel Buchhaltung.
Es ist ein großes Problem in der Tat. Probieren Sie diesen Code ein:
print "%.2f" % (round((2*4.4+3*5.6+3*4.4)/8,2),)
Es zeigt 4,85. Dann sind Sie tun:
print "Media = %.1f" % (round((2*4.4+3*5.6+3*4.4)/8,1),)
, und es zeigt 4.8. Haben Sie Berechnungen von Hand die genaue Antwort ist 4,85, aber wenn Sie versuchen:
print "Media = %.20f" % (round((2*4.4+3*5.6+3*4.4)/8,20),)
Sie, die Wahrheit sehen. Der Schwimmer Punkt als nächste endliche Summe von Fraktionen, deren Nenner sind Zweierpotenzen gespeichert
Sie können die String-Format Operator %
, ähnlich wie sprintf verwenden.
mystring = "%.2f" % 5.5999
printf der Sauger.
print '%.1f' % 5.59 # returns 5.6
funktioniert perfekt
format(5.59, '.1f') # to display
float(format(5.59, '.1f')) #to round
ich tue:
int(round( x , 0))
In diesem Fall haben wir erste Runde richtig auf die Einheit, dann wandeln wir integer Drucken eines Schwimmers zu vermeiden.
so
>>> int(round(5.59,0))
6
Ich glaube, diese Antwort funktioniert besser als die Zeichenfolge Formatierung, und es macht auch mehr sens mir die Rundenfunktion zu verwenden.
Code:
x1 = 5.63
x2 = 5.65
print(float('%.2f' % round(x1,1))) # gives you '5.6'
print(float('%.2f' % round(x2,1))) # gives you '5.7'
Ausgabe:
5.6
5.7
Hier sehe ich, dass die Runde versagt.Was wäre, wenn Sie diese beiden Zahlen auf eine Dezimalstelle runden möchten?23.45 23.55 Meine Ausbildung war, dass Sie durch die Abrunden von diesen erhalten sollten:23.4 23.6 Die "Regel" ist, dass Sie sich zusammenschließen sollten, wenn die vorhergehende Zahl ungerade war, nicht runden, wenn die vorhergehende Zahl gleichmäßig war.Die Round-Funktion in Python schneidet einfach die 5 ab.
Das Problem ist nur, wenn letzte Ziffer 5. Eg. 0.045 wird intern als ,044999999999999 gespeichert ... Sie einfach letzte Ziffer 6 und abrunden erhöhen könnte. Dies gibt Ihnen die gewünschten Ergebnisse.
import re
def custom_round(num, precision=0):
# Get the type of given number
type_num = type(num)
# If the given type is not a valid number type, raise TypeError
if type_num not in [int, float, Decimal]:
raise TypeError("type {} doesn't define __round__ method".format(type_num.__name__))
# If passed number is int, there is no rounding off.
if type_num == int:
return num
# Convert number to string.
str_num = str(num).lower()
# We will remove negative context from the number and add it back in the end
negative_number = False
if num < 0:
negative_number = True
str_num = str_num[1:]
# If number is in format 1e-12 or 2e+13, we have to convert it to
# to a string in standard decimal notation.
if 'e-' in str_num:
# For 1.23e-7, e_power = 7
e_power = int(re.findall('e-[0-9]+', str_num)[0][2:])
# For 1.23e-7, number = 123
number = ''.join(str_num.split('e-')[0].split('.'))
zeros = ''
# Number of zeros = e_power - 1 = 6
for i in range(e_power - 1):
zeros = zeros + '0'
# Scientific notation 1.23e-7 in regular decimal = 0.000000123
str_num = '0.' + zeros + number
if 'e+' in str_num:
# For 1.23e+7, e_power = 7
e_power = int(re.findall('e\+[0-9]+', str_num)[0][2:])
# For 1.23e+7, number_characteristic = 1
# characteristic is number left of decimal point.
number_characteristic = str_num.split('e+')[0].split('.')[0]
# For 1.23e+7, number_mantissa = 23
# mantissa is number right of decimal point.
number_mantissa = str_num.split('e+')[0].split('.')[1]
# For 1.23e+7, number = 123
number = number_characteristic + number_mantissa
zeros = ''
# Eg: for this condition = 1.23e+7
if e_power >= len(number_mantissa):
# Number of zeros = e_power - mantissa length = 5
for i in range(e_power - len(number_mantissa)):
zeros = zeros + '0'
# Scientific notation 1.23e+7 in regular decimal = 12300000.0
str_num = number + zeros + '.0'
# Eg: for this condition = 1.23e+1
if e_power < len(number_mantissa):
# In this case, we only need to shift the decimal e_power digits to the right
# So we just copy the digits from mantissa to characteristic and then remove
# them from mantissa.
for i in range(e_power):
number_characteristic = number_characteristic + number_mantissa[i]
number_mantissa = number_mantissa[i:]
# Scientific notation 1.23e+1 in regular decimal = 12.3
str_num = number_characteristic + '.' + number_mantissa
# characteristic is number left of decimal point.
characteristic_part = str_num.split('.')[0]
# mantissa is number right of decimal point.
mantissa_part = str_num.split('.')[1]
# If number is supposed to be rounded to whole number,
# check first decimal digit. If more than 5, return
# characteristic + 1 else return characteristic
if precision == 0:
if mantissa_part and int(mantissa_part[0]) >= 5:
return type_num(int(characteristic_part) + 1)
return type_num(characteristic_part)
# Get the precision of the given number.
num_precision = len(mantissa_part)
# Rounding off is done only if number precision is
# greater than requested precision
if num_precision <= precision:
return num
# Replace the last '5' with 6 so that rounding off returns desired results
if str_num[-1] == '5':
str_num = re.sub('5$', '6', str_num)
result = round(type_num(str_num), precision)
# If the number was negative, add negative context back
if negative_number:
result = result * -1
return result
Was ist mit:
round(n,1)+epsilon