Имеет ли FCC-математика GCC гарантии согласованности между платформами или версиями компилятора? - PullRequest
0 голосов
/ 11 апреля 2019

Я хочу написать кроссплатформенный C / C ++, который воспроизводит поведение в разных средах.

Я понимаю, что математическая математика gcc позволяет использовать различные приближения с плавающей точкой. Это нормально, но мне нужны два отдельно скомпилированных двоичных файла для получения одинаковых результатов.

Скажем, я всегда использую gcc, но по-разному для Windows, Linux и т. Д. И разных версий компилятора.

Есть ли гарантия, что эти компиляции приведут к одному и тому же набору приближений с плавающей запятой для одного и того же исходного кода?

1 Ответ

3 голосов
/ 11 апреля 2019

Нет , дело не в том, что они допускают конкретные приближения, а в том, что -ffast-math позволяет компиляторам предполагать, что математика FP ассоциативна, когда это не так.т. е. игнорировать ошибку округления при преобразовании кода, чтобы обеспечить более эффективный ассемблер.

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

В более старых версиях компилятора можно было бы реализоватьsqrt(x) как x * approx_rsqrt(x) с итерацией Ньютона-Рафсона для -ffast-math, потому что у более старых процессоров была более медленная инструкция sqrtps, так что чаще стоило заменить ее приближением по обратной величине + sqrt + 3 или 4больше умножить и добавить инструкции.Как правило, это не относится к большинству кода для последних процессоров, поэтому , даже если вы используете те же настройки options (особенно, например, -mtune=generic по умолчанию вместо -mtune=haswell), варианты, которыепараметр make может меняться между версиями GCC.


Достаточно сложно получить детерминированный FP без -ffast-math;разные библиотеки в разных ОС имеют разные реализации функций, таких как sin и log (которые в отличие от базовых операций + - * / sqrt не обязаны возвращать «правильно округленный» результат, то есть максимальная ошибка 0.5ulp).

А дополнительная точность для временных (FLT_EVAL_METHOD) может изменить результаты, если вы скомпилируете 32-битную версию x86 с математикой x87 FP.(-mfpmath=387 является значением по умолчанию для -m32).Если вы хотите иметь хоть какую-то надежду, вам следует избегать 32-битного x86.Или, если вы застряли с этим, может быть, вы можете обойтись без -msse2 -mfpmath=sse ...

Вы упомянули Windows, поэтому я предполагаю, что вы говорите только о x86 GNU / Linux, хотя Linuxработает на многих других ISA.

Но даже в x86 компиляция с -march=haswell позволяет использовать инструкции FMA, а по умолчанию GCC #pragma STDC FP_CONTRACT ON (дажемежду утверждениями C, за пределами того, что допускают обычные правила ISO C.) Таким образом, даже без -ffast-math, доступность FMA может удалить округление для временного x*y в x*y + z.


С -ffast-math:

Одна версия gcc может решить развернуть цикл на 2 (и использовать 2 отдельных аккумулятора) при суммировании массива, в то время как более старая версия gcc с теми же параметрами может по-прежнему суммировать по порядку.

(На самом деле текущий gcc ужасен, когда он разворачивается (не по умолчанию), он часто все еще использует тот же (векторный) аккумулятор, поэтому он не скрывает задержку FP, как это делает кланг. Например, https://godbolt.org/z/X6DTxK использует разные регистры дляпеременная ame, но это всего лишь один аккумулятор, без вертикального сложения после цикла суммы.Но, надеюсь, будущие версии gcc будут лучше.И различия между версиями gcc в том, как они делают горизонтальную сумму регистра YMM или XMM, могут вносить различия при автоматической векторизации)

...