np.array([0.1, 0.2]).sum() ≠ 0.3 是因 ieee 754 双精度无法精确表示十进制小数 0.1(实际存为约 0.10000000000000000555),累加后误差累积导致结果为 0.30000000000000004。

为什么 np.array([0.1, 0.2]).sum() 不等于 0.3
这不是 NumPy 的 bug,而是 IEEE 754 双精度浮点数在二进制下无法精确表示十进制小数(比如 0.1 实际存储为约 0.10000000000000000555)导致的固有误差。NumPy 所有运算都基于底层 C/Fortran 实现,误差会累积——尤其在累加、比较、索引等场景下暴露明显。
常见现象包括:np.where(arr == 0.3) 返回空数组;np.isclose(a, b) 返回 False 即使肉眼看起来相等;用浮点数做数组索引时报 IndexError。
用 np.isclose() 替代 == 进行安全比较
直接用 == 比较浮点数组几乎总是错的。必须改用容差比较函数。
-
np.isclose(a, b, rtol=1e-05, atol=1e-08)是首选:它同时检查相对误差(rtol * abs(b))和绝对误差(atol),对大小值都鲁棒 - 对布尔掩码操作,直接写
arr[np.isclose(arr, 0.3)],别用arr[arr == 0.3] - 若需严格相等语义(如哈希、字典键),先用
np.round(arr, decimals=10)固定小数位再比较,但注意round()不改变底层精度,仅作截断
避免用浮点数做索引或字典键
像 my_dict[0.1 + 0.2] 或 arr[int(0.1 * 10)] 这类操作极易因误差导致键不存在或越界。
- 索引优先用整数:把
0.1 * i转成i // 10或预生成整数索引数组 - 字典键若必须是“逻辑浮点值”,统一转成字符串或四舍五入到固定精度:
str(round(x, 10))或np.round(x, 10).item() - 用
np.searchsorted()替代手动查找浮点目标值,它内部处理了排序与容差逻辑
控制累积误差:选对数据类型和算法
累加、矩阵乘、FFT 等操作中误差会随规模放大。不能只靠后期修,得从源头控。
- 对高精度需求,显式指定
dtype=np.float64(默认已是),但避免混用float32—— 它的atol默认容差比float64大 1000 倍 - 大数组求和优先用
np.sum(arr, dtype=np.float64)显式指定累加精度,防止中间结果降级 - 需要极致精度时,考虑
decimal模块或mpmath,但它们不兼容 NumPy 向量化,只能用于关键标量计算
最常被忽略的是:误差本身不可消除,只能管理。关键不是“修复”某个值,而是让整个计算链路对误差不敏感——从比较方式、索引策略到数据流设计,都要默认接受浮点数没有“精确相等”这回事。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











