np.arange(0, 1, 0.1) 使用默认数据类型 float64 初始化浮点数组。但是,当我使用 <= 将其与 np.float64(0.6) 进行比较时,第 7 个元素 (0.6) 返回 False。更奇怪的是,如果我用float32来初始化和比较,结果就变得正好了。对此有何解释?
如果你这样做,答案就很明显了:
import numpy as np
a = np.arange(0, 1, 0.1)
print('\n'.join(map(str, zip(a, a >= np.float64(0.6)))))
Run Code Online (Sandbox Code Playgroud)
结果:
(0.0, False)
(0.1, False)
(0.2, False)
(0.30000000000000004, False)
(0.4, False)
(0.5, False)
(0.6000000000000001, True)
(0.7000000000000001, True)
(0.8, True)
(0.9, True)
Run Code Online (Sandbox Code Playgroud)
这只是一个经典案例:浮点数学是否被破坏了?
您问为什么这对 来说不是问题float32。例如:
import numpy as np
a = np.arange(0, 1, 0.1, dtype=np.float32)
print('\n'.join(map(str, zip(a, a < np.float32(0.6)))))
Run Code Online (Sandbox Code Playgroud)
结果:
(0.0, True)
(0.1, True)
(0.2, True)
(0.3, True)
(0.4, True)
(0.5, True)
(0.6, False)
(0.7, False)
(0.8, False)
(0.90000004, False)
Run Code Online (Sandbox Code Playgroud)
线索在于最后一个值的长度。注意比和0.90000004短很多。这是因为 32 位的可用精度低于 64 位的精度。0.300000000000000040.6000000000000001
事实上,当您需要精度时,这就是使用 64 位浮点数而不是 32 位浮点数的全部原因。根据您的系统架构,64 位可能会慢一些,并且肯定会占用两倍的空间,但精度更好。具体如何取决于浮点数的实现(有许多选择技术性和细节性太强,无法在此处讨论) - 但可用于存储有关数字的信息的位数是两倍,因此您可以看到这如何允许精度的提高。
碰巧的是,在 32 位中,该格式的表示形式为 0.6,它有足够的零来表示 0.6(而不是 0.60000000)。在 64 位中,表示 0.6 的最佳值有更多的零,但最后出现一个非零,表明该格式的表示不准确。
float32比本例“更精确”似乎违反直觉float64,但这只是一个挑选问题。如果您查看大量随机选择的数字,您会发现float64平均起来更加接近。碰巧,偶然float32 看起来更准确。
这里的关键要点是浮点数是实数的近似值。它们对于大多数日常操作来说足够准确,并且如果格式设计良好,对于许多用例来说,随着时间的推移,错误往往会趋于平均。但是,由于大多数情况下都会存在一些误差(当然有些数字只是碰巧得到了准确的表示,浮点类型中的每个点仍然落在实数线上),因此在打印浮点数时,通常需要进行一些舍入因此。
我最喜欢的例子表明,不精确性在 Python(或任何真正具有浮点的语言)中很早就出现了:
>>> .1 + .1 + .1 == .3
False
>>> print(.1 + .1 + .1, f'{.1 + .1 + .1:.1f}')
0.30000000000000004 0.3
Run Code Online (Sandbox Code Playgroud)
如果您需要更高的精度,您可以查看诸如decimal. 此外,在非常特殊的情况下,可能会提供比 64 位更多的位,但这可能会导致支持方面出现意外,我不会推荐它。