web-dev-qa-db-fra.com

Comment la fonction racine carrée est-elle implémentée?

Comment la fonction racine carrée est-elle implémentée?

55
pp7

Source ici

Enoncé du problème: étant donné x> 0, trouvez y tel que y ^ 2 = x => y = x/y (c’est l’étape clé). 

  1. Devinez une valeur g pour y et testez-la. 
  2. Calculer x/g. 
  3. Si x/g est suffisamment proche de g, retourne g. Sinon, essayez de deviner.
double test(double x, double g) {
   if closeEnough(x/g, g)
      return g;
   else
      return test(x, betterGuess(x, g));
}

boolean closeEnough(double a, double b) {
   return (Math.abs(a - b) < .001);
}

double betterGuess(double x, double g) {
   return ((g + x/g) / 2);
}

sqrt(2)         | Guess g  x / g               | New guess, (g + x / g) / 2
----------------|------------------------------|-------------------------------
test(2, 1)      | 1        2 / 1      = 2      | (2      +      1) / 2 = 1.5
test(2, 1.5)    | 1.5      2 / 1.5    = 1.3333 | (1.3333 +    1.5) / 2 = 1.4167
test(2, 1.4167) | 1.4167   2 / 1.4167 = 1.4118 | (1.4167 + 1.4118) / 2 = 1.4142
test(2, 1.4142) | 1.4142   ...                 | ...
30
Srujan Kumar Gulla

Mise en oeuvre simple avec Recherche binaire avec C++

double root(double n){
  double lo = 0, hi = n, mid;
  for(int i = 0 ; i < 1000 ; i++){
      mid = (lo+hi)/2;
      if(mid*mid == n) return mid;
      if(mid*mid > n) hi = mid;
      else lo = mid;
  }
  return mid;
}

Notez que la boucle while est plus courante avec la recherche binaire mais personnellement, je préfère utiliser for pour traiter les nombres décimaux, elle enregistre certaines manipulations de cas spéciaux et obtient un résultat assez précis de petites boucles telles que 1000 ou même 500 pour presque tous les chiffres mais juste pour être en sécurité).

Edit: consultez cet article Article Wikipedia pour différentes méthodes à des fins spécifiques, spécialisées dans le calcul de la racine carrée.

9
Argento

Sur le matériel Intel, il est souvent implémenté en plus de l'instruction SQRT du matériel. Certaines bibliothèques n'utilisent que le résultat de cette opération, d'autres peuvent le soumettre à quelques optimisations de Newton pour le rendre plus précis dans les angles.

6
Tom Anderson

Le FDLIBM (LIBEL librement distribuable) a une version assez bien documentée de sqrt. e_sqrt.c .

Ils ont une version qui utilise l’arithmétique entière et une formule de récurrence qui modifie un bit à la fois.

Une autre méthode utilise la méthode de Newton. Il commence avec de la magie noire et une table de recherche pour obtenir les 8 premiers bits, puis applique la formule de récurrence

 y_{i+1} = 1/2 * ( y_i + x / y_i)

où x est le nombre que nous avons commencé. C'est la méthode babylonienne de la méthode de Heron. Il remonte à Hero of Alexandra au premier centile de notre ère.

Il existe une autre méthode appelée racine carrée inverse rapide ou réciproque. qui utilise un "piratage de niveau en bits à virgule flottante" pour trouver la valeur de 1/sqrt (x) i = 0x5f3759df - ( i >> 1 ); Il exploite la représentation binaire d'un float en utilisant la mantisse et l'exposant. Si notre nombre x est (1 + m) * 2 ^ e, où m est la mantisse et e l'exposant et le résultat y = 1/sqrt (x) = (1 + n) * 2 ^ f. Prendre des journaux

lg(y) = - 1/2 lg(x)
f + lg(1+n) = -1/2 e - 1/2 lg(1+m)

Nous voyons donc que la partie exposant du résultat est -1/2 l'exposant du nombre. La magie noire effectue fondamentalement un décalage au niveau du bit sur l'exposant et utilise une approximation linéaire sur la mantisse. 

Une fois que vous avez une bonne première approximation, vous pouvez utiliser les méthodes de Newton pour obtenir un meilleur résultat et, enfin, un peu de travail au niveau du bit pour corriger le dernier chiffre.

