Jakiego rodzaju optymalizacje oferuje opcja -ffast-math?

Widziałem, że czas potrzebny na skrócenie prostego algorytmu $ O (n ^ 2) $ do czasu algorytmu $ O (n) $ przy użyciu tej opcji.

Komentarze

  • Myślę, że to pytanie ma już odpowiedź na temat przepełnienia stosu: stackoverflow.com/questions/7420665/…
  • Ja ' głosuję za zamknięciem tego pytania jako duplikatu pytania w innym SE .
  • @BillBarth: Zamknięcie pytania jako duplikatu generalnie działa tylko w ramach danej witryny StackExchange, z wyjątkiem oczywistych krzyżowych postów. Zobacz meta.stackexchange.com/questions/172307/… w Meta StackExchange, aby zapoznać się z dyskusjami i możliwymi rozwiązaniami.
  • @GeoffOxberry, widziałem to i wypróbowałem plan B.
  • @BillBarth, jak myślisz, gdzie mogę znaleźć szczegółową odpowiedź?

Odpowiedź

Istnieje kanoniczna odpowiedź na to pytanie na wiki GCC , którą jest przypuszczalnie utrzymywane, jest to zdecydowanie najbardziej autorytatywne źródło informacji dla tego typu pytań. Z drugiej strony, to pytanie może ostatecznie stracić aktualność. Wszystko to jest wyjaśnione bardziej szczegółowo na wiki, wraz z przykładami. jest jego cytatem ilustrującym dokładną odpowiedź na to pytanie, z drobnymi komentarzami:

  • -fno-signaling-nans
  • -fno-trapping-math

    Standard IEEE zaleca, aby implementacje zezwalały obsłudze pułapek na obsługę exc eptions jak dzielenie przez zero i przepełnienie. Ta flaga zakłada, że nie nastąpi żadna widoczna dla użytkownika pułapka.

  • -funsafe-math-optimizations – Te optymalizacje łamią prawa arytmetyki zmiennoprzecinkowej i mogą zastąpić je prawami zwykłej arytmetyki o nieskończonej precyzji:

    Ze względu na błędy zaokrąglenia asocjacja prawo algebry nie jest konieczne dla liczb zmiennoprzecinkowych i dlatego wyrażenia takie jak (x + y) + z nie są konieczne równe x + (y + z).

  • -ffinite-math-only – Specjalne ilości, takie jak inf lub nan nigdy się nie pojawi, co oszczędza czas spędzony na ich szukaniu i odpowiednim obsługiwaniu. Na przykład, czy $ x – x $ powinno być zawsze równe 0,0 $?

  • -fno-errno-math

    wyłącza ustawianie zmiennej errno zgodnie z wymaganiami C89 / C99 przy wywoływaniu procedur biblioteki matematycznej. W przypadku Fortran jest to ustawienie domyślne.

  • -fcx-limited-range

    powoduje pominięcie kroku redukcji zakresu podczas wykonywania złożonego dzielenia. To używa $ a / b = ((ar * br + ai * bi) / t) + i ((ai * br – ar * bi) / t) $ z $ t = br * br + bi * bi $ i może nie działa dobrze na dowolnych zakresach danych wejściowych.

  • -fno-rounding-math

  • -fno-signed-zeros

    Ze względu na błędy zaokrągleń, prawo asocjacyjne algebry nie jest konieczne liczby zmiennoprzecinkowe, a więc wyrażenia takie jak (x + y) + z, nie są konieczne równe x + (y + z).

Ściśle mówiąc, implikacje dwóch ostatnich nie zawsze są tak intuicyjne, jak mogłoby się wydawać. Na przykład (patrz wiki), co z $ – (a – a) = a – a $, czy to $ + 0,0 $ czy $ -0,0 $? Uważam, że istnieje sporo literatury na temat dokładnych implikacji, zwłaszcza Billa Kahana .

  • Nie wspomniano bezpośrednio (ja nie widzisz tego?), ale przy -ffast-math, niektóre popularne funkcje specjalne, takie jak odwrotność $ 1 / x $ i pierwiastek kwadratowy $ \ sqrt {x} $, są zastępowane przez mniej precyzyjne wersje, które są szybsze, ale nadal mają pewne „tolerowane” poziomy błędów (w porównaniu z błędem 0ulp wymaganym przez standard) – tutaj, na przykład, precyzja jest zwykle zapewniana przez glibc „s libm . Rzeczywiście, jest to najczęstsza przyczyna przyspieszenia od -ffast-math, w kodzie, który wykonuje wiele działań arytmetycznych z dzieleniami i pierwiastkami kwadratowymi, prawie do tego stopnia, że ja ( osobiście ) sądzę, że inne podopcje (-ffinite-math-only i tym podobne, szczególnie – sygnalizacja NaN s są całkiem przydatne do debugowania) powodują również trochę wiele kłopotów pod względem kosztów / korzyści.

Widziałem, że czas potrzebny na proste $ O (n ^ 2) $ algorytm został zredukowany do algorytmu $ O (n) $ przy użyciu opcji.

Uważam, że to nieprawdopodobne i możliwe, że popełniłeś błąd w swojej analizie.Niebezpieczne optymalizacje zmiennoprzecinkowe mogą sprawić, że poszczególne wyrażenia będą nieco tańsze do oszacowania ze względu na większy wybór optymalizacji. Ale przyspieszenie powinno zawsze być co najwyżej stałym czynnikiem. Czy to możliwe, że porównałeś algorytm $ O (n ^ 2) $ z $ O (n) $ dla niewystarczająco dużego $ n $?

Odpowiedź

Algorytm $ n ^ 2 $ można zredukować do czegoś, co zachowuje się $ O (n) $, jeśli na przykład $ n $ jest znane kompilatorowi i jest wielokrotnością rozmiaru wektora dla instrukcji wektorowych (jeśli istnieją) obsługiwanych przez procesor. Jeśli kompilator widzi to wszystko, może rozwinąć wewnętrzną pętlę i użyć instrukcji wektorowych do wykonania pracy. Może to zmniejszyć ogólną liczbę wykonywanych operacji do zaledwie kilku i znacznie poprawić wydajność.

Czytam, że fast-math nie włącza takiej optymalizacji, ale mogłaby, gdyby były one domyślnie włączone przez unsafe-math-optimizations z powodu ograniczeń asocjacyjnych, które są tam wyłączone.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *