Точное текстовое представление IEEE "двойник"

Мне нужно представить двойное (64-битное) число с плавающей запятой IEEE 754-1985 в удобочитаемой текстовой форме с условием, что текстовая форма может быть проанализирована обратно в одно и то же (побитовое) число.

Возможно ли это / практично обойтись без простой печати необработанных байтов? Если да, то код для этого будет высоко ценится.

4 ответа

Решение

Лучший вариант: используйте шестнадцатеричный формат с плавающей запятой C99:

printf("%a", someDouble);

Созданные таким образом строки могут быть преобразованы обратно в double с С99 strtod( ) функция, а также с scanf( ) функции. Несколько других языков также поддерживают этот формат. Некоторые примеры:

decimal number    %a format     meaning
--------------------------------------------
2.0               0x1.0p1       1.0 * 2^1
0.75              0x1.8p-1      1.5 * 2^-1

Шестнадцатеричный формат имеет то преимущество, что все представления являются точными. Таким образом, преобразование строки обратно в число с плавающей запятой всегда даст исходное число, даже если кто-то изменит режим округления, в котором выполняется преобразование. Это не верно для неточных форматов.

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

Звучите так, как вы хотите алгоритм Бургера (PDF):

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

Образец исходного кода (на C и Scheme) также доступен.

Этот алгоритм используется в Python 3.x для обеспечения floats могут быть преобразованы в строки и обратно без потери точности. В Python 2.x floats всегда были представлены 17 значащими цифрами, потому что:

repr(float) производит 17 значащих цифр, потому что оказывается, что этого достаточно (на большинстве машин), чтобы eval(repr(x)) == x точно для всех конечных чисел x, но округления до 16 цифр недостаточно, чтобы сделать это правдой. (Источник: http://docs.python.org/tutorial/floatingpoint.html)

.NET Framework имеет формат туда и обратно для этого:

string formatted = myDouble.ToString("r");

Из документации:

Спецификатор туда-обратно гарантирует, что числовое значение, преобразованное в строку, будет проанализировано обратно в то же числовое значение. Когда числовое значение отформатировано с использованием этого спецификатора, оно сначала тестируется с использованием общего формата, с 15 пробелами точности для Double и 7 пробелами для Single. Если значение успешно проанализировано до того же числового значения, оно форматируется с использованием общего спецификатора формата. Однако, если значение не было успешно проанализировано обратно к тому же числовому значению, то это значение форматируется с использованием 17 цифр точности для двойного и 9 цифр точности для одинарного.

Этот метод, конечно, может быть воссоздан на любом языке.

Да, это можно сделать, хотя реализация зависит от языка. Основная идея заключается в том, чтобы просто распечатать его с достаточной точностью.

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

Другие вопросы по тегам