Python:读取float80值

时间:2016-08-09 11:28:24

标签: python floating-point long-double

我有一个10字节(80位)Little Endian浮点值(或struct)的数组。我怎样才能在python 3中读取这个值?

float80不支持array(可能是我不小心阅读了文档)。

float80与包" struct"相同不支持numpy

float128支持float96\x00类型。它非常好,但将float80添加到float96的尾部以将其扩展为float128ctypes是丑陋的,导入此软件包需要花费很多时间。

c_longdouble支持sizeof(c_longdouble)。它比numpy快很多倍,但\x00与机器有关,可能小于80位,在float80的尾部附加c_longdouble以将其扩展为{{ 1}}也很难看。

更新1 :在gist.github处测试代码。 函数decode_str64很难看,但它有效。现在我正在寻找正确的方式

3 个答案:

答案 0 :(得分:2)

让我以更合乎逻辑的方式重写我的答案:

ctypes c_longdouble是机器相关的,因为longdouble浮点类型不是由C标准设置的,并且取决于编译器:(但它仍然是你现在可以拥有的高精度浮点数的最佳选择..

如果您计划使用numpy,numpy.longdouble是您正在寻找的,numpy.float96或numpy.float128是极具误导性的名称。它们不表示96位或128位IEEE浮点格式。相反,它们表示底层long double类型使用的对齐位数。所以例如在x86-32上,long double是80位,但是最多填充96位以保持32位对齐,numpy调用此float96。在x86-64上,long double也是相同的80位类型,但现在它被填充到128位以保持64位对齐,并且numpy调用此float128。没有额外的精度,只是额外的填充。

\x00末尾添加float80以使Float96变得丑陋,但最后只是因为float96只是填充float80 1}}和numpy.longdoublefloat96float128,具体取决于您使用的机器的体系结构。

What is the internal precision of numpy.float128?

答案 1 :(得分:0)

numpy can use 80-bit float if the compiler and platform support them

  

numpy中是否可以[支持更高精度]取决于   硬件和开发环境:特别是x86   机器提供80位精度的硬件浮点数   而大多数C编译器都将其作为long double类型,MSVC   (Windows版本的标准)使long double与double相同   (64位)。 Numpy使编译器的long double可用   np.longdouble(和复数的np.clongdouble)。您可以   找出你的numpy为np.finfo(np.longdouble)提供的内容。

我在PyPI以及np.longdouble中的float64numpy-1.11.1-win32.whl中检查了float96 numpy-1.4.1-9.el6.i686库存post是否为pre

答案 2 :(得分:0)

在4(x32)或16(x64)字节边界上添加填充或更确切地说,扩展精度浮点的内存对齐 - by recommendatation from Intel no less - 以避免与处理非对齐相关的性能损失x86 CPU上的数据。为了让您了解命中数量some figures from Microsoft show ~2 times difference for DWORDs.

This layout is ingrained into the underlying C's long double而不是numpy的发明,因此numpy并未尝试提供任何方法来提取/插入&#34 ;显著"一部分。

因此,如果你有没有填充的原始数据,手动添加填充看起来就像是要走的路。您可以通过直接写入底层缓冲区来加快进程:

fi=np.finfo(np.longdouble)
assert fi.nmant==63 and fi.nexp==15, "80-bit float support is required"
del fi

len_float80=10    #no way to extract this from dtype/finfo
len_padded=np.dtype(np.longdouble).itemsize

f=open('float80.bin','rb')
f_items=os.stat(f.name).st_size//len_float80

n = np.empty(f_items,dtype=np.longdouble)

for i in xrange(f_items):
    raw=f.read(len_float80)
    n.data[i*len_padded:i*len_padded+len_float80]=raw

del f,i,raw,f_items

甚至可以通过porting the code to Cython获得更多的加速(if using raw buffers, the speedup compared to regular array indexing can be as much as 100x!这会损害代码的可维护性,但请注意这里的过早优化。)

或者,对于"交换"格式,您可以考虑使用未绑定到内部表示的格式,例如savetxt