Le moyen le plus efficace de la mise en œuvre de fonction pow() en virgule flottante
Je suis en train de mettre en œuvre ma propre version de pow() et sqrt() comme à mon habitude de bibliothèque n'a pas pow()/sqrt() de virgule flottante de soutien.
Oui, le Soleil peut (Oracle maintenant, je suppose):
fdlibm, la "librement distribuable de la bibliothèque math", a sqrt et pow, ainsi que de nombreuses autres fonctions mathématiques.
Ils sont assez high-tech implémentations, bien que, et bien sûr rien n'est jamais le "plus efficace" de la mise en œuvre de quelque chose comme cela. Êtes-vous après le code source, ou êtes-vous plus vraiment à la recherche pour pow et sqrt, mais en réalité la recherche d'une éducation en floating-point des algorithmes de programmation?
Tout d'abord pour trouver une meilleure source code avec une bonne précision et d'autre part à réellement me renseigner sur ce sujet. Pour la dernière, je crois que vous avez vraiment besoin d'un bon livre, il ya seulement tellement que vous pouvez obtenir à regarder le code source, surtout quand il est principalement composé de numéros de magie et coin-cas. Je crains que ce n'est pas un domaine que je suis forte, cependant: je recommande fdlibm uniquement parce que je sais qu'il fonctionne assez bien, pas parce que j'ai fait de comprendre la source. La plupart d'entre nous peut faire quelque chose à mi-chemin intelligent avec un développement en série de Taylor de mettre en œuvre une fonction, mais de trouver une manière très rapide pour calculer cette fonction va prendre de connaissances spécialisées, et peut varier en fonction de la plate-forme. Vous êtes probablement mieux de prendre quelqu'un d'autre source et en cours d'exécution. fdlibm est un excellent point de départ. Ce n'est pas la manière la plus rapide de mise en œuvre sur une plate-forme, mais il est portable et assez bon pour la plupart des besoins. Si vous voulez le plus efficace de mise en œuvre sur une plate-forme donnée, vous aurez besoin de passer quelques années à apprendre à propos de la micro-architecture de votre plate-forme cible, puis quelques années de plus, l'apprentissage de bas niveau numerics -- ou embaucher quelqu'un qui a déjà fait =) Le code pour le rapprochement avec un développement en série de taylor des expansions sont plus lents que d'autres approximations...
Sûr - c'est facile si vous avez exponentielle et logarithme naturel des fonctions.
Depuis y = x^n, vous pouvez prendre le logarithme naturel des deux côtés:
ln(y)= n*ln(x)
Puis en prenant l'exponentielle des deux côtés vous donne ce que vous voulez:
y = exp(n*ln(x))
Si vous voulez quelque chose de mieux, le meilleur endroit que je connaisse pour look est Abramowitz et Stegun.
Et si vous n'avez pas exponentielle et les fonctions de journalisation, vous pouvez utiliser un développement en série de Taylor de l'approximation. Mais je ne suis pas sûr si c'est le "plus efficace"... Pour x > 0, de toute façon. Avec l'entrée négative pas tellement. Même pour x > 0, vous allez perdre de la précision de cette façon, par rapport à un système sophistiqué spécialisé de la mise en œuvre telle que celle trouvée dans fdlibm. rlbond: un développement en série de Taylor est une mauvaise idée. Polynômes de tchebychev sont probablement mieux. Plus au point, exp(y log x) offre beaucoup moins de précision que ne le fait une bonne mise en œuvre de pow(x,y). Cela peut être acceptable pour vous, ou il ne peut pas.
Notez que si votre jeu d'instruction est une instruction pour la racine carrée ou la puissance, vous allez être beaucoup mieux l'aide de cette. Le x87 instructions en virgule flottante, par exemple, ont une instruction fsqrt, et le SSE2 ajouts comprennent une autre instruction sqrtsd, qui sont probablement va être beaucoup plus rapide que la plupart des solutions écrit en C. En effet, au moins gcc utilise les deux instructions lors de la compilation a lieu sur une machine x86.
De pouvoir, cependant, les choses deviennent un peu glauque. Il y a une instruction dans le x87 instruction à virgule flottante qui peut être utilisé pour calculer n*log2(n), à savoir fyl2x. Une autre instruction, fldl2e, magasins log2(e) en virgule flottante, la pile. Vous pourriez vouloir donner à ces un look.
Vous pouvez également jeter un oeil à la façon dont chaque C des bibliothèques de le faire. dietlibc, par exemple, utilise simplement fsqrt:
sqrt:
fldl 4(%esp)
fsqrt
ret
glibc utilise du Soleil de mise en œuvre pour les machines sur lesquelles un matériel de la racine carrée d'instruction n'est pas disponible (sous sysdeps/ieee754/flt-32/e-sqrtf.c), et utilise fsqrt sur le jeu d'instructions x86 (bien que gcc peut être invité à utiliser à la place la sqrtsd l'instruction.)
double ipow(intbase,int exp){bool flag=0;if(exp<0){flag=1;exp*=-1;}int result =1;while(exp){if(exp &1)
result *=base;
exp >>=1;base*=base;}if(flag==0)return result;elsereturn(1.0/result);}//most suitable way to implement power function for integer to power integer
Pour le calcul de la racine carrée d'un float en C je vous recommande d'utiliser fsqrt si vous cible x86.
Vous pouvez utiliser ces ASM avec l'instruction:
asm("fsqrt":"+t"(myfloat));
Pour GCC ou
asm{
fstp myfloat
fsqrt
fldp myfloat
}
Ou quelque chose comme ça pour Visual Studio.
Pour la mise en œuvre de pow, à l'aide d'une grande instruction switch comme celle de upitasoft.com/link/powLUT.h devrait le faire.
Il peut causer des problèmes de cache, mais si vous continuez comme ça, il ne devrait pas être un problème, il suffit de limiter la plage (remarque, vous pouvez encore optimiser le code que j'ai fourni).
Si vous voulez soutenir virgule flottante pouvoirs, est beaucoup plus difficile...
Vous pouvez essayer d'utiliser le logarithme népérien et exponentielle fonctions, telles que:
Le moyen le plus rapide, je pense, de faire un pow() serait le long de ces lignes (remarque, c'est assez compliqué):
//raise x^ydouble pow(double x,int y){int power;
map<int,double> powers;for(power =1; power < y; power *=2, x *= x)
powers.insert(power, x);while(power > y){//figure out how to get there
map<int,double>::iterator p = powers.lower_bound(power - y);//p is an iterator that points to the biggest power we have that doesn't go over power - y
power -= p->first;
x /= p->second;}return x;}
Je n'ai aucune idée sur la façon de mettre en œuvre une virgule pouvoir. Ma meilleure supposition serait d'utiliser les logarithmes.
Edit: je suis d'essayer logarithmique solution (basé sur y), par opposition à un linéaire de la solution que vous proposez. Permettez-moi de faire ce travail et de le modifier, parce que je sais que ça fonctionne.
Edit 2: Héhé, mon mauvais. d'alimentation *= 2 au lieu de pouvoir++
L'aspect pratique de cet algorithme de côté, comme l'a écrit ça ne fonctionne pas. Considérons un cas simple, x = 2, y = 3. puissance = 1, x = 4. puissance = 2, x = 8. puissance = 3, x = 16. puissance == y, donc la première boucle s'arrête. la puissance est toujours == y, donc la deuxième boucle ne fait rien. x == 16, mais 2^3 == 8. De plus, le seul moment de la seconde boucle serait jamais faire quoi que ce soit est si y < 0; je vais le laisser, pourquoi c'est une catastrophe comme un exercice pour le lecteur. Erp, mon résumé est faux. Vous êtes à la quadrature x chaque itération, plutôt que de multiplier par votre valeur d'origine. x -> xx -> xxxx lorsque vous voulez x -> xx -> xx*x. Mais comme je l'ai dit, votre deuxième boucle [et, par extension, l'ensemble de la carte vous construisez] est complètement inutile, parce que votre première boucle se termine lorsque l'alimentation == y, sauf si y est négatif. construire/remplir/utilisation/détruire une carte dans l'un des plus fréquemment appelée fonction est une des activités douteuses.
Oui, le Soleil peut (Oracle maintenant, je suppose):
fdlibm, la "librement distribuable de la bibliothèque math", a sqrt et pow, ainsi que de nombreuses autres fonctions mathématiques.
Ils sont assez high-tech implémentations, bien que, et bien sûr rien n'est jamais le "plus efficace" de la mise en œuvre de quelque chose comme cela. Êtes-vous après le code source, ou êtes-vous plus vraiment à la recherche pour
pow
etsqrt
, mais en réalité la recherche d'une éducation en floating-point des algorithmes de programmation?Pour la dernière, je crois que vous avez vraiment besoin d'un bon livre, il ya seulement tellement que vous pouvez obtenir à regarder le code source, surtout quand il est principalement composé de numéros de magie et coin-cas. Je crains que ce n'est pas un domaine que je suis forte, cependant: je recommande fdlibm uniquement parce que je sais qu'il fonctionne assez bien, pas parce que j'ai fait de comprendre la source.
La plupart d'entre nous peut faire quelque chose à mi-chemin intelligent avec un développement en série de Taylor de mettre en œuvre une fonction, mais de trouver une manière très rapide pour calculer cette fonction va prendre de connaissances spécialisées, et peut varier en fonction de la plate-forme. Vous êtes probablement mieux de prendre quelqu'un d'autre source et en cours d'exécution.
fdlibm
est un excellent point de départ. Ce n'est pas la manière la plus rapide de mise en œuvre sur une plate-forme, mais il est portable et assez bon pour la plupart des besoins. Si vous voulez le plus efficace de mise en œuvre sur une plate-forme donnée, vous aurez besoin de passer quelques années à apprendre à propos de la micro-architecture de votre plate-forme cible, puis quelques années de plus, l'apprentissage de bas niveau numerics -- ou embaucher quelqu'un qui a déjà fait =)Le code pour le rapprochement avec un développement en série de taylor des expansions sont plus lents que d'autres approximations...
OriginalL'auteur Steve Jessop
Sûr - c'est facile si vous avez exponentielle et logarithme naturel des fonctions.
Depuis
y = x^n
, vous pouvez prendre le logarithme naturel des deux côtés:Puis en prenant l'exponentielle des deux côtés vous donne ce que vous voulez:
Si vous voulez quelque chose de mieux, le meilleur endroit que je connaisse pour look est Abramowitz et Stegun.
Pour x > 0, de toute façon. Avec l'entrée négative pas tellement.
Même pour x > 0, vous allez perdre de la précision de cette façon, par rapport à un système sophistiqué spécialisé de la mise en œuvre telle que celle trouvée dans fdlibm.
rlbond: un développement en série de Taylor est une mauvaise idée. Polynômes de tchebychev sont probablement mieux.
Plus au point,
exp(y log x)
offre beaucoup moins de précision que ne le fait une bonne mise en œuvre depow(x,y)
. Cela peut être acceptable pour vous, ou il ne peut pas.OriginalL'auteur duffymo
Notez que si votre jeu d'instruction est une instruction pour la racine carrée ou la puissance, vous allez être beaucoup mieux l'aide de cette. Le x87 instructions en virgule flottante, par exemple, ont une instruction
fsqrt
, et le SSE2 ajouts comprennent une autre instructionsqrtsd
, qui sont probablement va être beaucoup plus rapide que la plupart des solutions écrit en C. En effet, au moins gcc utilise les deux instructions lors de la compilation a lieu sur une machine x86.De pouvoir, cependant, les choses deviennent un peu glauque. Il y a une instruction dans le x87 instruction à virgule flottante qui peut être utilisé pour calculer n*log2(n), à savoir
fyl2x
. Une autre instruction,fldl2e
, magasins log2(e) en virgule flottante, la pile. Vous pourriez vouloir donner à ces un look.Vous pouvez également jeter un oeil à la façon dont chaque C des bibliothèques de le faire.
dietlibc
, par exemple, utilise simplementfsqrt
:glibc
utilise du Soleil de mise en œuvre pour les machines sur lesquelles un matériel de la racine carrée d'instruction n'est pas disponible (soussysdeps/ieee754/flt-32/e-sqrtf.c
), et utilisefsqrt
sur le jeu d'instructions x86 (bien que gcc peut être invité à utiliser à la place lasqrtsd
l'instruction.)OriginalL'auteur susmits
Racine carrée est correctement mis en œuvre avec un processus itératif de Newton la méthode.
OriginalL'auteur John Gordon
OriginalL'auteur Shivendra
Pour le calcul de la racine carrée d'un float en C je vous recommande d'utiliser
fsqrt
si vous cible x86.Vous pouvez utiliser ces ASM avec l'instruction:
Pour GCC ou
}
Ou quelque chose comme ça pour Visual Studio.
Pour la mise en œuvre de pow, à l'aide d'une grande instruction switch comme celle de upitasoft.com/link/powLUT.h devrait le faire.
Il peut causer des problèmes de cache, mais si vous continuez comme ça, il ne devrait pas être un problème, il suffit de limiter la plage (remarque, vous pouvez encore optimiser le code que j'ai fourni).
Si vous voulez soutenir virgule flottante pouvoirs, est beaucoup plus difficile...
Vous pouvez essayer d'utiliser le logarithme népérien et exponentielle fonctions, telles que:
Mais généralement, il est lent et/ou imprécises.
Espère que j'ai aidé.
OriginalL'auteur Matth
Le moyen le plus rapide, je pense, de faire un pow() serait le long de ces lignes (remarque, c'est assez compliqué):
Je n'ai aucune idée sur la façon de mettre en œuvre une virgule pouvoir. Ma meilleure supposition serait d'utiliser les logarithmes.
Edit: je suis d'essayer logarithmique solution (basé sur y), par opposition à un linéaire de la solution que vous proposez. Permettez-moi de faire ce travail et de le modifier, parce que je sais que ça fonctionne.
Edit 2: Héhé, mon mauvais. d'alimentation *= 2 au lieu de pouvoir++
Erp, mon résumé est faux. Vous êtes à la quadrature x chaque itération, plutôt que de multiplier par votre valeur d'origine. x -> xx -> xxxx lorsque vous voulez x -> xx -> xx*x. Mais comme je l'ai dit, votre deuxième boucle [et, par extension, l'ensemble de la carte vous construisez] est complètement inutile, parce que votre première boucle se termine lorsque l'alimentation == y, sauf si y est négatif.
construire/remplir/utilisation/détruire une carte dans l'un des plus fréquemment appelée fonction est une des activités douteuses.
OriginalL'auteur hehewaffles