为何1+machine epsilon+machine epsilon/2调换加法顺序后结果不等?
浮点数加法运算顺序差异原理说明
核心前提澄清
- 你观测到的差异不是加法交换律不成立,浮点数加法本身满足交换律(a+b = b+a),但不满足结合律((a+b)+c ≠ a+(b+c)),你的两个测试用例实际是运算结合顺序不同:
- 第一个式子
1 + machine_epsilon + machine_epsilon/2实际执行顺序是(1 + machine_epsilon) + machine_epsilon/2 - 第二个式子
1 + machine_epsilon/2 + machine_epsilon实际执行顺序是(1 + machine_epsilon/2) + machine_epsilon
- 第一个式子
- 双精度浮点数(对应Python
float、Cdouble)的有效位为53位(含1位隐含整数位),机器epsilon(np.finfo(float).eps/DBL_EPSILON)是刚好能让1 + eps ≠ 1的最小正浮点数,值为2^-52 ≈ 2.2204e-16,默认舍入规则为就近舍入,中间值舍入到偶数。
第一个式子运算过程拆解
- 第一步计算
1 + eps:刚好是1之后第一个可精确表示的浮点数,无舍入,结果为1 + 2^-52 - 第二步计算
(1 + 2^-52) + 2^-53(即eps/2 = 2^-53):
结果的二进制表示为1.000...0011(小数点后第52位为1、第53位为1),超出53位有效位的部分需要舍入,按照规则进一位后得到1 + 2^-51 ≈ 1.00000000000000044409,和你的输出一致。
第二个式子运算过程拆解
- 第一步计算
1 + eps/2即1 + 2^-53:
结果的二进制表示为1.000...0001(小数点后第53位为1),刚好位于1和1+eps的正中间,按照中间值舍入到偶数的规则,会舍入到最低位为偶数的1,这一步的eps/2直接被舍掉了。 - 第二步计算
1 + eps,无舍入得到1 + 2^-52 ≈ 1.00000000000000022204,和你的输出一致。
总结
差异本质是浮点数运算的每一步都会触发舍入,不同的运算顺序会导致中间结果的舍入误差完全不同,最终体现为最终结果的差异。
内容的提问来源于stack exchange,提问作者Katya Kuznetsova
相关产品推荐
相关产品推荐

