Каков наилучший метод для чтения двойного из двоичного файла, созданного в C? - PullRequest
5 голосов
/ 10 марта 2009

Программа на C выдает последовательные двойные числа в двоичный файл. Я хочу прочитать их в Python. Я пытался использовать struct.unpack('d',f.read(8))

EDIT: Я использовал следующее в C, чтобы написать случайное двойное число

r = drand48();
fwrite((void*)&r, sizeof(double), 1, data);

Ошибки теперь исправлены, но я не могу прочитать первое значение. для номера 0,000 .. он читается как 3.90798504668055, но с остальными все в порядке.

Ответы [ 5 ]

3 голосов
/ 11 марта 2009

Я думаю, что вы на самом деле правильно читаете номер, но вас сбивает с толку дисплей. Когда я читаю число из предоставленного вами файла, я получаю «3.907985046680551e-14» - это почти, но не совсем ноль (0,000000000000039 в развернутом виде). Я подозреваю, что ваш C-код просто печатает его с меньшей точностью, чем Python.

[Edit] Я только что попытался прочитать файл на C, и я получил тот же результат (хотя и с немного меньшей точностью: 3.90799e-14) (используя printf ("% g", val)), поэтому я думаю, если это значение неверно, оно происходит на стороне записи, а не на чтении.

1 голос
/ 11 марта 2009

Во-первых, вы пробовали рассол ? Никто еще не показал код Python ... Вот код для чтения в двоичном коде в Python:

import Numeric as N
import array
filename = "tmp.bin"
file = open(filename, mode='rb')
binvalues = array.array('f')
binvalues.read(file, num_lon * num_lat) 
data = N.array(binvalues, typecode=N.Float)   

file.close()

Где f здесь указывает числа с одинарной точностью, 4 байта с плавающей точкой. Найдите любой размер ваших данных для каждой записи и используйте его.

Для недвоичных данных вы можете сделать что-то простое, как это:

   tmp=[]
   for line in open("data.dat"):
                tmp.append(float(line))
1 голос
/ 10 марта 2009

Не могли бы вы уточнить, "не работал"? Команда вылетела? Данные вышли не так? Что на самом деле произошло?

В случае сбоя команды:

  • Пожалуйста, поделитесь выводом ошибки команды

Если данные просто неверны:

  • Имеют ли системы, которые создают и считывают данные, одинаковые порядковые номера? Если один из них имеет порядок с прямым порядком байтов, а другой - с прямым порядком байтов, то вам нужно указать преобразование с порядком байтов в строке формата.

  • Если порядковые номера двух компьютеров одинаковы, как данные, записанные в файл, точно ? Вы знаете? Если да, то какое значение было записано в файл и какое неверное значение вы получили?

0 голосов
/ 11 марта 2009

Метод best будет использовать текстовый файл ASCII:

0,0
3,1416
3.90798504668055

в том смысле, что он будет переносимым и будет работать с любой реализацией с плавающей запятой до определенной степени.

Чтение необработанных двоичных данных из адреса памяти double вообще не переносимо и обязательно приведет к сбою в какой-то другой реализации.

Конечно, вы можете использовать двоичный формат для компактности, но переносимая функция C, пишущая в этом формате, совсем не будет выглядеть как ваш фрагмент.

По крайней мере, код должен быть окружен серией ifs / ifdefs, проверяющих, что представление памяти double s, используемое текущей машиной, точно совпадает с ожидаемым интерпретатором Python.

Написание такого кода было бы затруднительно, поэтому я предлагаю простое, чистое, переносимое и удобочитаемое решение текста ASCII.

Это будет мое определение "лучшего".

0 голосов
/ 10 марта 2009
  • f.read(8) может вернуть менее 8 байт
  • Данные могут иметь различное выравнивание и / или порядковый номер:

    >>> for c in '@=<>':
    ...     print repr(struct.pack(c+'d', -1.05))
    ...
    '\xcd\xcc\xcc\xcc\xcc\xcc\xf0\xbf'
    '\xcd\xcc\xcc\xcc\xcc\xcc\xf0\xbf'
    '\xcd\xcc\xcc\xcc\xcc\xcc\xf0\xbf'
    '\xbf\xf0\xcc\xcc\xcc\xcc\xcc\xcd'
    >>> struct.unpack('<d', '\xbf\xf0\xcc\xcc\xcc\xcc\xcc\xcd')
    (-6.0659880001157799e+066,)
    >>> struct.unpack('>d', '\xbf\xf0\xcc\xcc\xcc\xcc\xcc\xcd')
    (-1.05,)
    
...