Partage
  • Partager sur Facebook
  • Partager sur Twitter

Trouver racine carrée entière rapidement

Sujet résolu
    10 décembre 2019 à 2:10:01

    Bonjour,

    Corrigez-moi si je me trompe. On peut calculer la racine carrée d'un nombre par approximations successives de la formule:

    r' = ( n/r + r ) / 2

    Ou n est le nombre pour lequel on cherche la racine carrée, et r est une approximation de cette racine carrée.

    On dit qu'elle converge de façon quadratique, ce qui voudrait dire que le nombre de bits significatifs double à chaque ittération.

    On attribue à Newton cette formule.

    Si je veux calculer la racine entière de cette façon, comment trouver une valeur de départ adéquate?

    Sur certains ordinateurs, il y a des instructions qui nous donnent la mantisse et l'exposant pour un nombre réel (float ou double).

    Si e est l'exposant et m est la mantisse, on n'a qu'à seulement changer e en le divisant par 2. On recombine le nombre avec e/2 et m.

    La racine carrée se trouvera dans l'inttervalle approximatif: 0.707 r - 1.4142 r

    La convergeance se fait assez rapidement.

    Mais si on veut éviter cette étape, comment peut-on trouver une bonne première approximation entière rapidement?

    • Partager sur Facebook
    • Partager sur Twitter

    Le Tout est souvent plus grand que la somme de ses parties.

      13 décembre 2019 à 5:21:22

       Bonjour

      Non c'est l'algorithme de Héron d'Alexandrie que vous avez esquissé très largement ici (et non la méthode de Newton )

      Soit N un réel positif dont on recherche la racine carrée

      on se donne r1 une approximation de la racine carrée de N qui peut être très éloignée (cela ne pose pas de problème on arrivera quand même à atteindre la limite(la démonstration fait trois lignes) 

      la suite (r_n) tend vers la racine carrée de N

      $$r_{n+1}=\dfrac {r_n+\dfrac {N}{r_n}}{2}$$

      par exemple on va choisir exprès r1 très éloigné de la racine carrée de N

      N=9745821103 

      $$\sqrt {N}\approx 98720.9253553$$

      $$r_1=21$$ 

      $$r_2\approx 232043370$$

      à partir de $$r_{15}$$ on atteint 98906 et à partir de là la convergence est quadratique

      $$r_{16}\approx 98721.0995339$$

      $$r_{17}\approx 98720.9253554$$

      Mais Héron d'Alexandrie nous a aussi laissé sa méthode d'extraction d'une racine carrée à la main

      que nos ancêtres (d'avant 1968 nous enseignaient avant le passage au certificat d'étude) 

      il s'agissait de la cinquième opération à la main (après celle de l'addition, la soustraction, la multiplication et la division)

      il y a avec recherche Google "racine carrée à la main" des multitudes de liens

      idem racine cubiques à la main

      mais le lien que je préfère c'est celui de Therese Eveilleau

      [url]http://therese.eveilleau.pagesperso-orange.fr/pages/truc_mat/textes/r_carree_anc.htm[/url]

      ____________________

      il y a une autre méthode ceci dit

      utiliser une bonne approximation du logarithme népérien (même sur des très très grand nombres) 

      et une bonne approximation de l'exponentielle exp() alors

      pour tout x >0

      $$\sqrt {x}=y$$

      $$exp\left(\dfrac {1}{2}ln(x)\right)=y$$

       _______________________   

      pour une bonne approximation du logarithme népérien sur des très grands nombres il y en a une très efficace utilisant une fonction trigonométrique (par exemple sinus de période 2pi)

      -
      Edité par DominiqueSicilia 13 décembre 2019 à 5:24:01

      • Partager sur Facebook
      • Partager sur Twitter
        13 décembre 2019 à 7:53:16

        Salut,
        Je te remercie pour ces informations.
        Cependant, comme tu dis, la convergeance est quadratique à partir d'un  certain point seulement.
        Avec la méthode que je donnais, cela converge en 5 ou 6 étapes, alors que cela en prend beaucoup plus si on est loin de la racine.
        Calculer un logarithme népérien est-il plus rapide que de calculer le logarithme base 2?
        Dans ce dernier cas, on divise la valeur par 2 et on trouve un nombre assez près de la racine.
        Ou on peut procéder comme suit:
        for (i = 1; i * i < n: i += i) ;
        Note: i = i + i est plus rapide que i = i * 2
        • Partager sur Facebook
        • Partager sur Twitter

        Le Tout est souvent plus grand que la somme de ses parties.

          13 décembre 2019 à 9:16:48

          PierrotLeFou a écrit:

          Calculer un logarithme népérien est-il plus rapide que de calculer le logarithme base 2?
          Dans ce dernier cas, on divise la valeur par 2 et on trouve un nombre assez près de la racine.
          Ou on peut procéder comme suit:
          for (i = 1; i * i < n: i += i) ;
          Note: i = i + i est plus rapide que i = i * 2
          pour une approximation et pour le logarithme d'un nombre t de poids numérique n en base b
          i.e. le poids numérique d'un nombre écrit en base b est la quantité des chiffres
          de sa partie entière écrite en base b
          ici on prendra par exemple b=10
          t=91244 68871 23541 11412 25014 73352 69688 54752 38777 77241 58472 31548 65265 54753 5874
          en base dix le poids numérique de ce nombre est n=74
          une approximation intéressante $$w=ln(t)\approx  ln(10)\left(n-1+\dfrac {29}{40}+\dfrac {t}{4.10^n}\right)$$
          cette formule n'est valable que pour b=10 évidemment
          $$ln(t)\approx 170.29967148$$
          $$w=170.283332631$$
          la formule précédente provient d'une formule générale
          pour toute base b pas très compliquée
           

          • Partager sur Facebook
          • Partager sur Twitter
            13 décembre 2019 à 15:04:11

            Salut,
            Comment se calcule ln(n)? Est-ce vraiment plus rapide que ma stupide boucle for ( )?
            Dans ce genre de calcul, il y a souvent des sommes de termes contenant des divisions.
            Or la division est une des opérations les plus lentes sur un ordinateur.
            Si cela prend plus de temps pour trouver une approximation adéquate, toute approximation ferait l'affaire.
            • Partager sur Facebook
            • Partager sur Twitter

            Le Tout est souvent plus grand que la somme de ses parties.

              13 décembre 2019 à 15:37:30

              je ne sais pas si j'ai bien compris votre question à cause du commentaire  il faut regarder à séries entières la fonction ln est infiniment dérivable et on peut l'écrire de la façon suivante selon le théorème suivant : si f est une fonction régulière alors

              $$f(x_a)=\sum _{n=0}^{\infty }\left(x_a-x_0\right)^n n!^{-1}d^nf_0$$

              $$d^nf_0$$ est la dérivée nième au point x_0 (borne de référence)  


              -
              Edité par DominiqueSicilia 13 décembre 2019 à 15:59:59

              • Partager sur Facebook
              • Partager sur Twitter
                13 décembre 2019 à 18:46:07

                En fait, j'ai peut-être mal formulé ma question de départ.
                Lorsque je parle de "rapidement", je fais allusion au rtemps de calcul sur un ordinateur.
                Lorsqu'on parle d'une formule avec des exposants et des factorielles, cela prend beaucoup de temps à calculer pour chaque facteur.
                Je cherchais une méthode qui demande peu de temps de calcul.
                Si par exemple, je dois appeler ma fonction disons un milliard de fois, je veux que cela se fasse assez rapidement.
                • Partager sur Facebook
                • Partager sur Twitter

                Le Tout est souvent plus grand que la somme de ses parties.

                  13 décembre 2019 à 19:18:44

                  eh bien ln(x) comme racine carrée comme toute fonction régulière peut se calculer avec une convergence de type 

                  1 décimale

                  2 décimales supplémentaire (total = 3) 

                  3 décimales supplémentaire (total = 6)  

                  4 décimales supplémentaires (total 10)

                  5 décimales supplémentaires  (total 15)  

                  etc...

                  c'est " très très  rapide" 

                  et pour le sujet ici il est facile de se donner une bonne approximation

                  j'avais fait exprès de prendre 21 mais pour montrer qu'à partir d'un certain rang la convergence devient rapide 

                  mais j'ai fait ça pour montrer "physiquement" qu'il y a un théorème (qui fait trois lignes -celui de Héron d'Alexandrie- pour la racine carrée-  comme j'ai dit) qui de toute façon affirme qu'aussi loin le premier terme de la suite soit de la limite on arrivera quand même au terme à partir duquel la suite devient très rapide

                   et vous avez trouvé comment exprimer efficacement ce premier terme  

                  -
                  Edité par DominiqueSicilia 13 décembre 2019 à 19:34:23

                  • Partager sur Facebook
                  • Partager sur Twitter
                    14 décembre 2019 à 19:37:38

                    Si j'utilisais une formule avec ln et exp, cela pourrait converger "rapidement" de façon quadratique.
                    Cependant, quel serait le temps d'exécution pour chaque itération?
                    Avec l'algorithme de base je n'ai que 2 divisions et 1 addition (n / r + r) / 2
                    Et puisque je divise par 2 et que je serait en arithmétique entière, je pourrait la remplacer par un décalage destructif vers la droite. J'aurais:
                    r' = (n / r + r) >> 1.
                    Ma boucle for (i=1; i*i <= n; i+=i);
                    me donnera une très bonne approximation en log2(n) / 2 opérations.
                    Et le nombre d'opérations n'est pas très      élevé.
                    • Partager sur Facebook
                    • Partager sur Twitter

                    Le Tout est souvent plus grand que la somme de ses parties.

                      14 décembre 2019 à 20:57:28

                      Bonjour

                      Comme vous terminez votre question par une réponse, je serais enclin à conclure que ce sujet est résolu. 

                      L'idéal serait soit de signaler que ce sujet est résolu soit de terminer vos messages par une question. 

                      Amicalement

                      • Partager sur Facebook
                      • Partager sur Twitter
                        16 décembre 2019 à 17:37:24

                        En fait, le problème n'est pas résolu du tout. Il n'y a pas toujours convergeance si on fait de l'arithmétique entière.
                        Par exemple, si je considère n=15 et r=4 au départ, j'aurai:
                        (15/4 + 4) / 2 = (3 + 4) / 2 = 7 / 2 = 3
                        (15/3 + 3) / 2 = (5 + 3) / 2 = 8 / 2 = 4
                        et je reviens au point de départ ...
                        Je pourrais envisager d'utiliser la fonction sqrt en double précision comme suit:
                        r = (int)sqrt((double)n + 0.5)
                        Cela devrait marcher pour des nombres inférieurs à 2^53, mais pas jusqu'à 2^63-1.
                        • Partager sur Facebook
                        • Partager sur Twitter

                        Le Tout est souvent plus grand que la somme de ses parties.

                          17 décembre 2019 à 12:43:28

                          Bonjour

                          Je ne pense pas  que ce soit très profitable d'utiliser la bibliothèque math.h ni même d'utiliser les types standards int ou long ou long long ou double pour faire des calculs qui vont dépasser les limites que celles données par ces types 

                          dans l'exemple donné plus haut j'avais pris 

                          t=91244 68871 23541 11412 25014 73352 69688 54752 38777 77241 58472 31548 65265 54753 5874

                          où j'avais donné une approximation de son logarithme népérien

                          mais ce que je n'ai pas dit c'est que ce t est ici une chaîne de caractères

                          Oui car en ce qui me concerne je préfère travailler sur des chaîne de caractères dont l'alphabet est [0123456789-.+i]

                          les entiers seront écrits dans l'alphabet [0123456789-]

                          les "rationnels non entiers ou irrationnels réels" dans l'alphabet [0123456789-.] entre guillemets car en fait les réels en informatique n'existent pas (ce sont des nombres décimaux ((quand ils sont écrits en base dix) qui s'expriment avec une quantité finie de chiffres significatifs) 

                          les nombres complexes dans l'alphabet [0123456789-.+i]

                          Là vous voulez faire des calculs par exemple avec des nombres de l'ordre 2^63 donc de l'ordre de 2^18

                          avec un type standard ça me semble un peu limite (de mémoire un type long est un nombre à dix chiffres) 

                           


                          • Partager sur Facebook
                          • Partager sur Twitter
                            17 décembre 2019 à 15:13:15

                            Ce que vous décrivez est soit de l'arithmétique simulée, soit des extensions de l'arithmétique standard, donc très lents.
                            Pour information, le type long long comporte au maximum 16 valeurs décimales.
                            Pour corriger la non convergeance apparente de mon calcul, je dois garder les deux dernières approximations au lieu de la dernière seulement et je les compare avec la nouvelle approximation.
                            En faisant le calcul pour des nombres jusqu'à un milliard, cela me prend moins de 40 secondes.
                            Je vais tenter d'améliorer la façon de trouver la première approximation en utilisant une recherche dichotomique sur les exposants de 2.
                            • Partager sur Facebook
                            • Partager sur Twitter

                            Le Tout est souvent plus grand que la somme de ses parties.

                              19 décembre 2019 à 1:54:20

                              C'était un autre exemple où ce n'est pas seulement le nombre d'ittérations qui est important, mais le temps pris pour chaque ittération.
                              Si je suppose mon nombre n pas trop gros: n < 2^32. Sa racine sera de l'ordre de 2^16.
                              Si je fais une recherche dichotomique, je vais faire 4 ittérations au lieu de 16, mais chaque ittération sera plus longue.
                              Il me faudra peut-être 3 ou 4 variables de plus, quelques comparaisons de plus, certains calculs du genre m = (d +f)/2
                              Je devrai faire un décalage avec une variable au lieu d'une constante, etc.
                              Au final, cela me coûtera plus cher en temps qu'une simple boucle qui se fera peut-être uniquement dans des registres.
                              • Partager sur Facebook
                              • Partager sur Twitter

                              Le Tout est souvent plus grand que la somme de ses parties.

                                21 décembre 2019 à 11:47:54

                                Bonjour PierrotLF

                                ça serait dommage de laisser mourir ce sujet car ça serait intéressant de comparer nos temps de calcul selon les deux méthodes (l'une en s'aidant de la bibliothèque math.h et l'autre en traitant tout uniquement avec des chaînes de caractères -et devoir coder le calcul-pour calculer la racine carrée entière d'un nombre de plusieurs centaines de chiffres (en base dix)  

                                 Ceci dit je n'en suis pas encore là et mon code sera lourd (et ça ne fait qu'un mois que j'ai commencé à apprendre le C -et mes journées sont courtes)

                                NB: C'est certain que si on prend pour $$u_0$$ un nombre de poids numérique "en base dix par exemple" de la moitié du poids numérique (dans la même base) du nombre dont on recherche la racine carrée on arrive plus vite au $$u_a$$ à partir duquel la suite converge quadratiquement

                                -
                                Edité par DominiqueSicilia 21 décembre 2019 à 11:50:51

                                • Partager sur Facebook
                                • Partager sur Twitter
                                  21 décembre 2019 à 19:17:30

                                  Si on fait de l'arithméttique avec des chaînes de caractères, on peut traiter de très grands nombres, mais ça prend beaucoup plus de temps de calcul.
                                  Je comprend l'argument que tu me donnes en disant qu'on n'a qu'à calculer le nombre de chiffres et qu'on divise par deux.
                                  Par exemple, si j'ai un nombre de 1000 chiffres, je peux m'attendre à ce que sa racine carrée contienne environ 500 chiffres.
                                  Même si la convergeance est quadratique à partir de ce moment, chaque opération est assez longue.
                                  Imagines devoir diviser un nombre de 1000 chiffres par un nombre de 500 chiffres. C'est comme le faire à la main.
                                  Il y a d'autres alternatives, je vais chercher de ce côté.
                                  Je pourrais toujours écrire le code en assembleur, mais ça ne me tente pas d'apprendre l'assembleur de ma machine pour le moment.
                                  C'est une façon de travailler tout à fait différente.
                                  • Partager sur Facebook
                                  • Partager sur Twitter

                                  Le Tout est souvent plus grand que la somme de ses parties.

                                    22 décembre 2019 à 7:12:20

                                    Edit je voulais dire de 1 à 11 (dans la base dix)

                                    j'étais mal réveillé

                                    PierrotLF a dit

                                    "Imagine devoir diviser un nombre de 1000 chiffres par..."

                                    En fait c'est pas si monstrueux que cela 

                                    il faut exploiter certains trucs 

                                    On sait que pour tout entier positif x et tout entier strictement positif y alors $$\dfrac {x}{y}=E\left(\dfrac {x}{y}\right)+\dfrac {x-yE\left(\dfrac {x}{y}\right)}{y}$$

                                    et ici $$0\leq x-yE\left(\dfrac {x}{y}\right)<y$$  est le reste de la division de x par y 

                                    en manipulant bien cela il devient très facile de déterminer le rapport de deux nombres même s'ils font des milliers de chiffres

                                     tout se ramène en fait à se donner une table de multiplication de 1 à 11 par 1 à 11 et à l'utiliser

                                    une fois la partie entière calculée avec cette minuscule petite table on peut ensuite s'attaquer à la partie décimale qui est donnée par

                                    $$\dfrac {x-yE\left(\dfrac {x}{y}\right)}{y}$$


                                    -
                                    Edité par DominiqueSicilia 22 décembre 2019 à 8:47:54

                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                      22 décembre 2019 à 19:29:31

                                      J'ai trouvé ceci qui permet de calculer les factorielles jusqu'à 34! alors qu'on ne peut aller plus loin que 20! avec le type long long.
                                      https://openclassrooms.com/forum/sujet/factorielle
                                      Ce que tu suggères avec ta table de multiplication ressemble à de l'arithmétique simulée.
                                      Tu pourrais faire des calculs avec des milliards de chiffres, mais ce serait horriblement long.
                                      • Partager sur Facebook
                                      • Partager sur Twitter

                                      Le Tout est souvent plus grand que la somme de ses parties.

                                      Trouver racine carrée entière rapidement

                                      × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                                      × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                                      • Editeur
                                      • Markdown