Runden von Dezimalzahlen und ganzen Zahlen in Python mit “round” und “Decimal.quantize

Geschäft

Im Folgenden wird erklärt, wie man Zahlen in Python durch Runden oder Aufrunden auf eine gerade Zahl rundet. Es wird angenommen, dass die Zahlen vom Typ Fließkomma-Float oder Ganzzahl-Int sind.

  • eingebaute Funktion (z.B. in einer Programmiersprache): round()
    • Runden Sie Dezimalzahlen auf eine beliebige Anzahl von Ziffern.
    • Rundet ganze Zahlen auf eine beliebige Anzahl von Ziffern.
    • round() rundet auf eine gerade Zahl, nicht auf eine gewöhnliche Rundung
  • Standardbibliothekdecimal quantize()
    • DecimalErstellen eines Objekts
    • Rundung von Dezimalzahlen auf eine beliebige Anzahl von Ziffern und Rundung auf gerade Zahlen
    • Rundung ganzer Zahlen auf eine beliebige Anzahl von Ziffern und Rundung auf gerade Zahlen
  • Definieren Sie eine neue Funktion
    • Runden Sie Dezimalstellen auf eine beliebige Anzahl von Ziffern ab.
    • Runde ganze Zahlen auf eine beliebige Anzahl von Ziffern
    • Hinweis: Bei negativen Werten

Beachten Sie, dass, wie oben erwähnt, die eingebaute Funktion round keine allgemeine Rundung ist, sondern eine Rundung auf eine gerade Zahl. Siehe unten für Details.

eingebaute Funktion (z.B. in einer Programmiersprache): round()

Round() wird als eingebaute Funktion bereitgestellt. Sie kann ohne den Import von Modulen verwendet werden.

Das erste Argument ist die ursprüngliche Zahl, das zweite Argument ist die Anzahl der Stellen (wie viele Stellen aufgerundet werden).

Runden Sie Dezimalzahlen auf eine beliebige Anzahl von Ziffern.

Es folgt ein Beispiel für die Verarbeitung des Typs Gleitkomma-Float.

Wenn das zweite Argument weggelassen wird, wird es auf eine ganze Zahl gerundet. Der Typ wird ebenfalls zu einem Integer int-Typ.

f = 123.456

print(round(f))
# 123

print(type(round(f)))
# <class 'int'>

Wenn das zweite Argument angegeben ist, wird ein Fließkomma-Float-Typ zurückgegeben.

Wird eine positive ganze Zahl angegeben, wird die Dezimalstelle angegeben; wird eine negative ganze Zahl angegeben, wird die Ganzzahlstelle angegeben. -1 rundet auf die nächste Zehntelstelle, -2 rundet auf die nächste Hundertstelstelle und 0 rundet auf eine ganze Zahl (die erste Stelle), gibt aber einen Float-Typ zurück, anders als wenn er weggelassen wird.

print(round(f, 1))
# 123.5

print(round(f, 2))
# 123.46

print(round(f, -1))
# 120.0

print(round(f, -2))
# 100.0

print(round(f, 0))
# 123.0

print(type(round(f, 0)))
# <class 'float'>

Rundet ganze Zahlen auf eine beliebige Anzahl von Ziffern.

Nachfolgend ein Beispiel für die Verarbeitung von Ganzzahlen vom Typ int.

Wird das zweite Argument weggelassen oder wird 0 oder eine positive ganze Zahl angegeben, wird der ursprüngliche Wert unverändert zurückgegeben. Wird eine negative ganze Zahl angegeben, wird auf die entsprechende ganze Zahl gerundet. In beiden Fällen wird eine Ganzzahl vom Typ int zurückgegeben.

i = 99518

print(round(i))
# 99518

print(round(i, 2))
# 99518

print(round(i, -1))
# 99520

print(round(i, -2))
# 99500

print(round(i, -3))
# 100000

round() rundet auf eine gerade Zahl, nicht auf eine gewöhnliche Rundung

Beachten Sie, dass das Runden mit der eingebauten Funktion round() in Python 3 auf eine gerade Zahl rundet, nicht auf eine allgemeine Rundung.

