2016-02-19 19 views
14

A seconda della domanda Floating point division vs floating point multiplication. La divisione è più lenta della moltiplicazione a causa di alcuni motivi.Il compilatore ottimizzerà la divisione in moltiplicazione

Il compilatore, di solito, sostituirà la divisione per moltiplicazione se è possibile?

Ad esempio:

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

Sará:

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

Se si considera domanda affidabile un compilatore, Sto usando VS2013 compilatore di default. Tuttavia, sarebbe bello se avessi una risposta generica (validità teorica di questa ottimizzazione)

+1

Il compilatore non dovrebbe fare una divisione per poter moltiplicare per il reciproco? – NathanOliver

+2

Questo non è il caso incluso in "se possibile", questo è un caso in cui non è possibile a meno che non venga accettata una perdita di precisione. Quindi, si spera solo quando si compila con una bandiera che lo consente specificamente. – harold

+0

@NathanOliver compile tempo uno .. non farà male –

risposta

15

No, il compilatore non è autorizzato a farlo per il caso generale: le due operazioni potrebbero produrre risultati che non sono bit-identici a causa dell'errore di rappresentazione del reciproco.

Nell'esempio, 0.1 non ha una rappresentazione esatta come float. In questo modo i risultati delle moltiplicazioni per 0.1 e divisione per 10 differire:

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

Demo.

Nota: Come njuffa rileva correttamente nel commento qui sotto, vi sono situazioni in cui il compilatore potrebbe make alcune ottimizzazioni per un ampio set di numeri, come descritto in this paper. Ad esempio, moltiplicando o dividendo per una potenza di due è equivalente all'aggiunta alla parte esponente della rappresentazione IEEE-754 float.

+3

Anche se il compilatore eseguirà la trasformazione se gli dirai che non importa (gcc's '-ffast-math', qualunque sia l'equivalente di MSVC). –

+1

Dato che C++ definisce in modo errato il punto mobile, penso che tu abbia torto. Il compilatore * è * autorizzato a farlo. Tuttavia, la maggior parte di essi sembra scegliere di non (preferendo fornire maggiore precisione, al costo della velocità). –

+3

Uno deve separare i casi in cui una divisione in virgola mobile può essere facilmente sostituita con una moltiplicazione * mantenendo i risultati bit identici *. Per piattaforme con aritmetica IEEE-754, questo è vero per i divisori costanti che sono una potenza di 2, quando l'inverso è rappresentabile. Ho visto i compilatori applicare questa ottimizzazione (ad esempio, la divisione per 2,0 diventa moltiplicata con 0,5). Esiste una tecnica applicabile a una gamma più ampia di altri divisori costanti, come descritto in [questo documento] (http://perso.ens-lyon.fr/nicolas.brisebarre/Publi/fpdivision.pdf). Purtroppo, non ho visto nessun compilatore usarlo. – njuffa