作python實驗時碰到這麼一道題:html
輸入三個浮點數,求它們的平均值並保留 1 位小數,對小數後第二位數進行四捨五入,最後輸出結果
由於涉及到四捨五入,隨便搜了一下,發現了好多博客都用round(),就直接拿來用了python
round(1.555, 2) // 對小數後第二位數進行四捨五入 # 1.55
可是當我測試時發現這個四捨五入有點水
啊!好比:git
>>>round(0.5) 0 >>>round(1.5) 2
和想的不同啊,而後我就去找python的官方文檔,它是這麼描述的:函數
round(values, ndigits),values are rounded to the closest multiple of 10 to the power minus ndigits; if two multiples are equally close, rounding is done toward the even choice.
值四捨五入到最接近的10倍冪減去ndigits;若是兩個倍數相等,則四捨五入到偶數。
什麼意思?學習
我嘗試了幾個例子才明白是怎麼一回事。
若是你寫過大學物理的實驗報告,那麼你應該會記得老師講過,直接使用四捨五入,最後的結果可能會偏高。因此須要使用四捨六入五成雙
的處理方法。測試
例如對於一個小數a.bcd,須要精確到小數點後兩位,那麼就要看小數點後第三位:.net
若是d等於5:code
例如:htm
1. 0.345,4是偶數,因此5捨去,結果0.34 2. 0.3451,5後面還有數,則4進位,結果0.35
ps:負數會往絕對值更大的方向「入」、絕對值更小的方向「舍」,此處不作具體分析blog
因此,把round()當成四捨五入並非十分準確的
可是,到這裏並無完,當我又換了一組數據測試時,發現了問題:
>>>round(0.645,2) # 按照上述舍入規則,應該是0.64,但結果倒是0.65
這裏就涉及到python的浮點數存儲了,python採用IEEE754標準存儲浮點數的,因此當我輸入0.645
後,底層存儲的實際上是0011111111100100101000111101011100001010001111010111000010100100
,也即十進制的0.645000000000000017763568394002504646778106689453125
,離0.65
更近。
從上可知,round()對浮點數四捨五入存在舍入規則和浮點數存儲的問題
對於浮點數運算,python提供了Decimal
(小數)模塊來讓小數的運算更貼近咱們人正常計算的習慣。
import decimal # 修改舍入方式爲四捨五入 decimal.getcontext().rounding = "ROUND_HALF_UP" # 使用字符串來儲存小數不會有精度偏差,Decimal能夠正確處理這種方法表示的數字 decimal.Decimal("0.645").quantize(decimal.Decimal("0.00"))
或者爲了不浮點數儲存致使精度損失,乾脆所有都用字符串來儲存小數,以下:
from decimal import Decimal a = Decimal('0.655') + Decimal('0.345') b = 0.655 + 0.345 # a = 1.000 # b = 1.0
最後附上一開始的問題吧:
# 輸入三個浮點數,求它們的平均值並保留 1 位小數,對小數後第二位數進行四捨五入,最後輸出結果 import decimal numbers = list(map(decimal.Decimal, input().split(','))) # 修改舍入方式爲四捨五入 decimal.getcontext().rounding = "ROUND_HALF_UP" # 計算平均數 result = decimal.Decimal(sum(numbers) / numbers.__len__()) # 使用字符串來儲存小數不會有精度偏差,Decimal能夠正確處理這種方法表示的數字 roundResult = decimal.Decimal(str(result)).quantize(decimal.Decimal("0.00")) print(roundResult) >>>1.535,1.545,1.555 # 平均數爲1.545 1.5 # 保留一位小數, 對小數點後第二位進行四捨五入
參考文章: