Точность с плавающей точкой при переходе с i386 на x86_64 - PullRequest
11 голосов
/ 27 ноября 2008

У меня есть приложение, которое было разработано для Linux x86 32 бит. Есть много операций с плавающей точкой и множество тестов в зависимости от результатов. Сейчас мы портируем его на x86_64, но результаты теста в этой архитектуре разные. Мы не хотим хранить отдельный набор результатов для каждой архитектуры.

Согласно статье Введение в GCC - для компиляторов GNU gcc и g ++ проблема состоит в том, что GCC в X86_64 предполагает fpmath = sse , а x86 предполагает fpmath = 387 . FPU 387 использует 80-битную внутреннюю точность для всех операций и преобразует результат только в заданный тип с плавающей точкой (float, double или long double), в то время как SSE использует тип операндов для определения его внутренней точности .

Я могу force -mfpmath = 387 при компиляции собственного кода, и все мои операции работают правильно, но всякий раз, когда я вызываю какую-либо библиотечную функцию (sin, cos, atan2 и т. Д.), Результаты снова оказываются неверными , Я предполагаю, что это потому, что libm был скомпилирован без переопределения fpmath.

Я пытался собрать libm самостоятельно (glibc), используя эмуляцию 387, но это вызвало множество сбоев (не знаю, сделал ли я что-то не так).

Есть ли способ заставить весь код в процессе использовать эмуляцию 387 в x86_64? Или, может быть, какая-то библиотека, которая возвращает те же значения, что и libm на обеих архитектурах? Есть предложения?

Относительно вопроса «Вам нужна точность 80 бит», я должен сказать, что это не проблема для отдельной операции. В этом простом случае разница действительно мала и не имеет значения. Однако при объединении большого количества операций ошибка распространяется, и разница в конечном результате уже не так мала и имеет значение. Поэтому я думаю, что мне нужна точность 80 бит.

Ответы [ 4 ]

17 голосов
/ 27 ноября 2008

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

Как вы узнали, каждая библиотека, на которую вы полагаетесь, будет принимать плавающую точку SSE, поэтому, если вы не планируете компилировать все вручную, сейчас и навсегда, просто так вы можете установить режим FP что касается x87, вам лучше справиться с проблемой сейчас, и просто принять, что математика FP не является точной на 100%, и в целом не даст одинакового результата на двух разных платформах. (Я полагаю, что производительность процессора AMD немного отличается и в математике x87).

Вам абсолютно нужна 80-битная точность? (Если это так, очевидно, что вариантов не так уж и много, кроме компиляции всего для использования 80-битной FP.)

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

5 голосов
/ 28 января 2009
Точность

80 бит на самом деле опасна. Проблема заключается в том, что она фактически сохраняется до тех пор, пока переменная хранится в регистре процессора. Всякий раз, когда он вытесняется в ОЗУ, он усекается с точностью до типа. Таким образом, переменная может фактически изменить ее значение, даже если с этим в коде ничего не произошло.

3 голосов
/ 29 июня 2011

Если вы хотите long double точность, используйте long double для всех ваших переменных с плавающей запятой, а не ожидайте, что float или double будут иметь дополнительную магическую точность. Это действительно легкая задача.

2 голосов
/ 28 ноября 2008

SSE с плавающей запятой и 387 с плавающей запятой используют совершенно разные инструкции, и поэтому нет никакого способа убедить инструкции SSE fp использовать 387. Вероятно, лучший способ справиться с этим - заставить свой набор тестов получить немного другие результаты, и не зависит от результатов, совпадающих с последним битом.

...