Точное текстовое представление IEEE "двойник" - PullRequest
5 голосов
/ 20 марта 2010

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

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

Ответы [ 4 ]

11 голосов
/ 20 марта 2010

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

printf("%a", someDouble);

Строки, созданные таким образом, могут быть преобразованы обратно в double с помощью функции C99 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 значащих цифр. Если у вас есть правильно округленная процедура преобразования (в большинстве, но не во всех платформах), это гарантирует, что вы можете совершить круговое путешествие от двойного до струнного и обратно без потери точности.

5 голосов
/ 20 марта 2010

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

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

Пример исходного кода (в C и на схеме) также доступен.

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

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

2 голосов
/ 20 марта 2010

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

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

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

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

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

1 голос
/ 20 марта 2010

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

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

...