2013-04-02 9 views
5

Zastanawiam się, czy GCC opuści arytmetyczne ze stałymi wartościami do wykonania w czasie wykonywania, czy też ustawi je na swoją odpowiedź, np.Czy GCC pozostawi arytmetyczne ze stałymi wartościami do wykonania lub skompiluje wyjście?

const float halfPi = M_PI/2; 

Będzie to "sprowadzać" równanie i ustawić

const float halfPi = 1.57079; 

lub pozostawić arytmetyki dla run-time?

+3

Wystarczy spojrzeć na wyjście asemblera: 'gcc -S' – ydroneaud

+1

GCC -O1 i wyżej na pewno wykona to podczas kompilacji. W rzeczywistości jest więcej kodu w GCC dla tego rodzaju rzeczy, obsługujących również funkcje zdefiniowane przez użytkownika - patrz także constexpr. – dascandy

+2

Tak jak FYI, ta optymalizacja nazywa się [stałe składanie] (http://en.wikipedia.org/wiki/Constant_folding). – unwind

Odpowiedz

8

Cóż ... jeśli mówiliśmy o całek odpowiedzią byłoby jednoznaczne tak (w ramach ogólnego terminu Stała Folding). Nawet obliczenia długotrwałe mogą być wykonywane w czasie kompilacji ... a tak naprawdę jest to wymagane w przypadku szablonów do oceny parametrów nie typu i zmiennych (teraz) constexpr.

W przypadku reprezentacji zmiennoprzecinkowych zmiennoprzecinkowe rzeczy stają się nieco skomplikowane, gdy obliczenia stają się nieco bardziej skomplikowane. Problem polega na tym, że reprezentacje zmiennoprzecinkowe o różnych rozmiarach (a tym samym dokładności) przyniosą różne wyniki dla tych samych podstawowych danych wejściowych.

Aby zrozumieć dlaczego, załóżmy, że float ma co najwyżej 5 cyfr dokładności:

5.0000 + 0.00001 
-> 5.00001 
-> 5.0000 (truncation to 5 digits) 

    5.0000 + 0.00001 + ... + 0.00001 (10 times) 
-> 5.0000 + 0.00001 + ... + 0.00001 (9 times) 
-> 5.0000 + 0.00001 + ... + 0.00001 (8 times) 
-> ... 
-> 5.0000 

Zaskakujące ... prawda? Jeśli kompilacja jest wykonywana w czasie wykonywania, wynik może się różnić w zależności od tego, czy używany jest rejestr (z większą przepustowością), czy nie.

W związku z tym, czy stałe składanie występuje prawdopodobnie zależy od na zestaw flag optymalizacji używasz. Na przykład for gcc, to może być kontrolowane przez -freciprocal-math (naprawdę nie mam pojęcia). Ponieważ nawet jeśli kompilator z pewnością może zrobić to, możesz powiedzieć, że nie (nieświadomie).

Tak więc jedynym pewnym sposobem na sprawdzenie tego jest sprawdzenie wyjścia kompilatora; albo poprzez sprawdzenie kodu obiektu LUB przez zapytanie kompilatora o emisję zespołu. I musisz sprawdzić to wyjście dla każdej kombinacji opcji, których używasz.

+0

Wycofano i oznaczono. Dziękuję Ci. :) – Erkling

+1

+1. Istnieją inne szczegóły, takie jak np. 'std :: fesetround', który ustawia zachowanie zaokrąglania w czasie wykonywania. Nawet 'const float x = 1, y = 2; bla(); const float z = x/y; 'może być problemem, gdy' foo() 'może zmienić tryb zaokrąglania. – MSalters

5

Dziś jest twój szczęśliwy dzień, ponieważ dowiadujesz się o Agner Fog i jego niesamowitej głębi c++ manuals! Jeśli spojrzysz na sekcję 8.2 z this one zobaczysz, że zasadniczo wszystkie kompilatory są zdolne do stałego składania.

Chociaż aby upewnić się, że ma to miejsce w tym szczególnym przypadku z opcjami kompilatora, należy sprawdzić dane wyjściowe zespołu, jak sugerowano powyżej (należy użyć -S). Chciałbym umieścić w kodzie coś podobnego do kodu asm("MY_LABEL:");, aby było łatwiej znaleźć, ale pamiętaj, że może to zmienić znaczenie kodu, a więc sposób, w jaki kompilator je interpretuje. W tym przypadku nie wierzę, że to by coś zmieniło.

+0

Dziękuję za odpowiedź. :) Oznaczone jako takie. – Erkling

+1

Inna odpowiedź zawierała więcej informacji, dlatego postanowiłem oznaczyć ją dla przyszłych czytelników. – Erkling

+0

Odczytywałam dane wyjściowe zespołu przez lata, ale nigdy nie wiedziałem o 'asm (" etykiecie ")', które jest tak bardzo użyteczne jako czasomierz. Warto naprawdę +1. – Voo

Powiązane problemy