Wie in der offiziellen Dokumentation beschrieben, wird 0,5 auf 0 gerundet, 5 auf 0 und so weiter.

print('0.4 =>', round(0.4))
print('0.5 =>', round(0.5))
print('0.6 =>', round(0.6))
# 0.4 => 0
# 0.5 => 0
# 0.6 => 1

print('4 =>', round(4, -1))
print('5 =>', round(5, -1))
print('6 =>', round(6, -1))
# 4 => 0
# 5 => 0
# 6 => 10

Die Definition des Aufrundens auf eine gerade Zahl lautet wie folgt.

Ist der Bruch kleiner als 0,5, rundet man ab; ist der Bruch größer als 0,5, rundet man auf; ist der Bruch genau 0,5, rundet man auf die gerade Zahl zwischen Ab- und Aufrundung auf.
Rounding – Wikipedia

0,5 wird nicht immer abgeschnitten.

print('0.5 =>', round(0.5))
print('1.5 =>', round(1.5))
print('2.5 =>', round(2.5))
print('3.5 =>', round(3.5))
print('4.5 =>', round(4.5))
# 0.5 => 0
# 1.5 => 2
# 2.5 => 2
# 3.5 => 4
# 4.5 => 4

In einigen Fällen gilt die Definition des Rundens auf eine gerade Zahl nicht einmal für die Verarbeitung nach zwei Dezimalstellen.

print('0.05 =>', round(0.05, 1))
print('0.15 =>', round(0.15, 1))
print('0.25 =>', round(0.25, 1))
print('0.35 =>', round(0.35, 1))
print('0.45 =>', round(0.45, 1))
# 0.05 => 0.1
# 0.15 => 0.1
# 0.25 => 0.2
# 0.35 => 0.3
# 0.45 => 0.5

Dies ist darauf zurückzuführen, dass Dezimalzahlen nicht exakt als Fließkommazahlen dargestellt werden können, wie in der offiziellen Dokumentation angegeben.

Das Verhalten von round() für Fließkommazahlen mag Sie überraschen:Wenn Sie zum Beispiel round(2.675, 2) eingeben, erhalten Sie 2.67 statt wie erwartet 2.68. Dies ist kein Fehler.:Dies ist darauf zurückzuführen, dass die meisten Dezimalzahlen nicht exakt durch Gleitkommazahlen dargestellt werden können.
round() — Built-in Functions — Python 3.10.2 Documentation

Wenn Sie eine allgemeine Rundung oder eine genaue Rundung von Dezimalzahlen auf gerade Zahlen erreichen wollen, können Sie die Standardbibliothek decimal quantize (siehe unten) verwenden oder eine neue Funktion definieren.

Beachten Sie auch, dass round() in Python 2 nicht auf eine gerade Zahl rundet, sondern rundet.

quantize() der Standardbibliothek decimal

Das Dezimalmodul der Standardbibliothek kann verwendet werden, um exakte dezimale Gleitkommazahlen zu verarbeiten.

Mit der Methode quantize() des Dezimalmoduls ist es möglich, Zahlen zu runden, indem man den Rundungsmodus angibt.

Die eingestellten Werte für das Argument Rundung der Methode quantize() haben jeweils die folgende Bedeutung.

  • ROUND_HALF_UP:Allgemeine Rundung
  • ROUND_HALF_EVEN:Rundung auf gerade Zahlen

Das Dezimalmodul ist eine Standardbibliothek, so dass keine zusätzliche Installation erforderlich ist, aber der Import ist notwendig.

from decimal import Decimal, ROUND_HALF_UP, ROUND_HALF_EVEN

Erstellen eines Decimal-Objekts

Decimal() kann verwendet werden, um Objekte vom Typ Decimal zu erzeugen.

Wenn Sie einen Float-Typ als Argument angeben, können Sie sehen, als was der Wert tatsächlich behandelt wird.

print(Decimal(0.05))
# 0.05000000000000000277555756156289135105907917022705078125

