Python内置函数round()的功能是对实数进行四舍五入,完整语法如下,
其中,参数ndigits用来指定最多保留几位小数。这个函数有时候表现有的出人意料,很多朋友感觉不好理解,例如:
很显然,试图通过大量样本测试来发现规律是不可取的。如果查阅相关资料的话,会发现有“四舍六入五成双”或“四舍六入五凑偶”的说法。以ndigits=2为例,如果第3位小数<=4则直接舍去;如果第3位小数>=6则进1;如果第3位恰好为5且后面还有小数则进1;如果第3位恰好为5且后面没有小数则第2位为奇数时进1而第2位为偶数时不进1,也就是尽量让第2位小数为偶数。
然而,上面的规则似乎无法解释round()函数的全部表现,例如round(1.255, 2)==>1.25,第3位恰好为5且后面没有小数,第2位的5是奇数,但返回的结果并没有进1把第2位变为偶数。
在计算机中使用固定长度的二进制数表示时,绝大部分实数都不能精确存储和表示,是存在误差的,我们看到的并不是内存中实际存储的值,所以才会出现表达式0.4-0.3 == 0.1的值为False这样的情况。
“四舍六入五成双”规则是针对数值具有足够多位数的情况的,例如round(1.35001, 1)==>1.4以及round(1.315001, 2)==>1.32,这样的结果是很显然的。
对于最后一位是5且恰好要把它舍去时要不要进1的情况,可以借助于Python标准库decimal中的高精度实数类Decimal来帮忙理解四舍五入的问题。Python内置的实数类型是float,把一个float类型的实数转换为Decimal高精度实数,可以查看实际值的更多位数,然后再按照“四舍六入五成双”或“四舍六入五凑偶”的规则理四舍五入就容易了。例如:
从上面的代码可以看出,1.275、1.285、1.295这样的数字在内存中实际存储的值都比原来的值略小一点,所以保留2位小数时第3位的4和后面的所有位都会直接丢弃。1.195在内存中实际存储的值比原来的值略大,所以保留2位小数时第3位的5会进1。1.5、2.5这样的数字与内存中实际存储的值完全相等,1.5保留0位小数时前面是奇数所以进1凑成偶数,2.5保留0位小数时前面是偶数所以没有进1。