Точное текстовое представление 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 для обеспечения float
s могут быть преобразованы в строки и обратно без потери точности. В Python 2.x float
s всегда были представлены 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 цифр точности для одинарного.
Этот метод, конечно, может быть воссоздан на любом языке.
Да, это можно сделать, хотя реализация зависит от языка. Основная идея заключается в том, чтобы просто распечатать его с достаточной точностью.
Обратите внимание, что обратное неверно: некоторые числа, которые могут быть представлены точно в десятичном виде, просто не могут быть представлены в двоичном виде.