gpt4 book ai didi

python - 比较 NumPy arange 和自定义范围函数以生成具有小数增量的范围

转载 作者:太空狗 更新时间:2023-10-29 20:36:59 26 4
gpt4 key购买 nike

这是一个允许步进小数增量的自定义函数:

def my_range(start, stop, step):
i = start
while i < stop:
yield i
i += step

它是这样工作的:

out = list(my_range(0, 1, 0.1))
print(out)

[0, 0.1, 0.2, 0.30000000000000004, 0.4, 0.5, 0.6, 0.7, 0.7999999999999999, 0.8999999999999999, 0.9999999999999999]

现在,这并不奇怪。发生这种情况是可以理解的,因为 float 不准确并且 0.1 在内存中没有准确的表示。因此,这些精度误差是可以理解的。

另一方面,以 numpy 为例:

import numpy as np

out = np.arange(0, 1, 0.1)
print(out)
array([ 0. , 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9])

有趣的是,这里没有引入明显的不精确度。我认为这可能与 __repr__ 显示的内容有关,所以为了确认,我尝试了这个:

x = list(my_range(0, 1.1, 0.1))[-1]
print(x.is_integer())

False

x = list(np.arange(0, 1.1, 0.1))[-1]
print(x.is_integer())

True

所以,我的函数返回了一个不正确的上限值(它应该是 1.0 但实际上是 1.0999999999999999),但是 np.arange 确实如此它正确。

我知道 Is floating point math broken?但这个问题的重点是:

numpy 是如何做到这一点的?

最佳答案

端点的不同是因为 NumPy 预先计算长度而不是临时计算长度,因为它需要预先分配数组。您可以在 _calc_length helper 中看到这一点。它不是在达到结束参数时停止,而是在达到预定长度时停止。

预先计算长度并不能使您免于非整数步骤的问题,而且无论如何您都会经常得到“错误”的端点,例如,numpy.arange(0.0, 2.1, 0.3):

In [46]: numpy.arange(0.0, 2.1, 0.3)
Out[46]: array([ 0. , 0.3, 0.6, 0.9, 1.2, 1.5, 1.8, 2.1])

使用 numpy.linspace 更安全,在这里您可以说出您想要多少个元素以及是否要包括正确的端点,而不是步长。


看起来 NumPy 在计算元素时没有出现舍入错误,但这只是显示逻辑不同所致。 NumPy 比 float.__repr__ 更积极地截断显示的精度。如果您使用 tolist 获取普通 Python 标量的普通列表(以及普通的 float 显示逻辑),您可以看到 NumPy 也遇到了舍入错误:

In [47]: numpy.arange(0, 1, 0.1).tolist()
Out[47]:
[0.0,
0.1,
0.2,
0.30000000000000004,
0.4,
0.5,
0.6000000000000001,
0.7000000000000001,
0.8,
0.9]

它的舍入误差略有不同 - 例如,在 .6 和 .7 中而不是 .8 和 .9 - 因为它还使用不同的方法计算元素,在 fill function 中实现对于相关的数据类型。

fill 函数实现的优点是它使用start + i*step 而不是重复添加步骤,这避免了每次添加时累积错误。然而,它的缺点是(我看不出有什么令人信服的理由)它从前两个元素重新计算步骤而不是将步骤作为参数,因此它可能会在前面的步骤中失去大量精度。

关于python - 比较 NumPy arange 和自定义范围函数以生成具有小数增量的范围,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45907088/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com