4
Salix alba

Ceci est une implémentation de l'algorithme de Newton, voir https://tour.golang.org/flowcontrol/8 .

func Sqrt(x float64) float64 {
  // let initial guess to be 1
  z := 1.0
  for i := 1; i <= 10; i++ {
    z -= (z*z - x) / (2*z) // MAGIC LINE!!
    fmt.Println(z)
  }
  return z
}

Ce qui suit est une explication mathématique de la ligne magique. Supposons que vous souhaitiez trouver la racine du polynôme $ f (x) = x ^ 2 - a $. Selon la méthode de Newton, vous pourriez commencer par une hypothèse initiale $ x_0 = 1 $. La prochaine estimation est $ x_1 = x_0 - f (x_0)/f '(x_0) $, où $ f' (x) = 2x $. Par conséquent, votre nouvelle estimation est 

$ x_1 = x_0 - (x_0 ^ 2 - a)/2x_0 $

2
Costa Huang

sqrt (); fonction Dans les coulisses.

Il vérifie toujours les points médians dans un graphique. Exemple: sqrt (16) = 4; sqrt (4) = 2;

Maintenant, si vous donnez une entrée dans 16 ou 4 comme sqrt (10) ==?

Il trouve le point médian de 2 et 4, c'est-à-dire = x, puis il trouve à nouveau le point médian de x et 4 (il exclut la limite inférieure dans cette entrée). Il répète cette étape encore et encore jusqu'à l'obtention de la réponse parfaite, c'est-à-dire sqrt (10) == 3.16227766017.

1
Aravind Bhat K

Implémentation en Python: Le plancher de la valeur racine est la sortie de cette fonction . Exemple: la racine carrée de 8 est 2.82842 ..., cette fonction donnera le résultat '2'.

def mySqrt(x):
        # return int(math.sqrt(x))
        if x==0 or x==1:
            return x
        else:
            start = 0
            end = x  
            while (start <= end):
                mid = int((start + end) / 2)
                if (mid*mid == x):
                    return mid
                Elif (mid*mid < x):
                    start = mid + 1
                    ans = mid
                else:
                    end = mid - 1
            return ans
1
Akshay Nair

Donc, juste au cas où il n'y a pas de spécification sur le fait de ne pas utiliser la fonction ceil ou round intégrée, voici une approche récursive en Java pour trouver la racine carrée d'un nombre non signé en utilisant la méthode de Newton-Raphson.

public class FindSquareRoot {

    private static double newtonRaphson(double N, double X, double oldX) {

        if(N <= 0) return 0;

        if (Math.round(X) == Math.ceil(oldX))
            return X;

        return newtonRaphson(N, X - ((X * X) - N)/(2 * X), X);
    }

    //Driver method
    public static void main (String[] args) {
        System.out.println("Square root of 48.8: " + newtonRaphson(48.8, 10, 0));
    }
}
0
Caleb Lucas

il y a quelque chose qui s'appelle la méthode babylonienne.

static float squareRoot(float n)
{

    /*We are using n itself as 
    initial approximation This 
    can definitely be improved */
    float x = n;
    float y = 1;

    // e decides the accuracy level
    double e = 0.000001;
    while(x - y > e)
    {
        x = (x + y)/2;
        y = n/x;
    }
    return x;
}

pour plus d'informations lien: https://www.geeksforgeeks.org/square-root-of-a-perfect-square/

0
nagaraju chidarla

Pour calculer la racine carrée (sans utiliser la fonction math.sqrt intégrée):

SquareRootFunction.Java

public class SquareRootFunction {

    public double squareRoot(double value,int decimalPoints)
    {
        int firstPart=0;


        /*calculating the integer part*/
        while(square(firstPart)<value)
        {
            firstPart++;            
        }

        if(square(firstPart)==value)
            return firstPart;
        firstPart--;

        /*calculating the decimal values*/
        double precisionVal=0.1;
        double[] decimalValues=new double[decimalPoints];
        double secondPart=0;

        for(int i=0;i<decimalPoints;i++)
        {
            while(square(firstPart+secondPart+decimalValues[i])<value)
            {
                decimalValues[i]+=precisionVal;
            }

            if(square(firstPart+secondPart+decimalValues[i])==value)
            {
                return (firstPart+secondPart+decimalValues[i]);
            }

            decimalValues[i]-=precisionVal;
            secondPart+=decimalValues[i];
            precisionVal*=0.1;
        }

        return(firstPart+secondPart);

    }


