Rozumiem, że --ffast-math
flaga gcc może znacznie zwiększyć prędkość operacji typu float i wykracza poza standardy IEEE, ale nie mogę znaleźć informacji o tym, co naprawdę się dzieje, gdy jest włączony. Czy ktoś może wyjaśnić niektóre szczegóły i może podać jasny przykład, jak coś by się zmieniło, gdyby flaga była włączona lub wyłączona?
Próbowałem przekopać się przez SO w poszukiwaniu podobnych pytań, ale nie mogłem znaleźć nic wyjaśniającego działanie ffast-matath.
double
, ale różni się w zależności od aplikacji). Należy zauważyć, że optymalizacje ffast-matematyczne niekoniecznie dodają „więcej” zaokrągleń. Jedynym powodem, dla którego nie jest zgodny ze standardem IEEE, jest to, że odpowiedź jest inna (choć nieznacznie) od tego, co jest napisane.x
jest mniejsze niż 10, błąd w przykładzie Mystical spadnie o około 10 ^ -10. Ale jeślix = 10e20
błąd prawdopodobnie wyniesie wiele milionów.-fassociative-math
, który jest zawarty w-funsafe-math-optimizations
którym z kolei jest włączona-ffast-math
Dlaczego nie GCC zoptymalizowaća*a*a*a*a*a
do(a*a*a)*(a*a*a)
?-ffast-math
robi o wiele więcej niż tylko łamanie ścisłej zgodności z IEEE.Przede wszystkim oczywiście się psuje ścisłą zgodność z IEEE, pozwalając np. Na zmianę kolejności instrukcji na coś, co jest matematycznie takie samo (idealnie), ale nie dokładnie takie samo w postaci zmiennoprzecinkowej.
Po drugie, wyłącza ustawianie
errno
po funkcjach matematycznych składających się z jednej instrukcji, co oznacza unikanie zapisu do zmiennej lokalnej wątku (może to spowodować 100% różnicę dla tych funkcji na niektórych architekturach).Po trzecie, przyjmuje założenie, że cała matematyka jest skończona , co oznacza, że nie są przeprowadzane żadne kontrole dla NaN (lub zera), w którym miałyby one szkodliwe skutki. Po prostu zakłada się, że tak się nie stanie.
Po czwarte, umożliwia odwrotne przybliżenie dzielenia i odwrotności pierwiastka kwadratowego.
Ponadto wyłącza zero ze znakiem (kod zakłada, że zero ze znakiem nie istnieje, nawet jeśli cel je obsługuje) i zaokrąglanie matematyki, co umożliwia między innymi stałe zawijanie w czasie kompilacji.
Na koniec generuje kod, który zakłada, że żadne przerwania sprzętowe nie mogą się zdarzyć z powodu matematyki sygnalizującej / pułapkowej (to znaczy, jeśli nie można ich wyłączyć w architekturze docelowej i w konsekwencji się zdarzają , nie będą obsługiwane).
źródło
-ffast-math
Ustawia -fno-math-errno, -funsafe-math-optimizations, -ffinite-math-only, -fno-rounding-math, -fno-signaling -nans i -fcx-limited-range. Ta opcja powoduje zdefiniowanie makra preprocesora FAST_MATH . "i coś z glibc, np. (math.h
blisko math_errhandling)" Domyślnie wszystkie funkcje obsługują zarówno obsługę błędów, jak i wyjątków. W szybkim trybie matematycznym gcc i jeśli zdefiniowano funkcje wbudowane, może to nie być prawda. "-ffast-math
pozwala kompilatorowi iść na skróty i złamać pewne obietnice (jak wyjaśniono), co generalnie nie jest niebezpieczne jako takie i nie stanowi problemu dla większości ludzi. Dla większości ludzi jest tak samo, tylko szybciej. Jeśli jednak Twój kod zakłada i opiera się na tych obietnicach, może on zachowywać się inaczej niż się spodziewasz. Zwykle oznacza to, że program wydaje się działać dobrze, ale niektóre wyniki mogą być „nieoczekiwane” (np. W symulacji fizyki dwa obiekty mogą nie zderzać się prawidłowo).-O2
ogólnie umożliwia „każdą” legalną optymalizację, z wyjątkiem tych, które handlują wielkością dla szybkości.-O3
umożliwia również optymalizacje, które pozwalają na zmianę rozmiaru dla szybkości. Nadal zachowuje 100% poprawność.-ffast-math
usiłuje przyspieszyć operacje matematyczne, dopuszczając „nieco niepoprawne” zachowanie, które zwykle nie jest szkodliwe, ale byłoby uznane za nieprawidłowe w świetle normy. Jeśli kod jest rzeczywiście znacznie różnią się prędkością na dwóch kompilatorów (nie tylko 1-2%), a następnie sprawdzić, czy kod jest zgodny ściśle norm i ...#pragma omp parallel for
, a wewnątrz treści pętli zarówno czytasz, jak i piszesz do adresów wskazanych przez argumenty funkcji, a także wykonujesz nietrywialne rozgałęzienia. Jako niewykształcone przypuszczenie, możesz rzucać pamięć podręczną z wewnątrz zdefiniowanego przez implementację wywołania wątków, a MSVC może niepoprawnie unikać magazynów pośrednich, których wymagają reguły aliasingu. Trudno powiedzieć.