print(type(Decimal(0.05)))
# <class 'decimal.Decimal'>

Wie im Beispiel gezeigt, wird 0,05 nicht als genau 0,05 behandelt. Dies ist der Grund, warum die oben beschriebene eingebaute Funktion round() bei Dezimalwerten einschließlich 0,05 im Beispiel auf einen anderen Wert als erwartet rundet.

Da 0,5 die Hälfte ist (-1 Potenz von 2), kann es genau in binärer Notation ausgedrückt werden.

print(Decimal(0.5))
# 0.5

Wenn Sie den Stringtyp str anstelle des Float-Typs angeben, wird er als Dezimaltyp des exakten Wertes behandelt.

print(Decimal('0.05'))
# 0.05

Rundung von Dezimalzahlen auf eine beliebige Anzahl von Ziffern und Rundung auf gerade Zahlen

Rufen Sie quantize() von einem Objekt des Typs Decimal auf, um den Wert abzurunden.

Das erste Argument von quantize() ist eine Zeichenkette mit der gleichen Anzahl von Ziffern wie die Anzahl der gesuchten Ziffern, z. B. '0,1' oder '0,01'.

Darüber hinaus gibt das Argument ROUNDING den Rundungsmodus an; wenn ROUND_HALF_UP angegeben ist, wird allgemein gerundet.

f = 123.456

print(Decimal(str(f)).quantize(Decimal('0'), rounding=ROUND_HALF_UP))
# 123

print(Decimal(str(f)).quantize(Decimal('0.1'), rounding=ROUND_HALF_UP))
# 123.5

print(Decimal(str(f)).quantize(Decimal('0.01'), rounding=ROUND_HALF_UP))
# 123.46

Anders als bei der eingebauten Funktion round() wird 0,5 auf 1 gerundet.

print('0.4 =>', Decimal(str(0.4)).quantize(Decimal('0'), rounding=ROUND_HALF_UP))
print('0.5 =>', Decimal(str(0.5)).quantize(Decimal('0'), rounding=ROUND_HALF_UP))
print('0.6 =>', Decimal(str(0.6)).quantize(Decimal('0'), rounding=ROUND_HALF_UP))
# 0.4 => 0
# 0.5 => 1
# 0.6 => 1

Wenn das Argument rounding auf ROUND_HALF_EVEN gesetzt ist, wird wie bei der eingebauten Funktion round() auf gerade Zahlen gerundet.

Wie bereits erwähnt, wird ein Gleitkomma-Float-Typ, der als Argument von Decimal() angegeben wird, als Decimal-Objekt mit einem Wert behandelt, der dem tatsächlichen Wert des Float-Typs entspricht, so dass das Ergebnis der Methode quantize() anders ausfällt als erwartet, genau wie bei der eingebauten Funktion round().

print('0.05 =>', round(0.05, 1))
print('0.15 =>', round(0.15, 1))
print('0.25 =>', round(0.25, 1))
print('0.35 =>', round(0.35, 1))
print('0.45 =>', round(0.45, 1))
# 0.05 => 0.1
# 0.15 => 0.1
# 0.25 => 0.2
# 0.35 => 0.3
# 0.45 => 0.5

print('0.05 =>', Decimal(0.05).quantize(Decimal('0.1'), rounding=ROUND_HALF_EVEN))
print('0.15 =>', Decimal(0.15).quantize(Decimal('0.1'), rounding=ROUND_HALF_EVEN))
print('0.25 =>', Decimal(0.25).quantize(Decimal('0.1'), rounding=ROUND_HALF_EVEN))
print('0.35 =>', Decimal(0.35).quantize(Decimal('0.1'), rounding=ROUND_HALF_EVEN))
print('0.45 =>', Decimal(0.45).quantize(Decimal('0.1'), rounding=ROUND_HALF_EVEN))
# 0.05 => 0.1
# 0.15 => 0.1
# 0.25 => 0.2
# 0.35 => 0.3
# 0.45 => 0.5

Wenn das Argument von Decimal() als Zeichenkette vom Typ str angegeben wird, wird es als Decimal-Objekt mit genau diesem Wert behandelt, so dass das Ergebnis wie erwartet ist.

