我在 Mac 和 Linux 上使用相同版本的 numpy 时遇到了不同的溢出行为。 MWE:
import numpy as np
arr = np.arange(0, 2 * 4e9, 1e9, dtype=float)
print(arr.astype(np.uint32))
print(np.__version__)
Mac(Python 3.9.13):
array([ 0, 1000000000, 2000000000, 3000000000, 4000000000,
705032704, 1705032704, 2705032704], dtype=uint32)
'1.22.4'
Linux(Python 3.9.7):
array([ 0, 1000000000, 2000000000, 3000000000, 4000000000,
0, 0, 0], dtype=uint32)
'1.22.4'
我更喜欢预期翻转的“Mac”行为(而不是将溢出值强制为 0),因此我想知道如何针对 Linux 版本修复此问题。
我相信这是由于 numpy 的底层
C
实现造成的,这可能会触发未定义的行为,而用于 numpy 的 linux 和 mac 发行版的编译器对此的处理方式有所不同。
查看处理类似主题的 cast float to unsigned int in C with gcc,我们还可以看到指向第 51 页所述的 C 标准的链接
6.3.1.4 实数浮点数和整数
1 当实浮点类型的有限值转换为_Bool以外的整数类型时,小数部分将被丢弃(即该值被截断为零)。如果整数部分的值不能用整数类型表示,则行为未定义。61)
一种可能性是我猜你尝试不同的编译器来编译你自己的 numpy 版本并检查行为。或者,由于您想要翻转行为,您可以尝试首先转换为较大宽度的无符号整数类型,然后转换为较小宽度,因为无符号整数转换总是进行翻转
6.3.1.3 有符号和无符号整数
1 当整数类型的值转换为_Bool以外的其他整数类型时,如果 该值可以用新类型表示,它没有改变。
2 否则,如果新类型是无符号的,则通过重复添加或来转换该值 比新类型可以表示的最大值减一 直到该值在新类型的范围内。60)
import numpy as np
arr = np.arange(0, 2 * 4e9, 1e9, dtype=float)
print(arr.astype(np.uint64).astype(np.uint32))
print(np.__version__)