NumPy:使用 dtype float64 将 int64 值存储在 np.array 中,然后将其转换回整数是否安全



我想知道我是否引起了问题,因为我在 Python2.7 中错误地将数据类型分配给和转换 numpy-array。

我正在做的是从 numpy.float64 类型将 hdf5 64 位整数值读取到 numpy.zeros() 数组!然后将这些值写入另一个分配 64 位无符号整数的 hdf5!

一些原始值的两个示例,这些值实际上是 ID 号(因此它们不会因数据类型转换而更改至关重要):

12028545243
12004994169

问题 1:第二个 hdf5 文件中的无符号整数是否与原始文件中相同?

我用一个小的子样本检查了这一点,但我无法控制是否适用于所有子样本(有数百万个)!

问题 2:如果我将 64 位值从原始文件读取到 数据类型=float64 的 numpy 数组,然后执行以下操作:

value=int(value)
value.astype(int64)

这是完全是原始值还是由于转换而改变?

问题 3:Python 会把我假设的值解释为 (a)、(b)、(c) 和 (d) 吗?格式化值也会有问题,比如使用科学记数法"e+10"?还是 Python 将它们识别为相同的值(因为它只是显示它们的不同方式......

1.20285452e+10 == 12028545243.0 == 12028545243 == 12028545243
1.20049942e+10 == 12004994169.0 == 12004994169 == 12004994169
(a)             (b)              (c)            (d)   

(a) 列出值打印一列名为 Data 的数组:

print data[:,0] <type 'numpy.ndarray'>

(b) 打印数据中的单个元素

print data[0,0] <type 'numpy.float64'>

(c) 进行转换后

print int(data[0,0]) <type int>

(d) 与 (a) 相同,但使用 astype() 进行转换!

print data[:,0].astype(numpy.int64) <type 'numpy.ndarray'>

您可能会问为什么为了安全起见,我不为 numpy 数组分配 int64 类型?是的,我会这样做,但是有些数据已经错误地存储了,我需要知道我是否仍然可以信任这些数据......

我正在使用: Python2.7, Pythonbrew, Ubuntu 14.04 LTS 64-bit on Lenovo T410

通常,不会保存将 64 位整数存储在 64 位浮点数中。例如,您可以通过查看以下内容轻松看到这一点:

import numpy as np
print(np.int64(2**63-1))
print(np.int64(np.float64(2**63-1))

虽然第一个会给你正确的结果 (9223372036854775807),但第二个有一个舍入误差,导致整数溢出 (-9223372036854775808)。

要理解这一点,您必须查看这些数字是如何存储的。虽然整数基本上只将其绝对值存储在二进制中(加上一个用于数字符号的位),但这不适用于浮点数。

浮点数将数字分为三部分存储。一个是符号位,下一个是有效/尾数,最后一个是指数。然后将该数字作为符号时间尾数乘以 2^指数给出。这三个必须共享可用的位(在您的案例中为 64)。正如 numpy 文档中为 anp.float64指定的那样,52 位用于有效,11 位用于指数。因此,仅对于最多 52 位的整数,如果将它们转换为np.float64并返回,您最终会得到正确的结果。

因此,要回答您的第一个和第二个问题:不,如果您的数据集中有任何大于2**52-1的数字,则无法确定数字是否相同。

关于您的第三个问题:仅在打印值时进行格式化。在内部比较数字时,数字没有任何格式,因此只要所有这些值具有完全相同的值,它们就会被视为相等。

顺便说一句,如果你想了解更多关于浮点算术的知识,一个非常好的阅读是大卫戈德堡的论文"每个计算机科学家都应该知道的关于浮点算术"。

这取决于 Numpy 是将您的 int64 值转换为 float64,然后再转换回整数,还是仅将 int 数据存储在为 float64 保留的内存中。我假设第一个选项是正确的。 即使不检查 float64 interna(女巫无论如何都应该做)。很明显,float64 不能对所有2**64不同的整数都有唯一的表示,如果它本身只有2**64不同的代码并且还需要一些用于0.1等等。Float64 使用 52 位来存储一个 53 位长的规范化尾数(最高有效位是隐式 1),所以如果你的 int 有非零位,那么它们在第一个之后多 52 位,就像:

5764607523034234887
= 0x5000000000000007
= 0b0101000000000000000000000000000000000000000000000000000000000111

(女巫是一个完美的64位整数)

最后,0b111部分在转换为双倍后会被四舍五入并丢失,以便将数字放入尾数。然后,此信息将永远丢失。您的某些 ID 可能会发生这种情况,因为它们通常是相当大的数字。 因此,请尝试将数组调整为 int64。

相关内容

最新更新