Python中//(floordiv)运算符对可表示为整数的浮点数返回错误结果问题
问题产生的核心原因
你观察到的现象本质是二进制浮点数的精度误差和//运算符的取整规则共同导致的,核心误区是:普通除法打印出来的9.0是格式化舍入后的结果,不代表两个操作数的商实际严格等于9。
- 十进制的
9/50 = 0.18和1/50 = 0.02都无法用双精度二进制浮点数(Python默认float类型的实现标准)精确存储:- 实际存储的
9/50是略小于0.18的近似值 - 实际存储的
1/50是略大于0.02的近似值
- 实际存储的
- 两者相除得到的实际浮点商略小于9,只是在你用
{:.50f}格式化输出时,精度限制导致舍入显示为9.0,你可以通过print((9/50)/(1/50) < 9)验证,这个判断会返回True。 //运算符不会对商做舍入,而是直接对实际的商做向下取整,小于9的数向下取整自然得到8。
floordiv(//运算符)的底层实现逻辑
针对float类型的两个操作数a和b,a // b的执行步骤如下:
- 计算
a / b的精确浮点结果,保留浮点数能表示的最高精度,不做任何整数方向的舍入 - 对上述结果执行
floor操作:即取小于等于该值的最大整数 - 将取整后的结果转换为float类型返回
你可以用以下代码验证中间值:
def show(x, n=60): return "{:.{}f}".format(x, n) # 查看两个操作数的实际存储值 print(show(9/50)) print(show(1/50)) # 查看商的实际值(60位小数下可以看到小于9) print(show((9/50)/(1/50))) # 验证商确实小于9 print((9/50)/(1/50) < 9)
内容的提问来源于stack exchange,提问作者JMC
相关产品推荐
相关产品推荐

