Python四舍五入round精度缺失问题

Python 2016-09-02

说了你可能不信,是内置函数的锅。

起步

round()是python进行四舍五入的函数,然而这里有坑。在我不断排查,万万没想到是内置函数也有错误,在此记个坑。

20160902175619.png

这是在python2.6的环境下,保留小数位数都是错的,一个bug。于是好奇在不同版本下round是怎么工作的

python 3.x

环境:Python 3.5.2 (default, Jul 5 2016, 12:43:10)


>>> round(1.5)
2
>>> round(2.5)
2
>>> round(3.5)
4
>>> round(4.5)
4
>>> round(5.5)
6
>>> round(6.5)
6

网上找了一下,python3中又重新设置四舍五入的规则,文档中是这样解释的:

For the built-in types supporting round(), 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 (so, for example, both round(0.5) and round(-0.5) are 0, and round(1.5) is 2). The return value is an integer if called with one argument, otherwise of the same type as number.

意思就是round(123.45,1),就是取在数轴上最接近pow(10, -1)的点,但是.5情况两边距离都一样,那round()取靠近的偶数。如果要取舍的位数前的小树是奇数,则直接舍弃,如果偶数这向上取舍。这时四舍五入就变成了奇舍偶入了。

20160902180326.png

官方的解释是,计算机需要先将十进制123.45转换为二进制,这个过程会导致二进制的值比123.45略大(比如123.45000001之类的),那么自然就得到123.5这个值了.

网上是有人这样解决的:

>>> from decimal import Decimal
>>> n = Decimal('123.35')
>>> round(n,1)
Decimal('123.4')

python2.7

>>> round(1.5)
2.0
>>> round(2.5)
3.0
>>> round(3.5)
4.0
>>> round(6.5)
7.0
>>> round(2.675,2)
2.67
>>> round(6.5)
7.0
>>> round(123.45,1)
123.5
>>> round(123.35,1)
123.3
>>> round(1.555,2)
1.55

2.7版本比3来得准确,其实也就是取整时候比较正确而已。解决办法同上。

python2.6

20160902183342.png

2.6版本哪里是保留小数了啊。为什么会这样?其实这问题得归结于保存浮点数的形式。

20160902184013.png

但是但是,浮点数保存精度问题上过课都知道啊,2.7在保存也有精度误差的。但是你怎么连保留的位数都是错的啊。没有什么有效的解决办法,先用这个吧:

"%.2f" % 1.555

本文由 hongweipeng 创作,采用 知识共享署名 3.0,可自由转载、引用,但需署名作者且注明文章出处。

赏个馒头吧