Effiziente 10 zum Power Double
Ich muss oft 10 auf die Kraft eines Doppelten erhöhen.
Gibt es einen effizienteren Weg, dies zu tun als mit der Mathematikbibliothek pow(10,double)? Wenn es darauf ankommt, sind meine Doppel zwischen -5 und -11 immer negativ.
Ich gehe davon aus, dass pow (double, double) einen allgemeineren Algorithmus verwendet als für pow (10, double) erforderlich und daher möglicherweise nicht die schnellste Methode ist. Angesichts einiger der folgenden Antworten könnte dies eine falsche Annahme gewesen sein.
Das Warum ist für die logartihmische Interpolation. Ich habe eine Tabelle mit x- und y-Werten. Mein Objekt hat einen bekannten x-Wert (der fast immer ein Doppelwert ist).
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]));
}
Diese Funktion wird häufig aufgerufen. Mir wurde gesagt, ich solle mich mit der Profilerstellung befassen, also werde ich das zuerst tun.
Mir wurde gerade gesagt, ich hätte natürliche Logarithmen anstelle von Basis 10 verwenden können, was offensichtlich richtig ist. (Meine Dummheit überrascht manchmal sogar mich selbst.)
Nachdem alles durch natürliche Logarithmen ersetzt wurde, läuft alles etwas schneller. Bei der Profilerstellung (ein neues Wort, das ich heute gelernt habe) stellte ich fest, dass 39% meines Codes in der exp-Funktion ausgegeben werden. Für diejenigen, die sich fragten, ob es tatsächlich dieser Teil war, der meinen Code zum Engpass machte, war dies der Fall.
Antworten
Ja, die Pow-Funktion ist langsam (ungefähr das 50-fache der Kosten einer Multiplikation für diejenigen, die nach Benchmarks fragen).
Durch einige log / Exponenten-Tricks können wir 10 ^ x als ausdrücken
10^x = exp(log(10^x)) = exp(x * log(10)).Sie können also 10 ^ x mit implementieren
exp(x * M_LN10), was effizienter sein sollte als pow.Wenn die doppelte Genauigkeit nicht kritisch ist, verwenden Sie die Float-Version der Funktion
expf(oderpowf), die effizienter sein sollte als die doppelte Version.Wenn die grobe Genauigkeit in Ordnung ist, berechnen Sie eine Tabelle über den Bereich [-5, -11] vor und führen Sie eine schnelle Suche mit linearer Interpolation durch.
Einige Benchmarks (mit 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
Denn pow(10.0, n)es sollte schneller zu setzen sein c = log(10.0), was Sie einmal berechnen können, und dann verwenden exp(c*n), was deutlich schneller sein sollte als pow(10.0, n)(was im Grunde genommen intern dasselbe tut, außer dass es log(10.0)immer und nicht nur einmal berechnet wird ). Darüber hinaus können Sie wahrscheinlich nicht viel anderes tun.