Algorithme de racine carrée de précision arbitraire entière?

9

Existe-t-il des algorithmes sous-quadratiques connus pour calculer le plancher de la racine carrée d'un nentier binaire?

L'algorithme naïf serait quelque chose comme

def sqrt(x):
    r = 0
    i = x.bit_length() // 2
    while i >= 0:
        inc = (r << (i+1)) + (1 << (i*2))
        if inc <= x:
            x -= inc
            r += 1 << i
        i -= 1
    return r

Cela prend des O(n)itérations, chacune impliquant des ajouts qui sont du O(n)temps, il est donc O(n^2)temps dans l'ensemble. Y a-t-il quelque chose de plus rapide? Je sais que dans le cas de la multiplication, il existe des algorithmes spéciaux qui font mieux que le temps quadratique, mais je ne trouve rien pour les racines carrées.

Antimoine
la source
Ma réponse à quelque chose de similaire pourrait aider cs.stackexchange.com/a/37338/12052 . Le seul problème est qu'une partie de l'équation nécessaire que vous auriez besoin de trouver empiriquement pour modifier sa précision.
Francesco Gramano
@FrancescoGramano: Désolé, je ne pense pas que cela aide.
Aryabhata
btw, cette exigence sub-quadratique fait-elle partie d'un problème plus important? Parce que la différence entre le quadratique simple et le sous-quadratique compliqué n'est peut-être pas si grande en pratique. Ou est-ce simplement d'intérêt théorique?
Aryabhata
@Aryabhata Désolé, je n'ai pas vu votre commentaire plus tôt. Non, cela ne fait pas partie d'un problème plus important, juste de la curiosité.
Antimony

Réponses:

5

Vous pouvez utiliser la méthode de Newton ou n'importe laquelle d'un certain nombre d'autres méthodes pour trouver des approximations aux racines du polynôme .p(x)=x2c

Le taux de convergence pour la méthode de Newton sera quadratique, ce qui signifie que le nombre de bits corrects double à chaque itération. Cela signifie que itérations de la méthode de Newton suffisent.O(lgn)

Chaque itération de la méthode de Newton calcule

xj+1=xj(xj2c)/(2xj)=0.5xj+c2xj.

La complexité en bits de la multiplication est , pour multiplier deux entiers bits (en ignorant les facteurs ). La complexité des bits pour la division (en bits de précision) est la même. Par conséquent, chaque itération peut être calculée dans les opérations . En multipliant par itérations, nous constatons que le temps d'exécution global pour calculer la racine carrée à bits de précision est . C'est sub-quadratique.blglgbb O (nlgn)O(lgn)n O (n(lgn)2)O (blgb)blglgbbO (nlgn)O(lgn)nO (n(lgn)2)

Je pense qu'une analyse plus minutieuse montre que cela peut être amélioré pour le temps d'exécution (en tenant compte du fait que nous avons seulement besoin de connaître chaque à environ bits de précision, plutôt que bits de précision). Cependant, même l'analyse la plus élémentaire montre déjà une durée de fonctionnement clairement sous-quadratique.xjjnO (nlgn)xjjn

DW
la source
En binaire, on a également une grande supposition initiale en utilisant l'identité . Au lieu de calculer le journal, on peut approximer comme le nombre de chiffres de . Par exemple, . log 2 x x log 2 101011 6x1/2=21/2log2xlog2xxlog21010116
Nick Alger
@DW: Mais ne cherchons-nous pas une racine carrée entière? Si vous faites l'itération de la méthode de newton en utilisant uniquement l'arithmétique entière, alors nous avons besoin d'une justification supplémentaire pour la revendication , n'est-ce pas? Sinon, nous supposons déjà une précision suffisamment grande ... Désolé si je manque quelque chose d'évident. O(logn)
Aryabhata
@DW:"Le taux de convergence pour la méthode de Newton" ne sera pas quadratique si , et je ne sais pas ce qui se passe pour les valeurs de qui ne sont pas non -Réalités négatives. Votre estimation de la complexité des bits de multiplication est plus stricte que ne le suggère votre remarque suivante . De plus, nous "devons connaître chaque à environ" "bits de précision". cc=0c2xj2j
@Aryabhata:Nous ne sommes pas tout à fait "à la recherche d'une racine carrée entière"; nous recherchons "le sol de la racine carrée". Vous avez raison sur le problème de l'arithmétique des nombres entiers, bien que les mêmes complexités de bits s'appliquent aux opérations en virgule flottante.
1
@RickyDemer, oui, est un cas spécial, car alors la racine de p ( x ) a la multiplicité 2, mais lorsque c > 0 , la racine a la multiplicité 1, la méthode de Newton a donc une convergence quadratique. Je suppose que personne n'utiliserait la méthode de Newton pour calculer la racine carrée de c = 0 (car la racine carrée de zéro est évidemment zéro). Alors qu'essayez-vous de dire? Votre commentaire est-il un commentaire trivial qui est résolu en ajoutant quelque chose à ma réponse qui dit "cas spécial la racine carrée de zéro", ou y a-t-il quelque chose de plus profond ici qui me manque? c=0p(x)c>0c=0
DW
6

L'un des problèmes de la méthode de Newton est qu'elle nécessite une opération de division à chaque itération, qui est l'opération de base la plus lente.

Cependant, la méthode de Newton pour la racine carrée réciproque ne le fait pas. Si est le nombre pour lequel vous voulez trouver 1x , itérer:1x

