2016-02-19 16 views
14

W zależności od tego pytania Floating point division vs floating point multiplication. Podział jest wolniejszy niż mnożenie z kilku powodów.Czy kompilator zoptymalizuje podział na mnożenie?

Czy kompilator zwykle zastępuje dzielenie przez mnożenie, jeśli jest to możliwe?

Na przykład:

float a; 
// During runtime a=5.4f 
float b = a/10.f; 

będzie to:

float a; 
// During runtime a=5.4f 
float b = a*0.1f; 

Jeśli to jest uważane za niezawodne kompilator pytanie, używam VS2013 domyślny kompilator. Byłoby jednak miło, gdybym otrzymał ogólną odpowiedź (teoretyczną prawidłowość tej optymalizacji).

+1

Czy kompilator nie musi wykonywać podziału, aby móc pomnożyć przez odwrotność? – NathanOliver

+2

Nie jest to uwzględnione w części "Jeśli to możliwe", jest to przypadek, w którym nie jest to możliwe, chyba że zostanie zaakceptowana utrata dokładności. Miejmy nadzieję, że tylko przy kompilacji z flagą, która na to pozwala. – harold

+0

@NathanOliver skompiluj jeden raz .. nie zaszkodzi –

Odpowiedz

15

Nie, kompilator nie może tego zrobić dla ogólnego przypadku: te dwie operacje mogą dawać wyniki, które nie są identyczne z powodu błędu reprezentacji odwrotności.

W twoim przykładzie 0.1 nie ma dokładnej reprezentacji jako float. Powoduje to, że wyniki mnożenie przez 0.1 i dzielenie przez 10 różnią:

float f = 21736517; 
float a = f/10.f; 
float b = f * 0.1f; 
cout << (a == b) << endl; // Prints zero 

Demo.

Uwaga: W njuffa słusznie zauważa w komentarzu poniżej, istnieją sytuacje, gdy kompilator mógł markę niektóre optymalizacje dla szerokiego zestawu liczb, jak opisano w this paper. Na przykład pomnożenie lub dzielenie przez moc dwóch jest równoważne dodaniu do części wykładniczej reprezentacji IEEE-754 float.

+3

Chociaż kompilator dokona transformacji, jeśli powiesz mu, że nie przejmuj się ("-ffast-matma" gcc, niezależnie od tego, jaki jest odpowiednik MSVC). –

+1

Biorąc pod uwagę, jak nieprecyzyjnie C++ definiuje zmiennoprzecinkowe, myślę, że jesteś w błędzie. Kompilator * może * to zrobić. Jednak większość z nich wydaje się nie wybierać (preferując zapewnienie większej dokładności, kosztem prędkości). –

+3

Należy oddzielić przypadki, w których podział zmiennoprzecinkowy może być łatwo zastąpiony przez mnożenie * przy zachowaniu identycznych wyników *. W przypadku platform z arytmetyką IEEE-754 ma to zastosowanie w przypadku stałych dzielników, które mają moc 2, gdy odwrotność jest reprezentowalna. Widziałem, że kompilatory stosują tę optymalizację (na przykład dzielenie przez 2.0 jest mnożone przez 0.5). Istnieje technika stosowana do szerszego zakresu innych stałych dzielników, jak opisano w [tym dokumencie] (http://perso.ens-lyon.fr/nicolas.brisebarre/Publi/fpdivision.pdf). Niestety, nie widziałem żadnego kompilatora go używać. – njuffa