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

Когда я выполняю тот же самый код, выполняющий то же самое вычисление с плавающей точкой (использование удваивается), скомпилированный в Windows и Солярисе, я получаю немного отличающиеся результаты.

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

Действительно ли это нормально, или у меня есть другая проблема в моем коде?

6
задан Brooks Moses 4 March 2010 в 01:48
поделиться

3 ответа

На x86, как правило, большинство вычислений происходит с 80-битными величинами, если иначе не требуется двойная точность. Большинство других известных мне архитектур выполняют все вычисления с двойной точностью (опять же, если иное не отменено).

Я не знаю, используете ли вы Solaris на SPARC или x86, но если первое, то я очень подозреваю, что это и является причиной разницы.

7
ответ дан 10 December 2019 в 00:37
поделиться

Тема вашего вопроса предполагает, что это может зависеть от компилятора. Возможно, но тот факт, что вы работаете на разном оборудовании (предполагается, что ваша Solaris не x86), указывает на гораздо более вероятную причину разницы - разницу в самом оборудовании.

Разные аппаратные платформы могут использовать совершенно разные аппаратные устройства (FPU, CPU) для выполнения вычислений с плавающей точкой, что приводит к разным результатам.

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

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

1
ответ дан 10 December 2019 в 00:37
поделиться

Я считаю, что под Windows / x86 ваш код будет работать с точностью x87, уже установленной на 53 бита (двойная точность), хотя я не уверен, когда именно это будет установлено. В Solaris / x86 FPU x87, вероятно, будет использовать точность по умолчанию в 64 бита (расширенная точность), отсюда и разница.

Вы можете выполнить простую проверку, чтобы определить, какая точность (53 или 64 бита) используется: попробуйте вычислить что-то вроде 1e16 + 2,9999 , стараясь при этом избегать оптимизаций компилятора сворачивания констант ( например, определите отдельную функцию add для добавления и отключения любых оптимизаций, которые могут быть встроены в функции). При использовании 53-битной точности (SSE2 или x87 в режиме двойной точности) это дает 1e16 + 2; при использовании 64-битной точности (x87 в режиме повышенной точности) это дает 1e16 + 4. Последний результат получается из-за эффекта, называемого «двойное округление», когда результат сложения округляется сначала до 64 бит, а затем до 53 бит. . (Выполняя этот расчет непосредственно в Python, я получаю 1e16 + 4 в 32-битном Linux и 1e16 + 2 в Windows по той же причине.)

Вот очень хорошая статья (которая значительно выходит за рамки часто цитируемого Голдберга «Что должен знать каждый компьютерный ученый ...»), в котором объясняются некоторые проблемы, возникающие при использовании FPU x87:

http://hal.archives-ouvertes.fr/docs/00/28/14 / 29 / PDF / статья с плавающей точкой.pdf

2
ответ дан 10 December 2019 в 00:37
поделиться