Разбор компилятором точных чисел с плавающей запятой

Как мы знаем, числа с плавающей запятой IEEE могут хранить точные представления всех целых чисел и целых чисел, кратных обратным степеням двойки, таким как 1/2 или 3/4, при условии, что числа остаются в пределах диапазона чисел с плавающей запятой. тип точки.

Однако гарантируют ли синтаксические анализаторы с плавающей запятой точные результаты анализа десятичных представлений таких чисел?

Например, если я использую 0.75 как литерал double в программе на C, будет ли компилятор гарантировать, что скомпилированный код содержит точное представление 3/4, или есть риск, что он выдаст сумму некоторого неточного представления 0,7? а какое неточное представление 0.05?

Или, аналогичным образом, если я использую 3e4 как литерал double, может ли точное число 3 быть умножено на какое-то неточное представление 2^(4*ln(10)/ln(2)) или что-то подобное?

Существуют ли какие-либо стандарты, которым обычно должны следовать FP-парсеры в этом вопросе, или это, как правило, полностью оставлено на усмотрение реализации? Если последнее, кто-нибудь знает, как на самом деле работают практически важные реализации, такие как GCC или glibc?

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


person Dolda2000    schedule 15.01.2013    source источник
comment
Если вы конкретно спрашиваете о C, вы можете пометить свой вопрос c. (В этом случае я почти уверен, что теоретически нет, а на практике — да.)   -  person Nemo    schedule 15.01.2013
comment
@Nemo: Я не спрашивал конкретно о C. Я просто использовал это как пример.   -  person Dolda2000    schedule 16.01.2013


Ответы (2)


Стандарт C разрешает константе с плавающей запятой быть либо представляемым значением, ближайшим к точному значению литеральных констант, либо большим или меньшим представляемым значением, непосредственно примыкающим к ближайшему значению, согласно C 2011 6.4.4.2 3. Некоторые реализации C делают лучше. Современные реализации должны работать лучше, так как есть опубликованные алгоритмы для правильного преобразования.

Однако стандарт C также предусматривает шестнадцатеричные константы с плавающей запятой, которые упрощают компилятору правильное преобразование. Шестнадцатеричная константа с плавающей запятой имеет базовую форму 0xhhh.hhhpeee, где hhh — шестнадцатеричные цифры. и eee — десятичная экспонента, которая может иметь знак. (Шестнадцатеричные цифры с одной стороны от «.» могут быть опущены, если они равны нулю, и точка может быть опущена, если цифры справа опущены.) Показатель степени равен степени двойки.

Стандарт C требует, чтобы шестнадцатеричная константа с плавающей запятой была правильно округлена, если основание для чисел с плавающей запятой является степенью 2 в реализации C. Рекомендуется создавать диагностическое сообщение, если шестнадцатеричная константа не может быть представлена ​​точно.

Например, 0x3p-2 должно быть ровно 0,75.

person Eric Postpischil    schedule 15.01.2013
comment
Хороший ответ. Вы случайно не знаете, встречается ли подобный язык в какой-либо спецификации C++? - person Nemo; 16.01.2013
comment
или большее или меньшее представляемое значение, непосредственно примыкающее к ближайшему значению - я полагаю, что в стандарте явно не упоминаются значения, которые имеют фактическое точное представление, и что он фактически не требует, чтобы они были точно представлены ? - person Dolda2000; 16.01.2013
comment
Для справки, я попытался дать GCC (с -Wall) константу 0x19238192839183983p-10, и он не выдал предупреждение о том, что его нельзя точно представить, хотя он содержит больше значащих цифр, чем умещается в двойном. - person Dolda2000; 16.01.2013
comment
@ Dolda2000: Похоже, вы должны отправить отчет об ошибке. - person Eric Postpischil; 16.01.2013

Обычно нет гарантии получения в абстрактном синтаксическом дереве ближайшего числа с плавающей запятой к десятичному представлению в исходном коде. Языковой стандарт, такой как C99, может указывать, что он должен находиться в пределах одного ULP (то есть не ближайшего, а одного из двух ближайших). На практике компилятор может использовать функции хоста strtof(), strtod(),…, которые опять же не указаны как возвращающие ближайшее число, и действительно иногда нет).

Ограничение внутри одного ULP подразумевает, что точное десятичное представление числа с плавающей запятой должно преобразовываться в это число. Однако многие интерпретаторы, такие как Ruby или Tcl, поставляются со своими собственными strtod(), если у хоста его нет. Эта реализация ужасна и может возвращать результат, неверный для нескольких ULP.

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


Подводя итог: для языка, который определяет преобразование десятичных чисел в числа с плавающей запятой в пределах одного ULP, вы должны быть в порядке для точных представлений, если вы используете качественную реализацию компилятора. Для интерпретируемых языков без такой спецификации либо вызывается хост strtod(), и в этом случае вы должны быть в порядке, либо используется ужасная реализация, и в этом случае вы не являетесь.

person Pascal Cuoq    schedule 15.01.2013
comment
Имейте в виду, меня в первую очередь интересует не то, как округляется результат, если он неточный, а то, анализируются ли числа, которые могут быть точно представлены, как их точные представления. - person Dolda2000; 15.01.2013
comment
@ Dolda2000 Да, я немного переформулировал вопрос, но после этого последнего редактирования я надеюсь, что ответ на ваш первоначальный вопрос тоже есть. Кстати, «сумма какого-то неточного представления 0,7 и какого-то неточного представления 0,05» — именно поэтому «ужасная реализация» неверна, возможно, не для 0,75, но точно, скажем, для 0,75e30. - person Pascal Cuoq; 15.01.2013
comment
Ограничение внутри одного ULP подразумевает, что точное десятичное представление числа с плавающей запятой должно быть преобразовано в это число. -- Имеет ли это? Разве технически и число выше, и число ниже (точно) не находятся в пределах одного ULP точного результата? - person Dolda2000; 16.01.2013
comment
@ Dolda2000 Я имел в виду строго. Но на самом деле в C99 формулировка такова: «либо ближайшее представимое значение, либо большее или меньшее представимое значение, непосредственно примыкающее к ближайшему представимому значению, выбранное способом, определяемым реализацией», который использует больше слов, но для точных значений имеет то же самое. двусмысленность, как моя формулировка. - person Pascal Cuoq; 16.01.2013