Що насправді робить факс-математика gcc?


144

Я розумію, --ffast-mathпрапор gcc може значно збільшити швидкість для float ops, і виходить за рамки стандартів IEEE, але я не можу знайти інформацію про те, що насправді відбувається, коли він включений. Чи можете будь-хто пояснити будь-яку деталь і, можливо, дати чіткий приклад того, як щось змінилося, якщо прапор був увімкнений чи вимкнений?

Я спробував перекопати SO через подібні запитання, але не зміг знайти нічого, що пояснює роботу фаст-математики.

Відповіді:


86

Як ви вже згадували, він дозволяє оптимізувати, які не зберігають суворого дотримання IEEE.

Приклад такого:

x = x*x*x*x*x*x*x*x;

до

x *= x;
x *= x;
x *= x;

Оскільки арифметика з плаваючою комою не асоціативна, впорядкування та факторинг операцій впливатимуть на результати за рахунок округлення. Отже, ця оптимізація не проводиться в умовах суворої поведінки ПП.

Я фактично не перевіряв, чи GCC насправді робить цю оптимізацію. Але ідея та сама.


25
@Andrey: У цьому прикладі ви переходите від 7
кратних

4
@Andrey: Математично це буде правильно. Але результат може незначно відрізнятися в останні кілька бітів через різну округлення.
Містичний

1
У більшості випадків ця незначна різниця не має значення (щодо порядку 10 ^ -16 для double, але змінюється залежно від програми). Варто зазначити, що оптимізація швидкої математики не обов'язково додає «більше» заокруглення. Єдина причина, чому це не відповідає IEEE, полягає в тому, що відповідь відрізняється (хоча і незначно) від написаного.
Містичний

1
@user: Величина помилки залежить від вхідних даних. Він повинен бути невеликим щодо результату. Наприклад, якщо xвона менше 10, помилка в прикладі Mystical зменшиться близько 10 ^ -10. Але якщо x = 10e20, помилка, ймовірно, буде багато мільйонів.
Ben Voigt

3
@stefanct це на самому справі про те, -fassociative-mathякий включений в -funsafe-math-optimizationsякому , в свою чергу включена -ffast-math Чому не GCC оптимізують a*a*a*a*a*aдо (a*a*a)*(a*a*a)?
phuclv

255

-ffast-math робить набагато більше, ніж просто порушувати суворе дотримання IEEE.

Перш за все, звичайно, це зламається чітке дотримання IEEE, дозволяючи, наприклад, переупорядкувати інструкції на те, що математично те саме (в ідеалі), але не зовсім однакове в плаваючій точці.

По-друге, це вимикає налаштування errnoпісля математичних функцій з однією інструкцією, що означає уникнення запису в локальну змінну потоку (це може зробити 100% різницю для цих функцій у деяких архітектурах).

По-третє, це робить припущення, що вся математика є кінцевою , а це означає, що ніяких перевірок на NaN (або нуль) не робиться там, де вони мали б згубний вплив. Просто припускається, що цього не відбудеться.

По-четверте, це дозволяє зворотні наближення для ділення та зворотного квадратного кореня.

Крім того, він відключає підписаний нуль (код припускає, що підписаний нуль не існує, навіть якщо ціль його підтримує) та математику округлення, що дозволяє, крім усього іншого, постійне згортання під час компіляції.

Нарешті, він генерує код, який передбачає, що жодне апаратне переривання не може відбутися через математичну сигналізацію / захоплення (тобто якщо їх не можна вимкнути в цільовій архітектурі і, отже, це не станеться , вони не будуть оброблятися).


15
Демоне, дякую! Чи можете ви додати кілька посилань? Як і gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html " -ffast-math Набори -fno-math-errno, -funsafe-math-optimizations, -ffinite-math-only, -fno-rounding-math, -fno-сигналізація -nans та -fcx з обмеженим діапазоном. Цей параметр призводить до визначення макросу препроцесора FAST_MATH . "та чогось із glibc, наприклад ( math.hбіля math_errhandling)" За замовчуванням усі функції підтримують як errno, так і обробку винятків. У швидкому математичному режимі gcc та якщо визначені вбудовані функції, це може бути неправдою ".
osgx

4
@javapowered: чи "небезпечно" це залежить від того, які гарантії вам потрібні. -ffast-mathдозволяє компілятору скоротити деякі кути і порушити деякі обіцянки (як пояснено), що в цілому не є небезпечним як таким і не є проблемою для більшості людей. Для більшості людей це те саме, тільки швидше. Однак якщо ваш код передбачає і покладається на ці обіцянки, то ваш код може поводитись інакше, ніж ви очікували. Зазвичай це означає, що програма, здається, працює нормально, але деякі результати можуть бути "несподіваними" (скажімо, у фізичному моделюванні два об'єкти можуть не стикатися належним чином).
Деймон

2
@Royi: Вони повинні бути незалежними один від одного. -O2як правило, дозволяє "кожну" юридичну оптимізацію, за винятком тих, що торгують розміром для швидкості. -O3також дозволяє оптимізувати розмір торгівлі для швидкості. Він все ще підтримує 100% правильність. -ffast-mathспроби зробити математичні операції швидшими, дозволяючи «злегка неправильну» поведінку, яка зазвичай не є шкідливою, але вважається неправильною формулюванням стандарту. Якщо ваш код дійсно сильно відрізняється швидкістю на двох компіляторах (а не лише на 1-2%), то перевірте, чи ваш код суворо відповідає стандартам і ...
Damon

1
... видає нульові попередження. Також переконайтеся, що ви не заважаєте створювати правила дозволу та такі речі, як автоматична векторизація. В принципі, GCC має працювати як мінімум настільки ж добре (як правило, краще, на мій досвід), як MSVC. Якщо це не так, ви, мабуть, зробили тонку помилку, яку MSVC просто ігнорує, але яка змушує GCC відключити оптимізацію. Ви повинні дати обидва варіанти, якщо ви хочете їх обох, так.
Деймон

1
@Royi: Цей код не схожий на мене справді маленьким і простим, а не тим, що можна було би глибоко проаналізувати за кілька хвилин (а то й годин). Крім усього іншого, він передбачає, здавалося б, нешкідливий #pragma omp parallel for, і всередині циклу циклу ви читаєте і пишете на адреси, на які вказують аргументи функції, і робите нетривіальну кількість розгалуження. Як неосвічений здогад, ви можете обробляти кеші з-за виклику потоків, визначених вашою реалізацією, і MSVC може неправильно уникнути проміжних сховищ, на які покладаються правила псевдонімування. Неможливо сказати.
Деймон
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.