81

How is the square root function implemented?

River
  • 7,472
  • 11
  • 47
  • 61
pp7
  • 835
  • 1
  • 7
  • 3
  • 17
    How is it implemented where? – fenomas Aug 27 '10 at 05:40
  • 3
    @Matt: add "... but try to make a slightly better guess this time", and that's actually an accurate description! – Tom Anderson Aug 27 '10 at 09:39
  • 3
    Possible duplicate of [Writing your own square root function](http://stackoverflow.com/questions/1623375/writing-your-own-square-root-function) – Minhas Kamal Mar 22 '16 at 16:40
  • If you're interested, the [Numerical Recipes](http://nr.com/) book has lots on how to calculate square roots, sines and cosines, exponentials, logarithms, and so on. – Philip Potter Aug 27 '10 at 07:58
  • Possible duplicate of [Definitions of sqrt, sin, cos, pow etc. in cmath](http://stackoverflow.com/questions/4541130/definitions-of-sqrt-sin-cos-pow-etc-in-cmath) – Salix alba Sep 27 '16 at 04:39
  • Possible duplicate of [Definitions of sqrt, sin, cos, pow etc. in cmath](https://stackoverflow.com/questions/4541130/definitions-of-sqrt-sin-cos-pow-etc-in-cmath) – underscore_d Nov 04 '18 at 21:00
  • @PhilipPotter The Numerical Recipes website changed their web address, [here](http://numerical.recipes/) is a link that works as of November 2019 – DarthVlader Nov 23 '19 at 20:06

15 Answers15

22

Simple implementation using Binary Search with C++

double root(double n){
  // Max and min are used to take into account numbers less than 1
  double lo = min(1, n), hi = max(1, n), mid;

  // Update the bounds to be off the target by a factor of 10
  while(100 * lo * lo < n) lo *= 10;
  while(100 * hi * hi > n) hi *= 0.1;

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

Note that while loop is most common with the binary search but Personally I prefer using for when dealing with decimal numbers, it saves some special cases handling and gets pretty accurate result from small loops like that 1000 or even 500 (Both will give the same result for almost all numbers but just to be safe).

Edit: Check out this Wikipedia article for various -special purpose- methods specialized in computing the square root.

Edit 2: Apply updates suggested by @jorgbrown to fix the function in case of input less than 1. Also, apply optimization to make the bounds off the target root by a factor of 10

Amr Saber
  • 740
  • 7
  • 23
  • 3
    This is slower to converge than the Newton-Raphson method. It adds 1 bit of accuracy per iteration, whereas N-R doubles the number of bits of accuracy. So, if you don't mind 'slow', this works. – Jonathan Leffler Sep 26 '16 at 22:04
  • Can I ask how does this add only 1 bit per iteration ? while newton's method doubles it ? – Amr Saber Sep 26 '16 at 22:13
  • 4
    Your code halves the interval being searched on each iteration, which basically is equivalent to adding 1 bit. It's a bit of a crude approximation, but count the iterations and see. N-R uses calculus and does a better job of predicting the result. After you've got a few bits of accuracy in the square root, it converges very rapidly. See Wikipedia [Newton's Method — Example — Square Root](https://en.wikipedia.org/wiki/Newton's_method#Square_root_of_a_number) — or SO on [Writing your own square root function](http://stackoverflow.com/questions/1623375) or use your preferred search engine. – Jonathan Leffler Sep 26 '16 at 22:42
  • Nice and simple to implement in different languages when speed isn't the most important :) – BullyWiiPlaza Sep 09 '17 at 13:29
  • 1
    This routine doesn't work at all when n is less than 1. For example, for the square root of 1/4, the routine starts with a lo=0 and hi=1/4, but the answer is 1/2, which isn't between 0 and 1/4. So it always returns n, for all n less than 1. After iterating 1,000 times. You can fix this by changing your first line declaring lo, hi, and mid to be `double lo = 1, hi = n, mid; if (n < 1) lo = n, hi = 1;` – jorgbrown Sep 24 '20 at 04:40
  • The routine is horribly slow on very large or very small values because its initial hi/lo guesses are so far off. One simple loop will bring lo to within a factor of 10: `while (lo * 100 * lo < n) lo *= 10;` and another will bring hi to within a factor of 10: `while (hi * 0.01 * hi > n) hi *= 0.1;` With these mods, you really will be computing one bit of answer for every time through your loop, so you can limit it to 64 loops rather than 1000. – jorgbrown Sep 24 '20 at 05:04
  • 1
    Also, if anyone says Newton's method uses fewer loops, you can point out that Newton's method uses divide, which is 15-80 cycles, depending on which CPU is used. Your loop on the other hand uses only multiply and add, which are only a few cycles each. (Minor note: you may have to change `(lo+hi)/2` to `(lo+hi)*0.5`, depending on the compiler, to be sure it's not doing division) – jorgbrown Sep 24 '20 at 05:04
10

On Intel hardware, it's often implemented on top of the hardware SQRT instruction. Some libraries just use the result of that straight off, some may put it through a couple of rounds of Newton optimisation to make it more accurate in the corner cases.

Tom Anderson
  • 42,965
  • 15
  • 81
  • 123
  • Is the hardware sqrt instruction accurate for all inputs (up to 1ULP error in all cases where mathematically there is a valid result) – Paul Stelian Aug 27 '18 at 13:52
  • @PaulStelian I believe it is. Section 4.8.4 of the [Intel® 64 and IA-32 architectures software developer's manual](https://software.intel.com/sites/default/files/managed/a4/60/253665-sdm-vol-1.pdf) talks about rounding of results generally, and says "Rounding introduces an error in a result that is less than one unit in the last place". Section 5.2.2 lists the square root instruction FSQRT as one of the "x87 FPU Basic Arithmetic Instructions", so i believe it falls under that. Section 8.3.10 talks about the accuracy of transcendental functions, but that means trigonometric instructions. – Tom Anderson Aug 28 '18 at 17:30
  • 2
    @PaulStelian Although note that the documentation on this is [not always to be trusted](https://randomascii.wordpress.com/2014/10/09/intel-underestimates-error-bounds-by-1-3-quintillion/)! – Tom Anderson Aug 28 '18 at 17:31
8

The FDLIBM (Freely Distributable LIBM) has a quite nice documented version of sqrt. e_sqrt.c.

The have one version which uses integer arithmetic and a recurrence formula modifying one bit at a time.

Another method uses Newton's method. It starts with some black magic and a lookup table to get the first 8 bits and then applies the recurrence formula

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

where x is the number we started with. This is the Babylonian method of Heron's method. It dates back to Hero of Alexandra in the first centuary AD.

There is another method called the Fast inverse square root or reciproot. which uses some "evil floating point bit level hacking" to find the value of 1/sqrt(x). i = 0x5f3759df - ( i >> 1 ); It exploits the binary representation of a float using the mantisse and exponent. If our number x is (1+m) * 2^e, where m is the mantissa and e the exponent and the result y = 1/sqrt(x) = (1+n) * 2^f. Taking logs

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

So we see the exponent part of the result is -1/2 the exponent of the number. The black magic basically does a bitwise shift on the exponent and uses a linear approximation on the mantissa.

Once you have a good first approximation you can use Newton's methods to get a better result and finally some bit level work to fix the last digit.

Salix alba
  • 6,826
  • 1
  • 30
  • 34
6

This is an implementation of Newton's algorithm, see 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
}

The following is a mathematical explanation of the magic line. Suppose you want to find the root of the polynomial $f(x) = x^2 - a$. By Newton's method, you could start with an initial guess $x_0 = 1$. The next guess is $x_1 = x_0 - f(x_0)/f'(x_0)$, where $f'(x) = 2x$. Therefore, your new guess is

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

Costa Huang
  • 1,037
  • 11
  • 14
  • 1
    More specifically, this is a more concise implementation of http://www.cs.wustl.edu/~kjg/CS101_SP97/Notes/SquareRoot/sqrt.html, which has been referenced before, i.e. the Babylonian / Heron's method. See also https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method – lima.sierra Apr 25 '18 at 11:17
1

sqrt(); function Behind the scenes.

It always checks for the mid-points in a graph. Example: sqrt(16)=4; sqrt(4)=2;

Now if you give any input inside 16 or 4 like sqrt(10)==?

It finds the mid point of 2 and 4 i.e = x ,then again it finds the mid point of x and 4 (It excludes lower bound in this input). It repeats this step again and again until it gets the perfect answer i.e sqrt(10)==3.16227766017 .It lies b/w 2 and 4.All this in-built function are created using calculus,differentiation and Integration.

lifeisbeautiful
  • 574
  • 1
  • 3
  • 17
1

Implementation in Python: The floor of the root value is the output of this function. Example: The square root of 8 is 2.82842..., this function will give output '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
Akshay Nair
  • 445
  • 5
  • 10
1

I'm making a sqrt function too, 100000000 iterations takes 14 seconds, still nothing compared to 1 seconds by 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;
}

But the fastest implementation is:

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);}
ishidex2
  • 628
  • 9
  • 11
1
Formula: root(number, <root>, <depth>) == number^(root^(-depth))

Usage: root(number,<root>,<depth>)

Example: root(16,2) == sqrt(16) == 4
Example: root(16,2,2) == sqrt(sqrt(16)) == 2
Example: root(64,3) == 4

Implementation in C#:

static double root(double number, double root = 2f, double depth = 1f)
{
    return Math.Pow(number, Math.Pow(root, -depth));
}
Imk0tter
  • 11
  • 2
  • 1
    Code dumps without any explanation are rarely helpful. Stack Overflow is about learning, not providing snippets to blindly copy and paste. Please [edit] your question and explain how it works better than what the OP provided (and _don't_ sign your posts). – Chris May 09 '20 at 19:47
1

Solutions so far have been mainly floating-point... and have also assumed that a divide instruction is available and fast.

Here's a simple straightforward routine that doesn't use FP or divide. Every line computes another bit in the result, except for the first if statement which speeds up the routine when the input is small.

constexpr unsigned int root(unsigned int x) {
  unsigned int i = 0;
  if (x >= 65536) {
    if ((i + 32768) * (i + 32768) <= x) i += 32768;
    if ((i + 16384) * (i + 16384) <= x) i += 16384;
    if ((i + 8192) * (i + 8192) <= x) i += 8192;
    if ((i + 4096) * (i + 4096) <= x) i += 4096;
    if ((i + 2048) * (i + 2048) <= x) i += 2048;
    if ((i + 1024) * (i + 1024) <= x) i += 1024;
    if ((i + 512) * (i + 512) <= x) i += 512;
    if ((i + 256) * (i + 256) <= x) i += 256;
  }
  if ((i + 128) * (i + 128) <= x) i += 128;
  if ((i + 64) * (i + 64) <= x) i += 64;
  if ((i + 32) * (i + 32) <= x) i += 32;
  if ((i + 16) * (i + 16) <= x) i += 16;
  if ((i + 8) * (i + 8) <= x) i += 8;
  if ((i + 4) * (i + 4) <= x) i += 4;
  if ((i + 2) * (i + 2) <= x) i += 2;
  if ((i + 1) * (i + 1) <= x) i += 1;
  return i;
}
jorgbrown
  • 1,628
  • 12
  • 20
0

To calculate the square root (without using inbuilt math.sqrt function):

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();

    }

}
Jonathan Leffler
  • 666,971
  • 126
  • 813
  • 1,185
  • Calculating the integer part seems likely to be slow if you're calculating the square root of 1E36, for example. In fact, it probably overflows your `int` type, doesn't it, before it reaches the correct value. I'm not sure how well the algorithm as a whole will work finding the square root of 1E-36, either. You can tweak the exponents — but the range is usually ±300 or larger, and I don't think your code works well for most of that range. – Jonathan Leffler Sep 26 '16 at 22:53
0

there is some thing called Babylonian method.

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;
}

for more information link: https://www.geeksforgeeks.org/square-root-of-a-perfect-square/

0

So, just in case there are no specifications about whether not to use the in-built ceil or round function, here is a recursive approach in Java to finding the square root of an unsigned number using the Newton-Raphson method.

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));
    }
}
Caleb Lucas
  • 98
  • 1
  • 6
-1
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;
}
HeadAndTail
  • 758
  • 6
  • 8
-1

Following my solution in 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))
}

Following a classic/common solution.

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))
}

For further information check here

Camila Macedo
  • 607
  • 6
  • 8
-1

Usage: root(number,root,depth)

Example: root(16,2) == sqrt(16) == 4
Example: root(16,2,2) == sqrt(sqrt(16)) == 2
Example: root(64,3) == 4

Implementation in C#:

double root(double number, double root, double depth = 1f)
{
    return number ^ (root ^ (-depth));
}

Usage: Sqrt(Number,depth)

Example: Sqrt(16) == 4
Example: Sqrt(8,2) == sqrt(sqrt(8))

double Sqrt(double number, double depth = 1) return root(number,2,depth);

By: Imk0tter

Imk0tter
  • 11
  • 2
  • This essentially just translates the square root function to raising `number` to 0.5. The OP was likely aware of this identity and was interested in "how do I calculate `number`^0.5?" – weirdev May 09 '20 at 20:03