Ich probiere gerade die schnelle Funktion Exp(x) aus, die zuvor in diese Antwort auf eine SO-Frage zur Verbesserung der Rechengeschwindigkeit in C#:
public static double Exp(double x)
{
var tmp = (long)(1512775 * x + 1072632447);
return BitConverter.Int64BitsToDouble(tmp << 32);
}
Der Ausdruck verwendet einige IEEE-Gleitkomma-"Tricks" und ist in erster Linie für die Verwendung in neuronalen Gruppen gedacht. Die Funktion ist etwa 5 Mal schneller als die reguläre Math.Exp(x)
Funktion.
Leider liegt die numerische Genauigkeit nur bei -4% bis +2% im Vergleich zur normalen Math.Exp(x)
Funktion möchte ich im Idealfall eine Genauigkeit im unteren Prozentbereich erreichen.
Ich habe den Quotienten zwischen der approximativen und der regulären Exp-Funktion aufgetragen, und wie in der Grafik zu sehen ist, scheint sich der relative Unterschied mit praktisch konstanter Häufigkeit zu wiederholen.
Ist es möglich, diese Regelmäßigkeit zu nutzen, um die Genauigkeit der Funktion "fast exp" weiter zu verbessern, ohne die Berechnungsgeschwindigkeit wesentlich zu verringern, oder würde der Rechenaufwand einer Genauigkeitsverbesserung den rechnerischen Gewinn des ursprünglichen Ausdrucks überwiegen?
(Nebenbei bemerkt, habe ich auch versucht eine der Alternativen Ansätze, die in der gleichen SO-Frage vorgeschlagen wurden, aber dieser Ansatz scheint in C# nicht rechnerisch effizient zu sein, zumindest nicht für den allgemeinen Fall).
UPDATE 14. MAI
Auf Anfrage von @Adriano habe ich nun einen sehr einfachen Benchmark durchgeführt. Ich habe 10 Millionen Berechnungen mit jeder der folgenden Alternativen durchgeführt exp Funktionen für Fließkommazahlen im Bereich [-100, 100]. Da der Wertebereich, an dem ich interessiert bin, von -20 bis 0 reicht, habe ich auch den Funktionswert bei x = -5 explizit aufgeführt. Hier sind die Ergebnisse:
Math.Exp: 62.525 ms, exp(-5) = 0.00673794699908547
Empty function: 13.769 ms
ExpNeural: 14.867 ms, exp(-5) = 0.00675211846828461
ExpSeries8: 15.121 ms, exp(-5) = 0.00641270968867667
ExpSeries16: 32.046 ms, exp(-5) = 0.00673666189488182
exp1: 15.062 ms, exp(-5) = -12.3333325982094
exp2: 15.090 ms, exp(-5) = 13.708332516253
exp3: 16.251 ms, exp(-5) = -12.3333325982094
exp4: 17.924 ms, exp(-5) = 728.368055056781
exp5: 20.972 ms, exp(-5) = -6.13293614238501
exp6: 24.212 ms, exp(-5) = 3.55518353166184
exp7: 29.092 ms, exp(-5) = -1.8271053775984
exp7 +/-: 38.482 ms, exp(-5) = 0.00695945286970704
ExpNeural ist gleichbedeutend mit dem Exp Funktion, die am Anfang dieses Textes beschrieben wird. ExpSerie8 es el Formulierung die ich ursprünglich als nicht sehr effizient unter .NET bezeichnet hatte; bei der Implementierung genau wie Neil war sie tatsächlich sehr schnell. ExpSerie16 ist die analoge Formel, aber mit 16 Multiplikationen anstelle von 8. exp1 über exp7 sind die verschiedenen Funktionen aus Adriano's Antwort unten. Die letzte Variante von exp7 ist eine Variante, bei der das Vorzeichen von x wird geprüft; bei negativem Ergebnis gibt die Funktion 1/exp(-x)
stattdessen.
Leider ist keiner der beiden expN Funktionen, die von Adriano sind in dem von mir in Betracht gezogenen breiteren negativen Wertebereich ausreichend. Der Ansatz der Reihenentwicklung von Neil Coffey scheint in "meinem" Wertebereich besser geeignet zu sein, obwohl er bei größeren negativen Werten zu schnell abweicht x , insbesondere wenn "nur" 8 Multiplikationen verwendet werden.