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

时间:2017-03-07 14:46:06

标签: python-2.7 numpy type-conversion

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

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

一些原始值的示例,它们实际上是ID号(因此,由于数据类型转换,它们不会发生变化至关重要):

12028545243
12004994169

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

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

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

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-array分配int64类型是安全的?是的我会这样做,但是有些数据已经存在错误,我需要知道我是否仍然可以信任这些数据......

我正在使用:联想T410上的Python2.7,Pythonbrew,Ubuntu 14.04 LTS 64位

2 个答案:

答案 0 :(得分:0)

通常,不保存在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's documentation中针对np.float64所指定的那样,52位用于有效位,11位用于指数。因此,仅对于最多52位的整数,如果将它们转换为np.float64并返回,则最终会得到正确的结果。

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

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

顺便说一下,如果你想了解更多关于浮点运算的知识,那么David Goldberg撰写的论文"What every computer scientist should know about floating-point arithmetic"就是一个非常好的读物。

答案 1 :(得分:0)

这取决于Numpy是将int64值转换为float64然后再转换为int还是仅将int-data存储在为float64保留的内存中。我假设第一个选项是真的。 即使没有检查float64 interna(女巫无论如何都应该做)。很明显,如果float64只有2**64个不同的代码并且2**64需要一些0.1,那么它就不具有所有 5764607523034234887 = 0x5000000000000007 = 0b0101000000000000000000000000000000000000000000000000000000000111 个不同整数的唯一表示形式也是。 Float64使用52位来存储53位长的归一化尾数(最高有效位是隐式1)所以如果你的int有非零位,那么它们在第一个之后的52位比如:

0b111

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

最后的{{1}}部分会在将其转换为双精度后变得圆滑并丢失,以便将数字拟合到尾数中。这些信息将永远丢失。这可能会发生在您的一些ID上,因为它们通常都是相当大的数字。 因此,请尝试将数组调整为int64。