Чтение 16-байтового Фортрана плавает в Python из файла - PullRequest
0 голосов
/ 29 сентября 2018

Я пишу последовательности с плавающей запятой из Фортрана в двоичные файлы и хочу прочитать их на Python.Все работает нормально с плавающей запятой одинарной и двойной точности (kind = 4) и (kind = 8), но когда я пытаюсь перейти к типу переменной real (kind = 16), вдруг вещи перестают работать (массив данных, заполненный нулями),Я читаю здесь: Python читает двоичный файл длиной 16 байт в два раза Что для обхода функции np.fromfile необходимо.Я внес предложенное изменение, но все еще не получил правильный результат.Код Mwe Python и Fortran приведен ниже.Я попробовал это как с Python 2.7 + Numpy 1.8 и Python 3.4 + Numpy 1.14 с одинаковым эффектом.Я также проверил, и сгенерированный файл, кажется, имеет правильный объем данных (480 байт на 30 операций с 16 байтами).Любая помощь будет приветствоваться!

Читатель Python:

import numpy as np

inputfilename = "fortranData.bin"

dp = 8
nVals = 30

with open(inputfilename, 'rb') as f:
    # both work fine for 4 or 8 byte floats (32 and 64)
    # but not for 16 byte floats (np.float128)
    data = np.fromfile(f, dtype=np.float64)
    data = np.frombuffer(f.read(dp*nVals), dtype=np.float64, count=nVals)

print(data)

Writer Fortran (скомпилировано с gfortran 4.8.6 в Ubuntu 14.04)

program test

implicit none

integer, parameter :: dp=8
integer, parameter :: outFileUnit=51, nPts=10, nDim=3
character(len=100) :: binaryFile="fortranData.bin"
real(kind=dp), dimension(nPts,nDim) :: data
integer :: i, j

! - generate data -
do i=1, nPts
    do j=1, nDim
        data(i,j) = (i-1)*nDim + j
    enddo
enddo

! - open file and write data -
open(unit=outFileUnit, file=binaryFile, form='unformatted', access='direct', &
    status='replace', recl=nDim*sizeof(data(1,1)))

do i=1, nPts
    write(outFileUnit, rec=i) data(i,:)
enddo

end program test

РЕДАКТИРОВАТЬ: по запросуВот несколько строк данных в верхней части файла fortranData.bin:

$od fortranData.bin 
0000000 000000 000000 000000 000000 000000 000000 000000 037777
0000020 000000 000000 000000 000000 000000 000000 000000 040000
0000040 000000 000000 000000 000000 000000 000000 100000 040000
0000060 000000 000000 000000 000000 000000 000000 000000 040001
0000100 000000 000000 000000 000000 000000 000000 040000 040001
0000120 000000 000000 000000 000000 000000 000000 100000 040001

1 Ответ

0 голосов
/ 29 сентября 2018

Кажется, что numpy не поддерживает формат IEEE Quad, насколько я знаю, его просто нужно конвертировать вручную.Например, если вы читаете файл кусками по 16 байт, то его можно преобразовать следующим образом (хотя и плохо протестировано)

def rawQuadToDouble(raw):
    asint = int.from_bytes(raw, byteorder='little')
    sign = (-1.0) ** (asint >> 127);
    exponent = ((asint >> 112) & 0x7FFF) - 16383;
    significand = (asint & ((1 << 112) - 1)) | (1 << 112)
    return sign * significand * 2.0 ** (exponent - 112)
...