Ich versuche, die schnell Exp (x) Funktion aus, die zuvor in this Antwort auf eine Frage SO auf die Verbesserung der Rechengeschwindigkeit in C# beschrieben wurde:Fast Exp-Berechnung: möglich, um die Genauigkeit zu verbessern, ohne zu viel Leistung zu verlieren?
public static double Exp(double x)
{
var tmp = (long)(1512775 * x + 1072632447);
return BitConverter.Int64BitsToDouble(tmp << 32);
}
Der Ausdruck wird mit einigen IEEE Floating-Point „Tricks“ und ist hauptsächlich für den Einsatz in neuralen Sets vorgesehen. Die Funktion ist ca. 5 mal schneller als die normale Math.Exp(x)
Funktion.
Leider ist die numerische Genauigkeit nur -4% - + 2% relativ zur regulären Math.Exp(x)
Funktion, idealerweise hätte ich gerne eine Genauigkeit innerhalb von mindestens dem Sub-Prozent-Bereich.
Ich habe den Quotienten zwischen den approximierten und den regulären Exp-Funktionen aufgetragen, und wie in der Grafik zu sehen ist, scheint der relative Unterschied mit praktisch konstanter Frequenz wiederholt zu werden.
Ist es möglich, die Vorteile dieser Regelmäßigkeit, um die Richtigkeit der „schnellen exp“ Funktion weiter ohne wesentliche Verringerung der Rechengeschwindigkeit, oder würde der Rechenaufwand einer Genauigkeit Verbesserung schwerer wiegen als die rechnerische Gewinn zu verbessern des ursprünglichen Ausdrucks?
(Als Randbemerkung, habe ich versucht, auch one of the alternative in der gleichen Frage SO vorgeschlagenen Ansätze, aber dieser Ansatz scheint nicht rechnerisch in C# effizient zu sein, zumindest nicht für den allgemeinen Fall.)
UPDATE MAI 14
Auf Anfrage von @Adriano, habe ich jetzt einen sehr einfachen Benchmark durchgeführt. Ich habe 10 Millionen Berechnungen mit jeder der exp Funktionen für Fließkommawerte im Bereich [-100, 100] durchgeführt. Da der Bereich der Werte, die mich interessieren, von -20 bis 0 reicht, habe ich auch explizit den Funktionswert bei x = -5 aufgelistet. 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 entspricht der Exp Funktion am Anfang dieses Textes angegeben. ExpSeries8 ist die formulation, die ich ursprünglich behauptete, war nicht sehr effizient auf .NET; Bei der Implementierung wie Neil war es tatsächlich sehr schnell. ExpSeries16 ist die analoge Formel aber mit 16 Multiplikationen statt 8. exp1 bis exp7 sind die verschiedenen Funktionen von Adriano Antwort unten. Die letzte Variante exp7 ist eine Variante, bei der das Vorzeichen x geprüft wird; Wenn negativ, gibt die Funktion stattdessen 1/exp(-x)
zurück.
Leider sind keine der expN Funktionen, die von Adriano aufgeführt werden, in dem breiteren negativen Wertebereich, den ich in Betracht ziehe, ausreichend. Der Serienexpansionsansatz von Neil Coffey scheint in "meinem" Wertebereich besser geeignet zu sein, obwohl er bei größeren negativen Multiplikationen zu schnell divergiert, insbesondere wenn "nur" 8 Multiplikationen verwendet werden.
Ich bin neugierig auf Ihre Bezugnahme auf "neuralen Sets." Zur Zeit simuliere ich ein neuronales Netzwerk mit C++ und dem selben 'exp'-Leistungsengpass, mit dem Sie konfrontiert wurden. Gibt es Arbeiten innerhalb der Computational Neuroscience, die ungefähre exp-Funktionen vorgeschlagen haben, die sehr schnell sind? – dbliss