环境

Python 3.7

描述

在 Python 3 中,round() 函数采用银行家的思维“四舍六入五成双 银行家式舍入法”,而不是使用人类常用的思维“四舍五入”。同时还有浮点数在计算机中进行二进制存放问题,导致在使用 round() 函数时,会出现“感觉上很奇怪的舍入法”。

银行家式舍入法 四舍六入五成双

四舍六入五考虑。
五后非零就进一,
五后皆零看奇偶,
五前为偶应舍去,
五前为奇要进一。

例子

一个数 a.bcdef,需要精确到小数点后两位,那么就要看小数点后第三位:
1.如果 d 小于 5,直接舍去
2.如果 d 大于 5,直接进位
3.如果 d 等于 5:
3.1 且 d 后面没有数据,且 c 为偶数,那么不进位,保留 c
3.2 且 d 后面没有数据,且 c 为奇数,那么进位,c 变成(c + 1)
3.3 且 d 后面还有非 0 数字,此时一定要进位,c 变成(c + 1)

感觉上很奇怪的舍入法

1.315,采用“银行家式舍入法”,应该为多少?

分析

1.315,采用“银行家式舍入法”,保留两位小数,则应看看小数点第二(奇数)、三(等于5)和四位(无数据),则应执行“3.2”,则应结果应为:1.32
理论(感觉):1.32

实际

执行代码:

round(1.315, 2)

实际:1.31

为什么?

使用 Decimal(1.315) 查看 1.315 在人类眼中实际的值(十进制)。
发现 1.315 二进制转化时是有精度损失,所以实际是:1.314999999999999946709294817992486059665679931640625,导致在进行 round(1.315)时,实际执行为 round(1.31499...),则出现 1.31,而不是 1.32。

结束语

四舍五入是针对十进制的,在十进制与二进制转换中会有精度损失,再使用银行家式舍入法后,产生了感觉上奇怪的舍入法。

四舍五入代码

此函数实现了简单的四舍五入,只适用于有小数点的数且并不完善。
第一个参数:要进行四舍五入的数字
第二个参数:要保留小数点后几位

from decimal import Decimal, Context, ROUND_HALF_UP
def sswr(num, accuracy):
    str_num = str(num)
    zs_len = len(str_num.split('.')[0])
    fh = Context(prec=zs_len + accuracy, rounding=ROUND_HALF_UP).create_decimal(str_num)
    return fh

参考

https://segmentfault.com/a/1190000018929994
https://blog.csdn.net/qq_34979346/article/details/83827044

Last modification:August 24th, 2020 at 11:01 pm
如果觉得我的文章对你有用,可以请我喝杯咖啡。