Подтвердить что ты не робот

Точность с плавающей точкой при переходе с i386 на x86_64

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

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

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

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

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

Что касается вопроса "Нужна ли вам 80-битная точность", я должен сказать, что это не проблема для отдельной операции. В этом простом случае разница действительно мала и не имеет значения. Тем не менее, при составлении множества операций ошибка распространяется, и разница в конечном результате не так уж и мала и имеет значение. Поэтому я думаю, мне нужна точность в 80 бит.

4b9b3361

Ответ 1

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

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

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

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

Ответ 2

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

Ответ 3

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

Ответ 4

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