Efficiente 10 alla potenza doppia
Devo aumentare 10 volte la potenza di un doppio molte volte.
Esiste un modo più efficiente per farlo rispetto alla libreria matematica pow(10,double)? Se conta, i miei doppi sono sempre negativi tra -5 e -11.
Presumo che pow (double, double) utilizzi un algoritmo più generale di quello richiesto per pow (10, double) e potrebbe quindi non essere il metodo più veloce. Date alcune delle risposte di seguito, potrebbe essere stata un'ipotesi errata.
Quanto al perché, è per l'interpolazione logaritmica. Ho una tabella di valori x e y. Il mio oggetto ha un valore x noto (che è quasi sempre un doppio).
double Dbeta(struct Data *diffusion, double per){
double frac;
while(per>diffusion->x[i]){
i++;
}
frac = (per-diffusion->x[i-1])/(diffusion->x[i]-diffusion->x[i-1]);
return pow(10,log10DB[i-1] + frac * (log10DB[i]-log10DB[i-1]));
}
Questa funzione viene chiamata molte volte. Mi è stato detto di esaminare il profilo, quindi è quello che farò prima.
Mi è stato appena detto che avrei potuto usare logaritmi naturali invece di base 10, il che è ovviamente giusto. (la mia stupidità a volte stupisce anche me stesso.)
Dopo aver sostituito tutto con logaritmi naturali, tutto funziona un po 'più velocemente. Con la profilazione (che è una nuova parola che ho imparato oggi) ho scoperto che il 39% del mio codice viene speso nella funzione exp, quindi per coloro che si chiedevano se fosse in realtà questa parte a strozzare il mio codice, lo era.
Risposte
Sì, la funzione pow è lenta (circa 50 volte il costo di un moltiplicatore, per chi richiede benchmark).
Con qualche trucco di log / esponenti, possiamo esprimere 10 ^ x come
10^x = exp(log(10^x)) = exp(x * log(10)).Quindi puoi implementare 10 ^ x con
exp(x * M_LN10), che dovrebbe essere più efficiente di pow.Se la doppia precisione non è critica, usa la versione float della funzione
expf(opowf), che dovrebbe essere più efficiente della doppia versione.Se l'accuratezza approssimativa è OK, calcola anticipatamente una tabella nell'intervallo [-5, -11] ed esegui una rapida ricerca con l'interpolazione lineare.
Alcuni benchmark (utilizzando glibc 2.31):
Benchmark Time
---------------------------------
pow(10, x) 15.54 ns
powf(10, x) 7.18 ns
expf(x * (float)M_LN10) 3.45 ns
Perché pow(10.0, n)dovrebbe essere più veloce da impostare c = log(10.0), che puoi calcolare una volta, quindi usare exp(c*n), che dovrebbe essere significativamente più veloce di pow(10.0, n)(che fondamentalmente sta facendo la stessa cosa internamente, tranne che sarebbe il calcolo log(10.0)più e più volte invece che solo una volta). Oltre a ciò, probabilmente non c'è molto altro che puoi fare.