эффективное хранение на диске десятичных чисел в C (C89) - PullRequest
1 голос
/ 30 сентября 2011

Я пишу функции, которые сериализуют / десериализуют большую структуру данных для последующей эффективной перезагрузки.Существует определенный набор десятичных чисел, для которых точность невелика, и я хотел бы хранить их в 4 байтах двоичных данных.

Для большинства, чтение байтов в буфер и использование memcpy длядостаточно поместить их в поплавок, и это наиболее распространенное решение, которое я нашел.Однако это не переносимо, поскольку плавающие в системах, для которых предназначено это программное обеспечение, не гарантируют, что их размер будет 4 байта.м ограничен C89).Я не привязан к 4-х байтной памяти, но для меня это привлекательный вариант.Я полностью против хранения чисел в виде строк.Я знаком с проблемами с порядком байтов, и такие вещи уже приняты во внимание.

Поэтому я ищу системно-независимый способ хранения и извлечения чисел с плавающей точкой в ​​небольшом количестве двоичных файлов.данные (предпочтительно около 4 байтов).Я, по своей глупости, предположил, что это будет самая легкая часть этой задачи, поскольку это кажется такой распространенной проблемой, но популярные поисковые системы и различные справочники не оказали никакой материальной помощи.

Ответы [ 2 ]

2 голосов
/ 30 сентября 2011

Вы можете хранить их в 32-битном формате IEEE с плавающей запятой (или в очень близком к нему приближении, например, вы можете ограничить использование денорм и NaN). Затем настройте каждую платформу для приведения ее собственного типа float к этому формату и обратно.

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

Должна быть возможность написать переносимый код для поиска ближайшего значения IEEE к собственному значению float и наоборот, если это необходимо. Однако вы не захотите его использовать, потому что он, вероятно, будет гораздо менее эффективным, чем код, который использует знание формата float. В общем случае, когда платформа использует представление IEEE, это неоперативное или простое сужающее / расширяющее преобразование. Даже в самом худшем случае, с которым вы, вероятно, столкнетесь, поскольку это двоичная дробь, вам просто нужно извлечь знак, показатель степени и значение и биты и делать с ними правильные действия (отбрасывать биты из значения и, если он слишком большой, отрегулируйте смещение и, возможно, ширину экспоненты, сделайте правильные вещи с недостаточным и избыточным).

Если вы хотите избежать потери точности в случае, когда файл сохраняется и затем перезагружается в той же системе (но эта система не использует 32-битный IEEE), вы можете посмотреть на сохранение некоторых данных, указывающих формат в файле (размер каждого значения, количество битов значимых и экспонент), затем сохраните каждое значение с собственной точностью, чтобы оно округлялось только в том случае, если оно загружено в менее точную систему. Я не знаю, есть ли в ASN.1 стандарт для кодирования значений с плавающей запятой по этим линиям, но я бы ожидал от него такой сложной хитрости.

0 голосов
/ 30 сентября 2011

Проверьте это: http://steve.hollasch.net/cgindex/coding/portfloat.html

Они дают процедуру, которая является переносимой и не добавляет слишком много накладных расходов.

...