Является ли C с плавающей запятой недетерминированным?

Я где-то читал, что существует источник недетерминированности в С-точке с двойной точностью:

  • В стандарте C говорится, что 64-битные поплавки (удваиваются) необходимы для получения только около 64-битной точности.

  • Аппаратное обеспечение может выполнять с плавающей запятой в 80-битных регистрах.

  • Из-за (1) компилятор C не требуется очищать младшие биты регистров с плавающей запятой, прежде чем набивать двойной бит в старшие разряды.

  • Это означает, что YMMV, т.е. могут иметь место небольшие различия в результатах.

Есть ли какая-то общая комбинация аппаратного и программного обеспечения, где это действительно происходит? Я вижу в других потоках, что .net имеет эту проблему, но C удваивает через gcc OK? (например, я проверяю сходимость последовательных приближений на основе точного равенства)

Ответ 1

Поведение при реализации с избыточной точностью, которое, по-видимому, является проблемой, о которой вы беспокоитесь, строго указано стандартом в большинстве, если не во всех случаях. В сочетании с IEEE 754 (предполагая, что ваша реализация C соответствует Приложению F), это не оставляет места для тех видов недетерминированности, о которых вы, кажется, спрашиваете. В частности, такие вещи, как x == x (который Мехрдад упомянул в комментарии), запрещены, поскольку существуют правила, когда избыточная точность сохраняется в выражении и когда она отбрасывается. Явные приведения и назначение объекту относятся к операциям, которые вызывают избыточную точность и гарантируют, что вы работаете с номинальным типом.

Обратите внимание, что там все еще много сломанных компиляторов, которые не соответствуют стандартам. GCC намеренно игнорирует их, если вы не используете -std=c99 или -std=c11 (т.е. Варианты "gnu99" и "gnu11" намеренно нарушены в этом отношении). И до GCC 4.5 правильная обработка избыточной точности даже не поддерживалась.

Ответ 2

Это может произойти в коде Intel x86, который использует блок с плавающей запятой x87 (за исключением, вероятно, 3., что кажется фиктивным. Биты LSB будут установлены на ноль.). Таким образом, аппаратная платформа очень распространена, но со стороны программного обеспечения использование x87 вымирает в пользу SSE.

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

См. "Ловушки для проверки вычислений с плавающей запятой" , стр. 8ff.

Ответ 3

Тестирование точной сходимости (или равенства) в плавающей точке обычно является плохим, даже в полностью детерминированной среде. FP - примерное представление для начала. Гораздо безопаснее протестировать конвергенцию с точностью до определенного эпсилона.