下面解釋如何在 Python 中通過舍入或舍入到偶數來對數字進行舍入。這些數字被假定為浮點浮點或整數 int 類型。
- 內置函數(例如在編程語言中):
round()
- 將小數四捨五入到任意位數。
- 將整數四捨五入為任意位數。
- round() 舍入到偶數,而不是普通舍入
- 標準庫
decimal
quantize()
Decimal
創建對象- 將小數四捨五入為任意位數並四捨五入為偶數
- 將整數四捨五入為任意位數並四捨五入為偶數
- 定義一個新函數
- 將小數四捨五入到任意位數。
- 將整數四捨五入為任意位數
- 注意:對於負值
注意,如上所述,內置函數 round 不是一般的捨入,而是捨入到偶數。詳情見下文。
內置函數(例如在編程語言中):round()
Round() 作為內置函數提供。它可以在不導入任何模塊的情況下使用。
第一個參數是原始數字,第二個參數是位數(要四捨五入的位數)。
將小數四捨五入到任意位數。
以下是浮點浮點類型的處理示例。
如果省略第二個參數,則將其四捨五入為整數。該類型也變為整數 int 類型。
f = 123.456 print(round(f)) # 123 print(type(round(f))) # <class 'int'>
如果指定了第二個參數,則返回浮點浮點類型。
如果指定正整數,則指定小數位;如果指定了負整數,則指定整數位。 -1 舍入到最接近的十分之一,-2 舍入到最接近的百分之一,0 舍入到整數(第一位),但返回浮點類型,與省略時不同。
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'>
將整數四捨五入為任意位數。
以下是整型 int 類型的處理示例。
如果省略第二個參數,或者指定 0 或正整數,則按原樣返回原始值。如果指定了負整數,則將其四捨五入到相應的整數位。在這兩種情況下,都會返回整數 int 類型。
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() 舍入到偶數,而不是普通舍入
請注意,使用 Python 3 中的內置 round() 函數舍入到偶數,而不是一般舍入。
官方文檔中寫的,0.5四捨五入為0,5四捨五入為0,以此類推。
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
四捨五入到偶數的定義如下。
如果分數小於 0.5,則向下取整;如果分數大於 0.5,則向上取整;如果分數恰好為 0.5,則將其向上舍入到向下舍入和向上舍入之間的偶數。
Rounding – Wikipedia
0.5 並不總是被截斷。
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
在某些情況下,舍入到偶數的定義甚至不適用於小數點後兩位的處理。
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
這是因為小數不能完全表示為浮點數,如官方文檔中所述。
浮點數的 round() 行為可能會讓您感到驚訝:例如,round(2.675, 2) 會給你 2.67 而不是預期的 2.68。這不是錯誤。:這是因為大多數小數不能用浮點數精確表示。
round() — Built-in Functions — Python 3.10.2 Documentation
如果要實現小數的一般舍入或精確舍入為偶數,可以使用標準庫十進制量化(如下所述)或定義一個新函數。
另請注意,Python 2 中的 round() 不是四捨五入到偶數,而是四捨五入。
標準庫十進制的 quantize()
標準庫的十進制模塊可用於處理精確的十進制浮點數。
使用 decimal 模塊的 quantize() 方法,可以通過指定舍入模式對數字進行舍入。
- decimal quantize() — Decimal fixed point and floating point arithmetic — Python 3.10.2 Documentation
- Rounding modes — Decimal fixed point and floating point arithmetic — Python 3.10.2 Documentation
quantize() 方法的參數舍入的設置值分別具有以下含義。
ROUND_HALF_UP
:一般舍入ROUND_HALF_EVEN
:四捨五入為偶數
十進制模塊是一個標準庫,所以不需要額外安裝,但需要導入。
from decimal import Decimal, ROUND_HALF_UP, ROUND_HALF_EVEN
創建十進制對象
Decimal() 可用於創建 Decimal 類型的對象。
如果將浮點類型指定為參數,則可以看到該值實際被視為什麼。
print(Decimal(0.05)) # 0.05000000000000000277555756156289135105907917022705078125 print(type(Decimal(0.05))) # <class 'decimal.Decimal'>
如示例中所示,0.05 不完全被視為 0.05。這就是為什麼上述內置函數 round() 舍入到與示例中的十進制值(包括 0.05)不同的值的原因。
由於 0.5 是二分之一(2 的 -1 次方),因此可以精確地用二進製表示法表示。
print(Decimal(0.5)) # 0.5
如果指定字符串類型 str 而不是 float 類型,它將被視為精確值的 Decimal 類型。
print(Decimal('0.05')) # 0.05
將小數四捨五入為任意位數並四捨五入為偶數
從 Decimal 類型的對象調用 quantize() 以四捨五入該值。
quantize() 的第一個參數是一個字符串,其位數與您要查找的位數相同,例如“0.1”或“0.01”。
此外,參數 ROUNDING 指定舍入模式;如果指定了 ROUND_HALF_UP,則使用一般舍入。
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
與內置函數 round() 不同,0.5 舍入為 1。
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
如果參數舍入設置為 ROUND_HALF_EVEN,則舍入到偶數,如內置函數 round()。
如前所述,如果指定浮點浮點類型作為 Decimal() 的參數,則將其視為 Decimal 對象,其值等於浮點類型的實際值,因此使用 quantize() 的結果方法將與預期不同,就像內置函數 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
如果 Decimal() 的參數指定為 str 類型的字符串,則將其視為恰好具有該值的 Decimal 對象,因此結果符合預期。
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
由於 0.5 可以通過 float 類型正確處理,因此在舍入為整數時指定 float 類型作為 Decimal() 的參數是沒有問題的,但在舍入到小數位時指定字符串 str 類型更安全。
例如,2.675 實際上是 2.67499…. 浮點型。因此,如果要四捨五入到兩位小數,必須在 Decimal() 中指定一個字符串,否則無論是四捨五入到最接近的整數 (ROUND_HALF_UP) 還是偶數 (ROUND_HALF_EVEN),結果都會與預期結果不同)。
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
注意quantize()方法返回的是Decimal類型的數字,所以如果要對float類型的數字進行操作,需要使用float()將其轉換為float類型,否則會報錯。
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
將整數四捨五入為任意位數並四捨五入為偶數
如果你想四捨五入到一個整數,指定像“10”這樣的第一個參數不會給你想要的結果。
i = 99518 print(Decimal(i).quantize(Decimal('10'), rounding=ROUND_HALF_UP)) # 99518
這是因為 quantize() 根據 Decimal 對象的指數進行舍入,但 Decimal(’10’) 的指數是 0,而不是 1。
您可以通過使用 E 作為指數字符串來指定任意指數(例如,’1E1’)。可以在 as_tuple 方法中檢查指數指數。
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)
實際上,結果將使用 E 以指數表示法。如果您想使用普通表示法,或者如果您想在舍入後使用整數 int 類型進行操作,請使用 int() 轉換結果。
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
如果參數舍入設置為 ROUND_HALF_UP,將進行一般舍入,例如,5 將舍入為 10。
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
當然,如果指定為字符串也沒有問題。
定義一個新函數
使用decimal模塊的方法準確且安全,但如果您不習慣類型轉換,您可以定義一個新函數來實現一般舍入。
有很多可能的方法可以做到這一點,例如,下面的函數。
def my_round(val, digit=0): p = 10 ** digit return (val * p * 2 + 1) // 2 / p
如果您不需要指定位數並始終四捨五入到小數點後一位,則可以使用更簡單的形式。
my_round_int = lambda x: int((x * 2 + 1) // 2)
如果您需要精確,使用小數會更安全。
以下內容僅供參考。
將小數四捨五入到任意位數。
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
與舍入不同,0.5 按照一般舍入變為 1。
print(int(my_round(0.4))) print(int(my_round(0.5))) print(int(my_round(0.6))) # 0 # 1 # 1
將整數四捨五入為任意位數
i = 99518 print(int(my_round(i, -1))) # 99520 print(int(my_round(i, -2))) # 99500 print(int(my_round(i, -3))) # 100000
與舍入不同,根據普通舍入,5 變為 10。
print(int(my_round(4, -1))) print(int(my_round(5, -1))) print(int(my_round(6, -1))) # 0 # 10 # 10
注意:對於負值
在上面的示例函數中,-0.5 舍入為 0。
print(int(my_round(-0.4))) print(int(my_round(-0.5))) print(int(my_round(-0.6))) # 0 # 0 # -1
對負值進行四捨五入的想法有很多種,但是如果要將-0.5變成-1,可以修改如下,例如
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