print('0.05 =>', Decimal(str(0.05)).quantize(Decimal('0.1'), rounding=ROUND_HALF_EVEN))
print('0.15 =>', Decimal(str(0.15)).quantize(Decimal('0.1'), rounding=ROUND_HALF_EVEN))
print('0.25 =>', Decimal(str(0.25)).quantize(Decimal('0.1'), rounding=ROUND_HALF_EVEN))
print('0.35 =>', Decimal(str(0.35)).quantize(Decimal('0.1'), rounding=ROUND_HALF_EVEN))
print('0.45 =>', Decimal(str(0.45)).quantize(Decimal('0.1'), rounding=ROUND_HALF_EVEN))
# 0.05 => 0.0
# 0.15 => 0.2
# 0.25 => 0.2
# 0.35 => 0.4
# 0.45 => 0.4

Da 0,5 vom Typ float korrekt gehandhabt werden kann, ist es kein Problem, den Typ float als Argument von Decimal() anzugeben, wenn auf eine ganze Zahl gerundet wird, aber es ist sicherer, den Typ string str anzugeben, wenn auf eine Dezimalstelle gerundet wird.

Zum Beispiel ist 2,675 eigentlich 2,67499…. im Float-Typ. Wenn Sie also auf zwei Nachkommastellen runden wollen, müssen Sie Decimal() eine Zeichenkette übergeben. Andernfalls unterscheidet sich das Ergebnis vom erwarteten Ergebnis, egal ob Sie auf die nächste ganze Zahl (ROUND_HALF_UP) oder auf eine gerade Zahl (ROUND_HALF_EVEN) runden.

print(Decimal(2.675))
# 2.67499999999999982236431605997495353221893310546875

print(Decimal(2.675).quantize(Decimal('0.01'), rounding=ROUND_HALF_UP))
# 2.67

print(Decimal(str(2.675)).quantize(Decimal('0.01'), rounding=ROUND_HALF_UP))
# 2.68

print(Decimal(2.675).quantize(Decimal('0.01'), rounding=ROUND_HALF_EVEN))
# 2.67

print(Decimal(str(2.675)).quantize(Decimal('0.01'), rounding=ROUND_HALF_EVEN))
# 2.68

Beachten Sie, dass die Methode quantize() eine Zahl vom Typ Decimal zurückgibt. Wenn Sie also mit einer Zahl vom Typ Float arbeiten wollen, müssen Sie sie mit float() in einen Float-Typ umwandeln, sonst tritt ein Fehler auf.

d = Decimal('123.456').quantize(Decimal('0.01'), rounding=ROUND_HALF_UP)

print(d)
# 123.46

print(type(d))
# <class 'decimal.Decimal'>

# print(1.2 + d)
# TypeError: unsupported operand type(s) for +: 'float' and 'decimal.Decimal'

print(1.2 + float(d))
# 124.66

Rundung ganzer Zahlen auf eine beliebige Anzahl von Ziffern und Rundung auf gerade Zahlen

Wenn Sie auf eine ganze Zahl runden wollen, führt die Angabe von '10' als erstes Argument nicht zum gewünschten Ergebnis.

i = 99518

print(Decimal(i).quantize(Decimal('10'), rounding=ROUND_HALF_UP))
# 99518

Das liegt daran, dass quantize() die Rundung entsprechend dem Exponenten des Decimal-Objekts vornimmt, der Exponent von Decimal('10') aber 0 und nicht 1 ist.

Sie können einen beliebigen Exponenten angeben, indem Sie E als Exponenten-String verwenden (z. B. '1E1'). Der Exponent Exponent kann in der as_tuple-Methode überprüft werden.

print(Decimal('10').as_tuple())
# DecimalTuple(sign=0, digits=(1, 0), exponent=0)

print(Decimal('1E1').as_tuple())
# DecimalTuple(sign=0, digits=(1,), exponent=1)

