2016-08-09 2 views
2

У меня есть массив 10-байтных (80-битных) значений малых чисел Endian (или float80). Как я могу прочитать эти значения в python 3?Python: чтение значений float80

Пакет struct не поддерживает float80 (возможно, я читал документы небрежно).

Пакет array такой же, как упаковка "struct" не поддерживает float80.

Пакет numpy поддерживает float128 или float96. Это очень хорошо, но добавьте \x00 в хвост float80, чтобы увеличить его до float96 или float128. Ужасно, импорт этого пакета занимает много времени.

Пакет ctypes поддерживает c_longdouble. Это много раз быстрее, чем numpy, но sizeof(c_longdouble) зависит от машины и может быть меньше 80 бит, добавив \x00 в хвост float80, чтобы продлить его до c_longdouble тоже уродливо.

ОБНОВЛЕНИЕ 1: тестовый код на моем gist.github. Функция decode_str64 уродливая, но она работает. Теперь я ищу правильно

+0

Возможно, вы должны изменить формат производителя либо для создания 'float64', либо' float96'/'float128' ... – Bakuriu

+0

@Bakuriu, я бы сделал это, если бы мог :( – kai3341

+2

возможно загрузка как struct" < HQ "и обработки в соответствии с [x86_Extended_Precision_Format] (https://en.wikipedia.org/wiki/Extended_precision#x86_Extended_Precision_Format), возможно, используя [десятичное] (https://docs.python.org/3/library/decimal.html) чтобы не потерять точность – janbrohl

ответ

2

Позвольте мне переписать мой ответ в более логичной:

ctypes c_longdouble машинным зависит, потому что longdouble типа поплавок не установлен в камне стандарта C и зависит на компилятор :(но он по-прежнему ваш лучший вы можете иметь прямо сейчас для высокоточных поплавков ...

Если вы планируете использовать numpy, numpy.longdouble - это то, что вы ищете, numpy.float96 или numpy.float128 являются но не указывают на формат с плавающей запятой в формате 96 или 128 бит IEEE. Вместо этого они указывают количество бит выравнивания, используемое базовым длинным двойным типом. Так что, например, на x86-32, uble составляет 80 бит, но получает до 96 бит для поддержки 32-битного выравнивания, а numpy вызывает это float96. На x86-64 long double снова является идентичным 80-битным типом, но теперь он заполняется до 128 бит для поддержки 64-битного выравнивания, а numpy вызывает это float128. Нет лишней точности, просто дополнительное дополнение.

прилагая \x00 в конце float80 сделать Float96 некрасиво, но в конце концов, это просто, что, как float96 просто проложенный float80 и numpy.longdouble является float96 или float128 в зависимости от архитектуры машины вы используете ,

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 зависит от аппаратных средств и от среды разработки: в частности, x86 машины обеспечивает аппаратное обеспечение с плавающей точкой с 80-битная точность и , в то время как большинство компиляторов C предоставляют это как их тип long double, MSVC (стандарт для Windows-сборок) составляет long double идентичный t o double (64 бит).Numpy делает длинный двойной файл компилятора доступным как np.longdouble (и np.clongdouble для комплексных чисел). Вы можете узнать, что предлагает numpy np.finfo(np.longdouble).

Я проверил, что np.longdouble на складе numpy-1.11.1-win32.whl на PyPI float64, а также в Gohlke's build и float96 в numpy-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) байтов, добавляется - by recommendatation from Intel no less - во избежание повышения производительности, связанного с обработкой некорректированных данных на процессорах x86. Чтобы дать вам представление о величине Хитом в, some figures from Microsoft show ~2 times difference for DWORDs.

This layout is ingrained into the underlying C's long double а не изобретение numpy «s, так 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.

Смежные вопросы