ri+1=12ri(3xri2)

Cela s'exprime souvent comme suit:

d i = 1 - w i x r i + 1 = r i + r i d i

wi=ri2
di=1wix
ri+1=ri+ridi2

C'est trois opérations de multiplication. La division par deux peut être implémentée comme un décalage vers la droite.

Maintenant, le problème est que n'est pas un entier. Cependant, vous pouvez le manipuler en tant que tel en implémentant manuellement la virgule flottante et en effectuant un tas d'opérations de décalage pour compenser le cas échéant.r

Tout d'abord, redimensionnons :x

x=22ex

où nous aimerions que soit supérieur, mais proche de . Si nous exécutons l'algorithme ci-dessus sur au lieu de , nous trouvons . Ensuite, .x1xxr=1xx=2erx

Maintenant, divisons en une mantisse et un exposant:r

ri=2eiri

où est un entier. Intuitivement, représente la précision de la réponse.riei

Nous savons que la méthode de Newton double à peu près le nombre de chiffres significatifs précis. Nous pouvons donc choisir:

ei+1=2ei

Avec un peu de manipulation, on retrouve:

ei+1=2ei
wi=ri2
xi=x22eei+1
di=2ei+1wixi2ei+1
ri+1=2eiriridi2ei+1

A chaque itération:

xrix2e+ei

À titre d'exemple, essayons de calculer la racine carrée de . Nous savons que la réponse est . La racine carrée réciproque est , nous allons donc définir (c'est l'échelle du problème) et pour notre première estimation, nous choisirons et . (Autrement dit, nous choisissons pour notre estimation initiale à .)x=263231212231e=31r0=3e0=23412

Alors:

e1=4,r1=11
e2=8,r2=180
e3=16,r3=46338
e4=32,r4=3037000481

Nous pouvons déterminer quand arrêter l'itération en comparant à ; si j'ai calculé correctement, devrait être suffisant. Nous nous arrêterons ici, cependant, et trouverons:eieei>2e

2633037000481×263231+32=3037000481

La racine carrée entière correcte est , nous sommes donc assez proches. Nous pourrions faire une autre itération, ou faire une itération finale optimisée qui ne double pas . Les détails sont laissés en exercice.3037000499ei

Pour analyser la complexité de cette méthode, notez que la multiplication de deux entiers bits nécessite des opérations . Cependant, nous avons arrangé les choses pour que . Ainsi, la multiplication pour calculer multiplie deux nombres bits pour produire un nombre bits, et les deux autres multiplications multiplient deux nombres bits pour produire un -bit nombre.bO(blogb)ri<2eiwieiei+1ei+12ei+1

Dans chaque cas, le nombre d'opérations par itération est , et il y a itérations requises. La multiplication finale est de l'ordre des opérations . La complexité globale est donc les opérations , qui est sub-quadratique en nombre de bits en . Cela coche toutes les cases.O ( log e ) O ( 2 e log 2 e ) O ( e log 2 e ) xO(eilogei)O(loge)O(2elog2e)O(elog2e)x

Cependant, cette analyse cache un principe important que tous ceux qui travaillent avec de grands entiers doivent garder à l'esprit: parce que la multiplication est superlinéaire en nombre de bits, toutes les opérations de multiplication ne doivent être effectuées que sur des entiers qui ont à peu près l'ampleur de la précision actuelle (et , Je pourrais ajouter, vous devriez essayer de multiplier les nombres qui ont un ordre de grandeur similaire). L'utilisation d'entiers plus grands que cela est une perte d'effort. Les facteurs constants comptent, et pour les grands nombres entiers, ils importent beaucoup.

Enfin, deux des multiplications sont de la forme . De toute évidence, il est inutile de calculer tous les bits de uniquement pour en jeter avec un décalage à droite. La mise en œuvre d'une méthode de multiplication intelligente qui en tient compte est également laissée en exercice. abcab2cabc

Pseudonyme
la source
Ce sont d'excellentes choses. Un commentaire cependant: la complexité en bits de la division n'est-elle pas approximativement la même que la complexité en bits de la multiplication? Vous parlez donc de quelque chose qui donne une amélioration constante des facteurs, pas une amélioration asymptotique, non? Ce n'était pas tout à fait clair dans votre réponse.
DW
Vous dites que la multiplication de deux entiers bits nécessite des opérations sur bits. Je pense que la bonne réponse est quelque chose comme (non?). Vous voudrez peut-être indiquer que vous ignorez les facteurs poly-log-log (par exemple, en mettant un tilde sur votre grand O, ou quelque chose). O ( b lg b ) O ( b lg b ( lg l g b ) O ( 1 ) )bO(blgb)O(blgb(lglgb)O(1))
DW
1
@DW:Non, il dit que "la multiplication de deux entiers bits nécessite des opérations ". Le mot "bit" n'apparaît qu'une seule fois; sinon, je l'aurais déjà signalé. O ( b log b )bO(blogb)
C'est une question de facteurs constants, oui. Les meilleurs algorithmes de division de grands nombres entiers utilisent une technique très similaire à l'algorithme entier, comme l'itération de Newton-Raphson et le doublement de la précision effective à chaque itération. Une boucle de Newton-Raphson dans une boucle de Newton-Raphson empile sur les facteurs constants! Ricky Demer a raison; Je pensais dans le mot modèle RAM. J'aurais probablement dû en parler.
Pseudonyme du