Efficace 10 à la puissance double
Je dois souvent élever 10 à la puissance du double.
Existe-t-il un moyen plus efficace de faire cela qu'avec la bibliothèque mathématique pow(10,double)? Si cela compte, mes doubles sont toujours négatifs entre -5 et -11.
Je suppose que pow (double, double) utilise un algorithme plus général que celui requis pour pow (10, double) et pourrait donc ne pas être la méthode la plus rapide. Compte tenu de certaines des réponses ci-dessous, cela aurait pu être une hypothèse incorrecte.
Quant au pourquoi, c'est pour l'interpolation logartihmique. J'ai une table de valeurs x et y. Mon objet a une valeur x connue (qui est presque toujours un double).
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]));
}
Cette fonction est souvent appelée. On m'a dit de me pencher sur le profilage, c'est donc ce que je ferai en premier.
On vient de me dire que j'aurais pu utiliser des logarithmes naturels au lieu de la base 10, ce qui est évidemment juste. (Ma stupidité m'étonne parfois même moi-même.)
Après avoir tout remplacé par des logarithmes naturels, tout fonctionne un peu plus vite. Avec le profilage (qui est un nouveau mot que j'ai appris aujourd'hui), j'ai découvert que 39% de mon code est dépensé dans la fonction exp, donc pour ceux qui se demandaient si c'était en fait cette partie qui bloquait mon code, c'était le cas.
Réponses
Oui, la fonction pow est lente (environ 50x le coût d'un multiplication, pour ceux qui demandent des repères).
Par une supercherie de log / exposants, nous pouvons exprimer 10 ^ x comme
10^x = exp(log(10^x)) = exp(x * log(10)).Vous pouvez donc implémenter 10 ^ x avec
exp(x * M_LN10), ce qui devrait être plus efficace que pow.Si la double précision n'est pas critique, utilisez la version flottante de la fonction
expf(oupowf), qui devrait être plus efficace que la version double.Si la précision approximative est correcte, précalculez une table sur la plage [-5, -11] et effectuez une recherche rapide avec interpolation linéaire.
Quelques benchmarks (utilisant la 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
Car pow(10.0, n)il devrait être plus rapide à définir c = log(10.0), que vous pouvez calculer une fois, puis utiliser exp(c*n), ce qui devrait être beaucoup plus rapide que pow(10.0, n)(qui fait fondamentalement la même chose en interne, sauf que ce serait calculer log(10.0)encore et encore au lieu d'une seule fois). Au-delà de cela, vous ne pouvez probablement pas faire grand-chose d'autre.