So wie es ist, wird das Ergebnis in exponentieller Notation unter Verwendung von E sein. Wenn Sie die normale Notation verwenden wollen, oder wenn Sie nach dem Runden mit dem Ganzzahlentyp int arbeiten wollen, verwenden Sie int(), um das Ergebnis umzuwandeln.

print(Decimal(i).quantize(Decimal('1E1'), rounding=ROUND_HALF_UP))
# 9.952E+4

print(int(Decimal(i).quantize(Decimal('1E1'), rounding=ROUND_HALF_UP)))
# 99520

print(int(Decimal(i).quantize(Decimal('1E2'), rounding=ROUND_HALF_UP)))
# 99500

print(int(Decimal(i).quantize(Decimal('1E3'), rounding=ROUND_HALF_UP)))
# 100000

Wenn das Argument rounding auf ROUND_HALF_UP gesetzt ist, wird allgemein gerundet, z.B. wird 5 auf 10 gerundet.

print('4 =>', int(Decimal(4).quantize(Decimal('1E1'), rounding=ROUND_HALF_UP)))
print('5 =>', int(Decimal(5).quantize(Decimal('1E1'), rounding=ROUND_HALF_UP)))
print('6 =>', int(Decimal(6).quantize(Decimal('1E1'), rounding=ROUND_HALF_UP)))
# 4 => 0
# 5 => 10
# 6 => 10

Natürlich gibt es kein Problem, wenn Sie es als Zeichenkette angeben.

Definieren Sie eine neue Funktion

Die Methode der Verwendung des Dezimalmoduls ist genau und sicher, aber wenn Sie mit der Typkonvertierung nicht zurechtkommen, können Sie eine neue Funktion definieren, um eine allgemeine Rundung zu erreichen.

Es gibt viele Möglichkeiten, dies zu tun, zum Beispiel die folgende Funktion.

def my_round(val, digit=0):
    p = 10 ** digit
    return (val * p * 2 + 1) // 2 / p

Wenn Sie die Anzahl der Ziffern nicht angeben müssen und immer auf die erste Dezimalstelle runden, können Sie eine einfachere Form verwenden.

my_round_int = lambda x: int((x * 2 + 1) // 2)

Wenn Sie genau sein müssen, ist es sicherer, Dezimalzahlen zu verwenden.

Die folgenden Angaben dienen lediglich als Referenz.

Runden Sie Dezimalstellen auf eine beliebige Anzahl von Ziffern ab.

print(int(my_round(f)))
# 123

print(my_round_int(f))
# 123

print(my_round(f, 1))
# 123.5

print(my_round(f, 2))
# 123.46

Im Gegensatz zur Rundung wird 0,5 zu 1, wie bei der allgemeinen Rundung.

print(int(my_round(0.4)))
print(int(my_round(0.5)))
print(int(my_round(0.6)))
# 0
# 1
# 1

Runde ganze Zahlen auf eine beliebige Anzahl von Ziffern

i = 99518

print(int(my_round(i, -1)))
# 99520

print(int(my_round(i, -2)))
# 99500

print(int(my_round(i, -3)))
# 100000

Im Gegensatz zur Rundung wird aus 5 eine 10, wie es beim Runden üblich ist.

print(int(my_round(4, -1)))
print(int(my_round(5, -1)))
print(int(my_round(6, -1)))
# 0
# 10
# 10

Hinweis: Bei negativen Werten

In der obigen Beispielfunktion wird -0,5 auf 0 gerundet.

print(int(my_round(-0.4)))
print(int(my_round(-0.5)))
print(int(my_round(-0.6)))
# 0
# 0
# -1

Es gibt verschiedene Möglichkeiten, negative Werte zu runden, aber wenn Sie -0,5 in -1 umwandeln wollen, können Sie dies zum Beispiel wie folgt tun

import math

def my_round2(val, digit=0):
    p = 10 ** digit
    s = math.copysign(1, val)
    return (s * val * p * 2 + 1) // 2 / p * s

print(int(my_round2(-0.4)))
print(int(my_round2(-0.5)))
print(int(my_round2(-0.6)))
# 0
# -1
# -1
Copied title and URL