Vous cherchez un efficace entier racine carrée de l'algorithme pour les BRAS Thumb2
Je suis à la recherche d'un moyen rapide, entier uniquement algorithme pour trouver la racine carrée (partie entière de celui-ci) d'un entier non signé.
Le code doit avoir d'excellentes performances sur les BRAS de Pouce de 2 processeurs. Il pourrait être de langage d'assemblage ou de code C.
Tous les conseils de bienvenue.
InformationsquelleAutor Ber | 2009-07-08
Vous devez vous connecter pour publier un commentaire.
Entier Des Racines Carrées par Jack W. Crenshaw pourrait être utile comme une autre référence.
La C Extraits De L'Archive a aussi un entier racine carrée de la mise en œuvre. Celui-ci va au-delà de tout juste le résultat sous forme d'entier, et calcule supplémentaire fractionnaire (point fixe) bits de la réponse. (Mise à jour: malheureusement, le C des extraits d'archives est désormais obsolète. Le lien pointe vers un site web des archives de la page.) Voici le code à partir de la C des Extraits de l'Archive:
Que j'ai réglé sur le code suivant. C'est essentiellement à partir de la Article de Wikipedia sur la racine carrée méthodes de calcul. Mais il a été changé à utiliser
stdint.h
typesuint32_t
etc. Strictement parlant, le type de retour peut être changée pouruint16_t
.La bonne chose, j'ai découvert, est assez simple modification peut retourner le "arrondi" réponse. J'ai trouvé ce utile dans une certaine demande pour plus de précision. Notez que dans ce cas, le type de retour doit être
uint32_t
car l'arrondi de la racine carrée de 232 - 1 216.Si exacte précision n'est pas nécessaire, j'ai une rapide approximation pour vous, qui utilise 260bytes de ram (que vous pouvez réduire de moitié, mais ne le font pas).
Voici le code pour générer les tables:
Dans la gamme 1->2^20, l'erreur maximale est de 11, et dans la gamme 1->2^30, c'est sur 256. Vous pouvez utiliser des tables plus grandes et le minimiser. Il est important de mentionner que l'erreur sera toujours négatif - c'est à dire quand c'est faux, la valeur sera inférieure à la valeur correcte.
Vous pourriez bien faire pour suivre cela avec un raffinage.
L'idée est assez simple: (ab)^0.5 = a^0.b * b^0.5.
Donc, nous prenons l'entrée X = A*B où A=2^N et 1<=B<2
Ensuite, nous avons un lookuptable pour sqrt(2^N), et un lookuptable pour sqrt(1<=B<2).
Nous stockons les lookuptable pour sqrt(2^N) as integer, qui pourrait être une erreur (les tests montrent pas d'effets néfastes), et nous stockons les lookuptable pour sqrt(1<=B<2) à 15bits de point fixe.
Nous savons que 1<=sqrt(2^N)<65536, de sorte que c'est 16bit, et nous savons que nous pouvons vraiment que multiplier 16bitx15bit sur un BRAS, sans crainte de représailles, de sorte que c'est ce que nous faisons.
En termes de mise en œuvre, le temps(t) {cnt++;t>>=1;} est effectivement un comte de pointe-bits de l'instruction (CLB), donc si votre version du chipset est que, vous êtes gagnants! Aussi, le passage d'instruction serait facile à mettre en œuvre avec un levier de vitesse bidirectionnel, si vous en avez un?
Il y a un Lg[N] de l'algorithme de comptage de la plus haute bit ici.
En termes de numéros de magie, pour modifier les dimensions de la table, LE nombre magique pour ftbl2 est de 32, mais notez qu' 6 (Lg[32]+1) est utilisé pour le déplacement.
Une approche commune est non-bloquante.
Quelque chose comme ça devrait fonctionner raisonnablement bien. Il fait log2(nombre), les tests, faire
log2(nombre) se multiplie et divise. Depuis la division est une division par 2, vous pouvez le remplacer par un
>>
.La condition d'arrêt peut ne pas être exactement les mêmes, alors assurez-vous de tester une variété de nombres entiers pour être sûr que la division par 2 n'a pas tort osciller entre deux valeurs; ils s'en distinguent par plus de 1.
Il n'est pas rapide, mais il est petit et simple:
Je trouve que la plupart des algorithmes sont basés sur des idées simples, mais sont mis en œuvre de manière plus compliqué que nécessaire. J'ai pris l'idée à partir d'ici: http://ww1.microchip.com/downloads/en/AppNotes/91040a.pdf (par Ross M. Fosler) et en a fait un très bref C-fonction:
Cette compile à 5 cycles/bits sur mon blackfin. Je crois que votre code compilé sera en général plus rapide si vous utilisez des boucles au lieu de boucles while, et vous obtenez l'avantage supplémentaire de la déterministe du temps (bien que dans une certaine mesure dépend de la façon dont votre compilateur optimise l'instruction if.)
Il repose sur l'utilisation de la fonction sqrt. J'utilise souvent certains env de prendre rapidement des versions. Par exemple, quand j'ai besoin de calculer le module du vecteur :
J'utilise :
Qui peut être codée dans 3 ou 4 instructions:
J'ai réglé quelque chose de similaire à la binary digit par digit de l'algorithme décrit dans cet article de Wikipédia.
Voici une solution en Java qui combine entier log_2 et de la méthode de Newton pour créer une boucle de l'algorithme. Comme un inconvénient, il a besoin de la division. Les lignes commentées sont nécessaires pour convertir à une version 64 bits de l'algorithme.
Comment cela fonctionne: La première partie produit une racine carrée exacte à propos de trois bits. La ligne [y= (y+num/y)>>1;] double la précision en bits. La dernière ligne élimine le toit des racines qui peuvent être générés.
SQRT
etDeBruijnArray
sont à la foisint[32]
, et l'ajout d'un nécessaire de lancer pourint
pour faire de la compilation). Il semble écrire en dehors des limites lors de la première initialisation de la boucle.J'ai récemment rencontré la même tâche sur le processeur ARM Cortex-M3 (STM32F103CBT6) et après des recherches sur Internet est venu avec la solution suivante. Ce n'est pas le plus rapide en comparaison avec les solutions proposées ici, mais il a une bonne précision (de l'erreur maximale est de 1, c'est à dire LSB sur l'ensemble de la UI32 d'entrée de gamme) et de relativement bonne vitesse (environ 1,3 M racines carrées par seconde sur une de 72 MHz ARM Cortex-M3, soit environ 55 cycles par racine unique, y compris l'appel de la fonction).
Je suis en utilisant IAR et elle produit les suivants du code assembleur:
Cette méthode est similaire à la division longue: vous construisez une supposition pour le prochain chiffre de la racine, faire une soustraction, et entrez les chiffres si la différence répond à certains critères. Avec la version binaire, votre seul choix pour le prochain chiffre est 0 ou 1, ce qui vous permet de deviner 1, faire la soustraction, et entrez un 1, sauf si la différence est négative.
http://www.realitypixels.com/turk/opensource/index.html#FractSqrt
J'ai mis en place Warren de la suggestion et de la méthode de Newton en C# pour les entiers 64 bits. Isqrt utilise la méthode de Newton, tandis que Isqrt utilise Warren méthode. Voici le code source:
J'ai utilisé les méthodes suivantes pour référence le code:
Mes résultats sur un Dell Latitude E6540 en mode Release, Visual Studio 2012 ont été
que l'appel de la Bibliothèque de Mathématiques.Sqrt est plus rapide.
Je ne suis pas à l'aise avec les directives du compilateur, de sorte qu'il peut être possible de régler le compilateur pour obtenir le nombre entier maths plus vite. Clairement, le décalage de bits approche est très proche de la bibliothèque. Sur un système sans coprocesseur mathématique, il serait très rapide.