J'aimerais approfondir la fonction est-il possible de le faire en utilisant une approche basée sur plusieurs splines? I.e entre x 1 sub> strud> et x 2 sub> strong>, puis p>
alors p>
etc p>
Ceci est destiné au matériel de FPGA dédié et non à une CPU à usage général. En tant que tel, j'ai besoin de créer moi-même la fonction. La précision est beaucoup moins préoccupante. De plus, je ne peux pas vraiment me permettre plus d'un circuit de multiplication et / ou plusieurs équipes / advecteurs multiples. De plus, je veux quelque chose de beaucoup plus petit qu'une fonction cordique, la taille est critique. P>
10 Réponses :
Wolfram présente quelques bonnes façons de l'approcher en termes de série, etc.: p>
Page Wikipedias sur Série Taylor montre également un exemple d'expansion de E x sup> autour de 0: p>
p>
"Représentations alternatives: E ^ x = z ^ x pour e = z": D
ou vous pouvez simplement faire (comme David pointe dans les commentaires, Avez-vous un cas d'utilisation où le calcul de e x sup> em> est un goulot d'étranglement éprouvé? Sinon, vous devez d'abord coder pour la lisibilité; Essayez uniquement ces types d'optimisations si l'approche évidente est trop lente. P> pow (m_e, x) code> dans C. (certaines plates-formes n'ont pas
m_e code> définie; sur ceux-ci, vous devrez peut-être spécifier manuellement La valeur de e em>, qui est environ
2.71828182845904523536028747135266249775724709369995 code>.) P>
exp (x) code> serait plus efficace que
pow (m_e, x) code>. Encore une fois, le cerveau n'est pas encore activé. ) p>
pow (m_e, x) code>? Sérieusement?
POW (A, B) CODE> est généralement implémenté comme
exp (b * journal (a)) code>. Utilisation de
POW code> est une bosse de vitesse, pas une vitesse de vitesse.
C'était un peu mon point - écrivez le code correctement en premier, alors i> examine la performance de celui-ci. Nulle part dans la question initiale n'est indiqué que cela s'appelle un million de fois une seconde ou quelque chose comme ça, donc ce n'est pas immédiatement évident que la performance sera une question.
Quelle que soit la performance, exp (x) code> est une solution plus simple (et plus portable!) Que
pow (m_e, x) code>. Même si
pow () code> était plus rapide, le recours plutôt que
exp () code> serait une optimisation prématurée.
Très vrai, et j'ai mis à jour ma réponse pour refléter la correction de David. Pouvez-vous dire que je n'ai pas encore eu assez de café? :)
si si E f sup> Ceci provient de l'expansion de la série de puissance (optimisée) de Ce Math.StaCKExchange question contient quelques réponses intelligentes supplémentaires. P>
Edit: Notez qu'il existe un moyen plus rapide de calculer x code> est un entier, vous pouvez simplement multiplier
E code> à nouveau encore et encore. P>
x code> n'est pas un entier, vous pouvez calculer le sol
1 + f / 2 (1 + f / 4 (1 + f / 4))) code>, où f em> est la partie fractionnée de x p>
blockQuote>
x code>. Si vous avez besoin de plus de précision, passez simplement plus de termes à la série. P>
La meilleure solution à la solution entières n'est pas cette solution O (n). Un algorithme de division et de conquérir (PRE) calcule e ^ 1, e ^ 2, E ^ 4, E ^ 2, etc. Vous prenez ensuite les facteurs correspondant aux bits dans x code>. C'est O (logn). C'est à dire. Pour x = 255, cela ne prend que 8 multiplications au lieu de 254.
Merci - mais je cherche à minimiser les opérations de multiplication, je veux seulement une opération de multiplication
Mais pourquoi i>? Êtes-vous en fait i> Voir des problèmes de performance ou cette optimisation prématurée?
@Jonathan - ce n'est pas pour une CPU, c'est pour le matériel dédié. J'ai mis à jour ma question ci-dessus pour clarifier cela. Désolé pour la confusion
@Jonathan parce que d'avoir une fonction exponentielle O (n) conduira évidemment à une mauvaise performance. L'optimisation prématurée n'est pas mauvaise sur un niveau de systèmes.
C'était exactement ce que je devais faire une version entière mathématique de E ^ x
Bien sûr, il est "possible". Il y a plusieurs problèmes.
Quelle est votre exigence pour la précision? P> LI>
Êtes-vous prêt à utiliser des splines d'ordre supérieur? p> li>
Combien de mémoire êtes-vous prêt à dépenser à ce sujet? La fonction linéaire sur de petits intervalles suffisamment est approximative de la fonction exponentielle à tout degré de précision nécessaire, mais elle peut nécessiter un très petit intervalle. P> Li> OL>
EDIT: P>
Compte tenu des informations supplémentaires fournies, j'ai exécuté un test rapide. La réduction de la plage peut toujours être utilisée sur la fonction exponentielle. Ainsi, si je souhaite calculer exp (x) pour tout X, je peux réécrire le problème dans la forme ... p> où xi est la partie entière de x et XF est la partie fractionnée. La partie entière est simple. Calculez XI sous forme binaire, puis des carings répétés et des multiplications vous permettent de calculer Exp (XI) dans relativement peu d'opérations. (D'autres astuces, utilisant des pouvoirs de 2 et d'autres intervalles peuvent vous donner encore plus de vitesse pour la vitesse affamée.) P> Tout ce qui reste est maintenant de calculer exp (XF). Pouvons-nous utiliser une spline avec des segments linéaires pour calculer Exp (XF), sur l'intervalle [0,1] avec seulement 4 segments linéaires, à une précision de 0,005? P> Cette dernière question est résolue par une fonction Que j'ai écrit il y a quelques années, cela se rapprochera d'une fonction avec une spline d'une commande donnée, à l'intérieur d'une tolérance fixe sur l'erreur maximale. Ce code a nécessité 8 segments sur l'intervalle [0,1] pour atteindre la tolérance requise avec une fonction de spline linéaire par morceaux. Si j'ai choisi de réduire l'intervalle plus loin à [0,0,5], je pouvais maintenant atteindre la tolérance prescrite. P> Donc, la réponse est simple. Si vous êtes prêt à effectuer les réductions de la plage pour réduire x à l'intervalle [0.0.5], faites les calculs appropriés, alors oui, vous pouvez obtenir la précision demandée avec une spline linéaire dans 4 segments. P> En fin de compte, vous ferez toujours mieux d'utiliser une fonction exponentielle codée durement. Toutes les opérations mentionnées ci-dessus seront sûrement plus lentes que ce que votre compilateur fournira, si exp (x) est disponible. P> p>
Merci beaucoup pour la réponse détaillée. À la nouvelle réflexion, je peux tolérer des marges d'erreur beaucoup plus élevées, probablement autant que 0,05, et peut-être même 0,1. J'ai utilisé des splines avec une réduction de la plage avant d'autres fonctions, mais dans ce cas, je pense que la réponse de Lucas ci-dessus est encore plus appropriée pour la réalisation de précision inférieure. Le point clé est également qu'il n'ya aucune implémentation directe dans le matériel "compilateur" pour une fonction exponentielle. c'est-à-dire que je ne travaille pas sur une CPU
Tout d'abord, qu'est-ce qui motive cette approximation? En d'autres termes, qu'est-ce qui ne va pas avec le simple qui dit, une implémentation typique de Voici le kicker: Peu importe ce que vous faites, les chances sont très élevées que votre fonction sera beaucoup, beaucoup plus lente que simplement appeler exp (x) code>? P>
exp (x) code> est de p>
K code> et le numéro de point flottant
r code> tel que
x = k * journal (2) + r code> et
r code> est compris entre -0,5 * journal (2) et 0,5 * journal (2). li>
exp (x) code> est 2 k sup> *
exp (r) code>. li>.
exp (x) code> utilisent un algorithme de type REMES pour proposer un polynôme minimax qui se rapproche
exp (R) code>. Li>.
exp () code>. La plupart des fonctionnalités de
exp () code> sont implémentées dans le coprocesseur mathématique de votre ordinateur. Ré-implémentation de cette fonctionnalité dans des logiciels, même avec une précision réduite, une ordonnance de grandeur est plus lente que d'utiliser
exp () code>. P>
Remez * et la plupart utilisent réellement une approximation de pain centrée sur la liaison de sorte que l'erreur sur cette plage est aussi petite que possible. L'erreur d'une entrée donnée x code> est égale à l'erreur limitée multipliée par
2 ^ k code> qui détruit généralement la plupart de ces approximations lorsque l'entrée est grande ... je crois que «La mise en œuvre effective utilise à la fois l'approximation de la pente et une méthode de recherche de racines d'amélioration itérative de fonction inverse soustrayée de l'entrée.
Pourquoi r code> réside entre
-0.5log (2) code> et
0.5log (2) code> pas
(0, 1) code >?
Que diriez-vous d'une stratégie comme celle-ci qui utilise la formule p>
E x sup> = 2 x / ln (2) sup> p> blockQuote>
- Precalculate
1 / ln (2) code> li>
- Multipliez cette constante par votre argument (1 multiplication) li>
- Utilisez des changements binaires pour augmenter 2 à la partie entière de la puissance (suppose exp + Mantissa Format) LI>
- Réglez en fonction de la puissance fractionnée du reste-2 (probablement une seconde multiplication) li> ol>
Je me rends compte que ce n'est pas une solution complète, mais elle ne nécessite qu'une seule multiplication et réduit le problème restant pour rapprocher d'une puissance fractionnée de 2, ce qui devrait être plus facile à mettre en œuvre dans du matériel. P>
En outre, si votre application est suffisamment spécialisée, vous pouvez essayer de ré-dériver tout le code numérique qui fonctionnera sur votre matériel pour être dans un système de numéros de base- E EM> et de mettre en œuvre votre flottant Quincaillerie ponctuelle pour travailler dans la base e em> aussi. Alors aucune conversion n'est nécessaire du tout. P>
Merci Lucas - C'est parfait pour mes besoins, encore mieux que j'aurais pu espérer. Merci beaucoup!
Heureux d'entendre. On dirait que vous avez des compromis de design intéressants.
@Ttrican Il existe un bon papier sur la mise en œuvre de cette identité et de cette réduction pour obtenir une précision raisonnable pour un point flottant de précision unique à l'aide de tables de recherche et d'arithmétique à point fixe: LORIA.FR/~DETEDYJE/Publications/detdin_fpt_2005.pdf
Lien alternatif vers le PDF: perso.citi-lab.fr/ FDEINEC / RECHERCHE / Publis / 2005-FPT.PDF
http: //martin.anklerl. COM / 2007/02/11 / optimisé-exponentiel-fonctions-for-java /
Utilisation de la méthode de Schrauudolphe ( http://nnic.schrauudolph.org/pubs/schrauudolph99.pdfle >)
en Java: et
https://math.stackexchange.com/a/56064 (cherchez un approximant de pain). P> p>
Merci @jdberton pour ajouter cela et les liens. L'approche semble assez intéressante, mais êtes-vous sûr que l'extrait de code ci-dessus est correct? Je l'ai essayé pour certaines valeurs et le résultat ne semble pas être proche de près?
Je pense que cela serait inexact pour les grandes valeurs. Vous pouvez probablement trouver un meilleur approximateur de pain avec quelques travaux pour obtenir une meilleure gamme. Cela fonctionne pour moi parce que je n'ai besoin de rien exactement.
La méthode Schrauudolphs est parfaite. Je ne pense pas que cela puisse obtenir plus vite si la précision est acceptable. Dans son article, il détermine l'erreur relative moyenne d'être d'environ 4%. Source: Nic.schrauudolph.org/pubs/schrauudolph99.pdf
Voici une implémentation plus moderne de la méthode de Schrauudolph, en utilisant un float à point unique au lieu de double (qui est un gaspillage, car seuls les 32 bits supérieurs du double sont écrits). MachineDlearnings.com/2011/06/...
Ce n'est pas approprié pour la FPGA personnalisée, mais il convient de mentionner. P>
http://www.machinedlearnings.com/2011/ 06 / Fast-approximatif-logarithm-exponentiel.html p>
et le code source: p>
Ce n'est pas l'interpolation de spline lisse que vous avez demandée, mais son efficacité de calcul:
float expf_fast(float x) { union { float f; int i; } y; y.i = (int)(x * 0xB5645F + 0x3F7893F5); return (y.f); }
Pour le matériel, j'ai une solution géniale pour vous si vous en avez besoin pour être précis au bit. (Sinon faire une approximation comme ci-dessus). L'identité est exp (x) = Cosh (x) + sinh (x), le sinus hyperbolique et le cosinus. La capture est que le sinus et le cosinus hyperboliques peuvent être calculés à l'aide de la technique coricienne, et le meilleur de tous, ils sont l'une des fonctions cordicales rapides, ce qui signifie qu'ils semblent presque comme se multiplier au lieu de diviser presque comme une division! P>
Qui signifie pour sur la zone d'un multiplicateur de tableau, vous pouvez calculer l'exposant à une précision arbitraire en seulement 2 cycles! P>
Rechercher la méthode cordique - c'est incroyable pour la mise en œuvre du matériel. P>
Une autre approche matérielle utilise une petite table associée à une formule d'autres personnes mentionnées: exp (x + y) = exp (x) * exp (Y). Vous pouvez casser le numéro dans de petits champs - dire 4 ou 8 bits à la fois - et recherchez simplement l'exposant pour ce bitfield. Probablement seulement efficace pour des calculs étroits, mais c'est une autre approche. P>
Quelle gamme de valeurs x envisagez-vous de se rapprocher de cela?
Réponse par défaut: Série Power
Vous avez
exp () code> fonction dans la norme C ++. Pourquoi évitez-vous d'utiliser? Habituellement, il a une bonne vitesse.
Les approximations récursives ne conviennent pas à mon application. La plage maximale potentielle est comprise entre 0 et 4095, mais elle peut être mise à l'échelle à une valeur inférieure. Mon hunch est que j'ai besoin d'environ 4 à 6 bits de précision
Mon application n'est pas réellement C ou C ++, son matériel dédié, alors je roule moi-même. La fonction de puissance est agréable, mais je préférerais quelque chose avec moins d'opérations.
@ user786653: Certainement pas une série de puissance. C'est une définition de mathématiques théoriques, pas une définition de mathématiques numérique. La même page a plus de formules pratiques, par exemple Continuation des fractions
C'est plus ou moins un. Dans certains cas, beaucoup plus ou moins :) Désolé, une vieille blague de mathématiques.
Juste pour clarifier en fonction de l'instruction
0-4095 CODE>: c'est entier? Parce que l'algorithme d'entier x est trivial; Il suffit de stocker e ^ 1..e ^ 2048 et multipliez selon les bits de x. 11 multiplications pires cas.
Merci Msalter - Oui, la plage est entière, mais la solution contient environ 10 multiplications trop nombreuses
Voir Math .stackexchange.com / Questions / 55830 / ...
@trican: re "Mais la solution contient environ 10 multiplications trop nombreuses": Tout d'abord, cela ressemble beaucoup à l'optimisation prématurée. Deuxièmement, votre utilisation proposée des splines sera encore plus chère. Troisièmement, 0 à 4095?
EXP (4095) CODE> est un très grand nombre. Enfin, voir NetLib.org/fdlibm/e_exp.c .
Merci pour la réponse David, j'aimerais que c'était une optimisation prématurée - mais il n'ya pas de mise en œuvre de fonctions exponentielles dans des descriptions matérielles telles que Verilog ou VHDL pour FPGAS / ASICS. De plus, la petite taille et la puissance inférieure sont absolument critiques dans mon cas et je disposerai de négocier une précision pour cela.
Nous avons vraiment besoin de la plage et de la précision de l'entrée et B> la précision de la sortie. Q12.0 pour l'entrée donne Q400 + pour la sortie. Ce sont des signaux extrêmement larges pour traiter avec une FPGA.
@ ADAM12, dans mes scénarios - x sera négatif, ce qui signifie que la sortie est liée entre 0 et 1 - afin que je puisse confortablement à gérer cela.