浮点运算下满足1/i == 1/(i+1)的最小正整数i及原理
结论
你找到的i = 6369051721119404就是引发该排序失效的最小正整数。
原理解释
Python默认的float类型遵循IEEE 754双精度浮点数标准,由1位符号位、11位指数位、52位尾数位组成,因尾数隐含最高位的常量1,实际有效精度为53位二进制,对应15~17位十进制有效数字。
- 对落在区间
[2^e, 2^(e+1))内的浮点数,相邻两个可精确表示的浮点数的绝对间隔为2^(e-52),数值越小,间隔越小,表示精度越高。 - 连续正整数
i和i+1的倒数差值为1/i - 1/(i+1) = 1/(i*(i+1)),当这个差值小于倒数所在区间的浮点数舍入阈值时,两个倒数会被舍入为同一个浮点数,作为排序键时无法区分大小,直接导致逆序排序失效。
你观察到临界值接近2^52.5的规律完全符合浮点数精度特性:
当i = 2^52.5时,1/i = 2^-52.5,落在浮点数区间[2^-53, 2^-52)范围内,该区间的浮点数间隔为2^(-53-52) = 2^-105 ≈ 7.89e-32;此时1/(i*(i+1)) ≈ 1/i² = 1/2^105,刚好和浮点数间隔处于同一量级,达到了舍入后相等的临界条件。
受浮点数就近舍入、等值时取偶数尾数值的规则影响,第一个满足“两数倒数舍入后相等”的正整数就是你找到的6369051721119404,比理论近似值2^52.5略大,和你运行math.log2(i)得到的52.50000001100726结果完全吻合。
失效复现
执行以下排序代码时,两个元素的排序键完全相等,排序后不会交换位置,无法得到预期的逆序结果:
import math i = 6369051721119404 print(1/i == 1/(i+1)) # 输出:True print(math.log2(i)) # 输出:52.50000001100726 print(sorted([i, i+1], key=lambda x: 1/x)) # 输出:[6369051721119404, 6369051721119405],未按预期逆序
实际开发中做逆序排序直接使用
-i作为键即可,Python的int类型支持任意精度,不会出现这类精度问题,不要用1/i的取巧写法处理大整数排序场景。
内容的提问来源于stack exchange,提问作者Kelly Bundy
相关产品推荐
相关产品推荐