    public double square(double val)
    {
        return val*val;
    }

}

MainApp.Java

import Java.util.Scanner;

public class MainApp {

public static void main(String[] args) {

    double number;
    double result;
    int decimalPoints;
    Scanner in = new Scanner(System.in);

    SquareRootFunction sqrt=new SquareRootFunction();   
    System.out.println("Enter the number\n");               
    number=in.nextFloat();  

    System.out.println("Enter the decimal points\n");           
    decimalPoints=in.nextInt();

    result=sqrt.squareRoot(number,decimalPoints);

    System.out.println("The square root value is "+ result);

    in.close();

    }

}
0
Nagabhushana G M
long long int floorSqrt(long long int x) 
{
    long long r = 0;
    while((long)(1<<r)*(long)(1<<r) <= x){
        r++;
    }
    r--;
    long long b = r -1;
    long long ans = 1 << r;
    while(b >= 0){
        if(((long)(ans|1<<b)*(long)(ans|1<<b))<=x){
            ans |= (1<<b);
        }
        b--;
    }
    return ans;
}
0
HeadAndTail

Je fais une fonction aussi, 100000000 itérations prend 14 secondes, toujours rien comparé à 1 seconde par sqrt

double mysqrt(double n)
{
    double x = n;
    int it = 4;
    if (n >= 90)
    {
        it = 6;
    }
    if (n >= 5000)
    {
        it = 8;
    }
    if (n >= 20000)
    {
        it = 10;
    }
    if (n >= 90000)
    {
        it = 11;
    }
    if (n >= 200000)
    {
        it = 12;
    }
    if (n >= 900000)
    {
        it = 13;
    }
    if (n >= 3000000)
    {
        it = 14;
    }
    if (n >= 10000000)
    {
        it = 15;
    }
    if (n >= 30000000)
    {
        it = 16;
    }
    if (n >= 100000000)
    {
        it = 17;
    }

    if (n >= 300000000)
    {
        it = 18;
    }
    if (n >= 1000000000)
    {
        it = 19;
    }

    for (int i = 0; i < it; i++)
    {
        x = 0.5*(x+n/x);
    }
    return x;
}

Mais la mise en oeuvre la plus rapide est:

float Q_rsqrt( float number )
{
    long i;
    float x2, y;
    const float threehalfs = 1.5F;

    x2 = number * 0.5F;
    y  = number;
    i  = * ( long * ) &y;                       // evil floating point bit level hacking
    i  = 0x5f3759df - ( i >> 1 );               // what the fuck?
    y  = * ( float * ) &i;
    y  = y * ( threehalfs - ( x2 * y * y ) );   // 1st iteration
//  y  = y * ( threehalfs - ( x2 * y * y ) );   // 2nd iteration, this can be removed

    return y;
}

float mysqrt(float n) {return 1/Q_rsqrt(n);}
0
ishidex2

Suite à ma solution à Golang.

package main

import (
   "fmt"
)

func Sqrt(x float64) float64 {
   z := 1.0 // initial guess to be 1
   i := 0
   for int(z*z) != int(x) { // until find the first approximation
      // Newton root algorithm
      z -= (z*z - x) / (2 * z)
      i++
   }
   return z
}

func main() {
   fmt.Println(Sqrt(8900009870))
}

Suite à une solution classique/commune.

package main

import (
"fmt"
"math"
)

func Sqrt(num float64) float64 {
   const DIFF = 0.0001 // To fix the precision
   z := 1.0

   for {
      z1 := z - (((z * z) - num) / (2 * z))
      // Return a result when the diff between the last execution 
      // and the current one is lass than the precision constant
      if (math.Abs(z1 - z) < DIFF) {
         break
      }
      z = z1
   }

   return z
}


func main() {
   fmt.Println(Sqrt(94339))
}

Pour plus d'informations, consultez ici

0
Camila Macedo