2016-08-09 84 views
2

我有一個10字節(80位)Little Endian浮點值(或float80)的數組。我如何在python 3中讀取這個值?Python:讀取float80值

struct不支持float80(可能是我不小心閱讀了文檔)。

與包「struct」相同的包array不支持float80

numpy支持float128float96類型。這是非常好的,但在float80的尾部追加\x00以將其擴展爲float96float128是醜陋的,導入此軟件包需要很長時間。

包​​支持c_longdouble。它比numpy快很多倍,但是sizeof(c_longdouble)是機器相關的,可以少於80位,在float80的尾部追加\x00以將其擴展爲c_longdouble也很難看。

UPDATE 1:測試代碼在我的gist.github。 功能decode_str64是醜陋的,但它的工作原理。現在我正在尋找正確的方式

+0

你應該改變生產者的格式來產生'float64'或'float96' /'float128' ... – Bakuriu

+0

@Bakuriu,如果我可以的話我會這樣做的:( – kai3341

+2

可能加載爲struct「 HQ「,並可能使用[decimal](https://docs.python.org/3/library/decimal.html)處理[x86_Extended_Precision_Format](https://en.wikipedia.org/wiki/Extended_precision#x86_Extended_Precision_Format)不要丟失精度 – janbrohl

回答

2

讓我重寫我的答案更合乎邏輯的方式:

ctypes c_longdouble是依賴於機器,因爲longdouble float類型並不是一成不變C標準設置,並取決於編譯器:(但它仍然是你最好的,你現在可以擁有高精度浮標...

如果你打算使用numpy,numpy.longdouble是你正在尋找的東西,numpy.float96或numpy.float128是高度誤導性的名稱,它們不表示96位或128位IEEE浮點格式,而是表示底層long double類型使用的對齊位數,例如在x86-32上,long uble是80位,但被填充到96位以保持32位對齊,並且numpy調用這個float96。在x86-64上,long double再次是相同的80位類型,但現在它被填充到128位以保持64位對齊,並且numpy調用float128。沒有額外的精度,只是額外的填充。

float80年底追加\x00做出Float96是醜陋的,但最終它只是作爲float96只是一個軟墊float80numpy.longdoublefloat96float128根據您使用的計算機的體系結構。

What is the internal precision of numpy.float128?

+0

問題在於,在某些操作系統(特別是Windows)中,'np.longdouble'只是'np.float64',因此使用'np.longdouble'不能提供跨平臺的解決方案。 –

+0

@Mark Dickinson,和'ctypes.c_longdouble'一樣:在Windows上我讀了一個垃圾(可能是因爲'ctypes.sizeof(ctypes。c_longdouble)'少於10,這個檢查我在Windows上測試後添加了很長時間)。但對我來說現在並不是關鍵問題 – kai3341

0

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

無論[支持更高的精度]能夠在numpy的取決於 硬件和對開發環境:具體而言,86 機器提供硬件浮點與80位精度和 ,而大多數C編譯器提供此類型爲long double類型,MSVC (Windows版本的標準)使得long double與t o雙重 (64位)。Numpy使編譯器的long double可用,如 np.longdouble(對於複數,則爲np.clongdouble)。你可以 找出你的numpy提供的np.finfo(np.longdouble)

我檢查np.longdouble是在庫存的PyPI numpy-1.11.1-win32.whlfloat64以及在Gohlke's buildfloat96numpy-1.4.1-9.el6.i686於CentOS 6.

+0

是的,'numpy'提供'float64','float96','float128'數據類型。 – kai3341

+0

所以這很好,可以通過在尾部字節數組中追加\ x00來讀取數據。首先,我使用'numpy'完成了這項任務。由於長時間導入'numpy',我將'numpy'改爲'ctypes'。沒有什麼區別:我在字節數組尾部追加\ x00。 – kai3341

0

的填充,或者更確切地說,的擴展精度存儲器對準漂浮在4 (x32)或16(x64)字節邊界,以避免與處理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不會嘗試提供任何辦法解決它來提取/插入只有‘顯著’的一部分。

因此,如果您有沒有填充的原始數據,手動添加填充看起來就像要走的路。您可以通過直接寫入底層緩衝區加快這一進程:

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