numpy.arange生成数组时第7行元素超出预期的原因解析
np.arange生成数组超出预期范围的原因分析
问题重现
执行以下代码:
import numpy as np for i in range(9): x = np.arange(i+0.8, i+1.3, 0.1) print(i, x)
得到输出:
0 [0.8 0.9 1. 1.1 1.2] 1 [1.8 1.9 2. 2.1 2.2] 2 [2.8 2.9 3. 3.1 3.2] 3 [3.8 3.9 4. 4.1 4.2] 4 [4.8 4.9 5. 5.1 5.2] 5 [5.8 5.9 6. 6.1 6.2] 6 [6.8 6.9 7. 7.1 7.2] 7 [7.8 7.9 8. 8.1 8.2 8.3] 8 [8.8 8.9 9. 9.1 9.2]
其中i=7时生成的数组包含了8.3,而按预期np.arange应该不包含终止值i+1.3=8.3。
原因解析
浮点数精度误差是核心问题
np.arange的工作逻辑是:从起始值开始,不断累加步长,直到下一个值严格大于终止值时停止。但十进制的0.1无法用二进制浮点数精确表示,实际存储的是一个略大于0.1的近似值,多次累加后会产生误差累积。为什么刚好在i=7时出现
当i=7时,起始值为7.8,终止值为8.3:
- 理论上最后一个元素应该是8.2,因为8.2+0.1=8.3等于终止值,不应被包含。
- 但由于浮点数误差,前面累加得到的8.2实际存储为
8.199999999999999,加上步长0.1的近似值后,结果是8.299999999999998——这个值略小于8.3的实际存储值(8.300000000000001),所以np.arange会把这个值当作合法元素加入数组,最终打印时显示为8.3。
其他循环中,误差累积的方向或幅度没触发这个边界条件,所以没有出现多元素的情况。
解决方案
- 使用
np.linspace替代:可以直接指定生成元素的数量,避免浮点数步长的误差问题,例如np.linspace(i+0.8, i+1.2, 5)(对应预期的5个元素)。 - 给终止值减去极小epsilon:比如
np.arange(i+0.8, i+1.3 - 1e-10, 0.1),确保累加后的结果不会误判为小于终止值。
内容的提问来源于stack exchange,提问作者Dmitriy Tsoy
相关产品推荐
相关产品推荐

