Edited at

python3の四捨五入でハマったのでメモ


python2の四捨五入

四捨五入にはround()を使います。

>>> round(1.5)

2.0
>>> round(2.5)
3.0
>>> round(10.0/3, 0)
3.0

一般的な四捨五入ですね。


python3の四捨五入

>>> round(1.5)

2
>>> round(2.5)
2
>>> round(10.0/3, 0)
3.0

結果が異なる。


なにこれ

以下、Wikipedia先生より

端数処理


最近接偶数への丸め[編集]

最近接偶数への丸め (round to the nearest even; RN) は、端数が0.5より小さいなら切り捨て、端数が0.5より大きいならは切り上げ、端数がちょうど0.5なら切り捨てと切り上げのうち結果が偶数となる方へ丸める。JIS Z 8401で規則Aとして定められていて、規則B(四捨五入)より「望ましい」とされている。

四捨五入ではバイアスが発生する、端数0.5のデータが有限割合で存在する場合でも、バイアスがないのが特徴であり、多数足し合わせても丸め誤差が特定の側に偏って累積することがない(偶数+0.5は現れるが奇数+0.5は現れない、といったような特徴があるデータであれば、やはりバイアスはあらわれる)。


とのこと。


解決策

python3のroundをpython2と同様にするための、my_round関数を作ります。



import math

def my_round(x, d=0):

p = 10 ** d

return float(math.floor((x * p) + math.copysign(0.5, x)))/p

こんな感じになるらしい。

(09/03/2016 追記 shiracamusさんありがとうございます)

lambdaを使えばもっと簡単になる。




round=lambda x:(x*2+1)//2

round(1.5)

2.0

round(2.5)

3.0

round(10.0/3.0)

3.0