Python中升序、降序排列数组求和得到两种不同结果的原因求解
差异原因分析
1 底层根源:IEEE 754浮点数的精度限制
十进制的0.1、0.2、0.3都无法用二进制浮点数精确存储,Python默认使用的双精度浮点数仅保留53位有效二进制位,存储的都是近似值:
- 0.1、0.2的存储值略大于真实十进制值
- 0.3的存储值略小于真实十进制值
2 直接原因:加法顺序导致误差累积路径不同
浮点数加法不严格满足交换律,不同运算顺序的误差抵消情况完全不同:
- 运算顺序为
0.3 + 0.2 + 0.1时:0.3的负误差和0.2的正误差首先抵消,得到精确的0.5,再加上0.1的近似值后,最终总误差刚好落在双精度浮点数可表示为0.6的范围内,因此输出结果为0.6。 - 运算顺序为
0.1 + 0.2 + 0.3时:0.1和0.2的正误差首先叠加,得到0.30000000000000004,再加上0.3的近似值后总误差无法抵消,最终结果为0.6000000000000001。
3 额外说明
你给出的代码存在认知误区:你构造的N_1和N_2都是仅包含1个元素的列表,alg_sum遍历求和的逻辑并没有生效,你观察到的差异本质是列表元素初始化时的加法顺序差异,不是数组按升/降序遍历求和的差异。
如果要测试不同遍历顺序的求和差异,应该把代码调整为:
def alg_sum(x): s = 0. for x_i in x: s += x_i return s # 降序排列的数组 N_1 = [0.3, 0.2, 0.1] # 升序排列的数组 N_2 = [0.1, 0.2, 0.3] print("N_1:", alg_sum(N_1)) print("N_2:", alg_sum(N_2))
运行后你会得到和你示例完全一致的结果,这才是不同排序的数组求和的差异。
如果需要避免这类浮点求和误差,可以使用Python标准库的math.fsum方法,它会自动优化求和逻辑降低误差。
内容的提问来源于stack exchange,提问作者Adaptron
相关产品推荐
相关产品推荐

