Всегда ли double 0.0 представлен точно в переносимом C?

Можно ли ожидать, что следующий код будет работать во всех средах с ANSI-совместимым компилятором C?

double n = 0;
assert(n == 0);

А как насчет C++?

4 ответа

Решение

Вы не спрашиваете, если 0.0 всегда представлен точно.

В заявлении assert(n == 0), 0 преобразуется в double до сравнения Таким образом, утверждение может быть запущено только при преобразовании 0 от int в double не воспроизводится. Это гораздо более слабое ограничение, чем то, о чем вы спрашиваете, и оно почти наверняка будет иметь место (хотя я не могу придумать ссылку на стандарты, которая гарантировала бы это на моей голове).

На вопрос, который вы намеревались задать:

Как уже упоминалось, стандарт C не требует, чтобы типы с плавающей запятой отображались на IEEE-754, но я не знаю ни одного представления с плавающей запятой, используемого с любым компилятором C, у которого нет точного представления нуля. Тем не менее, было бы "законно" для реализации C использовать формат для double это не было точного нуля.

Стандарт C накладывает некоторые ограничения на представление значений с плавающей запятой. В §5.2.4.2.2 Характеристики плавающих типов числа с плавающей запятой должны демонстрировать характеристики, как если бы они были определены моделью:

x = sbe Σk = 1..p fk b-k

Куда:

  • s - знак, и должен быть ± 1;
  • b является основанием и должно быть целым числом> 1;
  • е - показатель степени и должно быть целым числом от emin до emax;
  • р - точность; а также
  • fk - неотрицательные целые числа < b - цифры значимости и.

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

Учитывая следующее ограничение в §6.3.1.4:

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

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

Сравнение увеличит целое число до двойного. Вы спрашиваете, гарантирует ли компилятор одинаковые преобразования каждый раз, когда он конвертирует одинаковые целые числа в удвоенные. Я верю, что это так.

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

C99 не обязывает IEEE754, только рекомендует. Существует символ, который могут определять платформы компиляции, соответствующие IEEE 754 (Приложение F). Если компилятор определяет этот символ, тогда да, утверждение будет гарантированно выполнено. Когда литеральная константа представляется точно как число с плавающей запятой, тогда это число с плавающей запятой - это то, что вы должны получить в скомпилированной программе.

Я не могу представить себе какую-либо не-IEEE 754 систему с плавающей запятой, которая не будет иметь ноль, или причину не отображать литерал 0 в исходном коде к нему.

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