How to Implement Integer Square Root in C/C++?


Question: Implement integer square root for int sqrt(int x)

There are many ways to compute the integer square root. But if you don’t bother, you can always cheat the compilers (online judge), but don’t do this in your interviews!

The cheat ways:

Well, most programming languages have sqrt for float numbers (single or double precision), we can simply write:

1
2
3
4
5
6
7
8
9
#include <math.h>
 
class Solution {
public:
    int sqrt(int x) {
        // add std:: namespace to distinguish from current sqrt()
        return (int)std::sqrt(x);
    }
};
#include <math.h>

class Solution {
public:
    int sqrt(int x) {
        // add std:: namespace to distinguish from current sqrt()
        return (int)std::sqrt(x);
    }
};

In Java,

1
2
3
4
5
public class Solution {
    public int sqrt(int x) {
        return (int)Math.sqrt(x);
    }
}
public class Solution {
    public int sqrt(int x) {
        return (int)Math.sqrt(x);
    }
}

Or (tex_6e628c96fffd75bd05c2355bb4494ffb How to Implement Integer Square Root in C/C++? algorithms c / c++ math )

1
2
3
4
5
6
7
#include <math.h>
class Solution {
public:
    int sqrt(int x) {
        return (int)pow(x, 0.5);
    }
};
#include <math.h>
class Solution {
public:
    int sqrt(int x) {
        return (int)pow(x, 0.5);
    }
};

Exhaustive Search:

One may come up with a brute-force search quickly. We just have to try numbers from 1 until the square of this number is larger than the output.

1
2
3
4
5
6
7
8
9
10
11
#include <math.h>
typedef unsigned long long ULONG;
 
class Solution {
public:
    int sqrt(int x) {
        ULONG a = 1;
        while (a * a <= x) a ++;
        return --a;
    }
}
#include <math.h>
typedef unsigned long long ULONG;

class Solution {
public:
    int sqrt(int x) {
        ULONG a = 1;
        while (a * a <= x) a ++;
        return --a;
    }
}

Please note that we have defined a unsigned long long type to hold the intermediate result of a * a so that the result won’t overflow (too big for a 32-bit integer).

Well, the above seems unlikely to accept in online judge. But surprisingly, this is an accepted solution. Why is that? The int type is 32-bit signed integer, which gives the maximum value 2^31 – 1 = 2147483647. The square root of this is just 46340.9, which means that at most 46341 iterations, we have the correct integer root. This is trivial in modern processors, which can be done in million seconds.

The improvement:

We notice that a * a is expensive, how to get rid of that?

tex_08b169a236720dadf2e60549c3d01b56 How to Implement Integer Square Root in C/C++? algorithms c / c++ math

Therefore, we can just add to a variable delta and add it to current variable to get the square of a + 1.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <math.h>
typedef unsigned long long ULONG;
 
class Solution {
public:
    int sqrt(int x) {
        ULONG a = 1;
        ULONG delta = 3;
        while (a <= x) {
            a += delta; // (a + 1)^2
            delta += 2;
        }
        return delta / 2 - 1;
    }
}
#include <math.h>
typedef unsigned long long ULONG;

class Solution {
public:
    int sqrt(int x) {
        ULONG a = 1;
        ULONG delta = 3;
        while (a <= x) {
            a += delta; // (a + 1)^2
            delta += 2;
        }
        return delta / 2 - 1;
    }
}

The above improvements remove the multiplication and use additions only, which is often implemented in some PC boards where time is not a critical issue.

Binary Search:

The above algorithm complexity is tex_caa5d58969fcc95bcd6477b6782501fa How to Implement Integer Square Root in C/C++? algorithms c / c++ math and it is still very slow when given integer is large. The binary search can shorten this to tex_9ccb264144562f5fe085671d89f1eab0 How to Implement Integer Square Root in C/C++? algorithms c / c++ math .

Binary search is one of the most important algorithms, and in order for it to work, it requires continuous search space (e.g. numbers sorted)

In the domain of integer square roots, we can find that easily:

tex_ea3a9d748f5a0a2c181d293706a7b481 How to Implement Integer Square Root in C/C++? algorithms c / c++ math is less than tex_023625b317653aaf9c54c82cdaaebce0 How to Implement Integer Square Root in C/C++? algorithms c / c++ math for any given non-negative integers.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <math.h>
typedef unsigned long long ULONG;
 
class Solution {
public:
    int sqrt(int x) {
        ULONG l = 0, r = x;
        while (l <= r) {
            ULONG mid = l + (r - l) / 2; // (l + r) / 2;
            ULONG midmid = mid * mid;
            // check if x falls into [mid^2, (mid + 1)^2) 
            if ((midmid <= x) && (x < (mid + 1) * (mid + 1))) return mid;             
            if (midmid > x) {
                r = mid - 1;
            } else {
                l = mid + 1;
            }
        }
    }
}
#include <math.h>
typedef unsigned long long ULONG;

class Solution {
public:
    int sqrt(int x) {
        ULONG l = 0, r = x;
        while (l <= r) {
            ULONG mid = l + (r - l) / 2; // (l + r) / 2;
            ULONG midmid = mid * mid;
            // check if x falls into [mid^2, (mid + 1)^2) 
            if ((midmid <= x) && (x < (mid + 1) * (mid + 1))) return mid;             
            if (midmid > x) {
                r = mid - 1;
            } else {
                l = mid + 1;
            }
        }
    }
}

With binary search, every iteration will narrow the search space to its half. The mid = (l + r) / 2 may overflow so we can use mid = l + (r – l) / 2 to accomplish the same thing.

Newton’s method:

Binary search is a great improvement, but it still is too slow finding the solution. Modern processors have hardware square roots algorithm implemented and most of them are based on Newtons’ equation:

65fe1ede88e3c6f6c3b5d9089f30e5c3.jpg How to Implement Integer Square Root in C/C++? algorithms c / c++ math

As we can see, with every iteration of Newton’s equation, we find a closer root of tex_03955ed5b1c906502e35587cf05c6f7b How to Implement Integer Square Root in C/C++? algorithms c / c++ math

We have tex_c690620fe511c31a72a75953bc48e11e How to Implement Integer Square Root in C/C++? algorithms c / c++ math if we want to find the square root of a.

The derivative tex_a5f0426a35e9f5ec863373322e2c4554 How to Implement Integer Square Root in C/C++? algorithms c / c++ math

and we have initial guess tex_514f00110e6fe54d6fb4e62a325979df How to Implement Integer Square Root in C/C++? algorithms c / c++ math .

tex_f2a726836d7bec26963f4339b122d02c How to Implement Integer Square Root in C/C++? algorithms c / c++ math

For example,

0b9ac8f25356296435ff0b2677beeeb5.jpg How to Implement Integer Square Root in C/C++? algorithms c / c++ math

The Newton’s method converges rapidly and is considered very efficient.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <math.h>
typedef unsigned long long ULONG;
 
class Solution {
public:
    int sqrt_newton(int x) {
        if (x==0) return x;  
        double dividend = x;  
        double val = x;
        double last;
        do {  
            last = val;  
            val = (val + dividend / val) * 0.5;  
        } while(abs(val - last) > 1e-9); // precision
        return (int)val;        
    }
}
#include <math.h>
typedef unsigned long long ULONG;

class Solution {
public:
    int sqrt_newton(int x) {
        if (x==0) return x;  
        double dividend = x;  
        double val = x;
        double last;
        do {  
            last = val;  
            val = (val + dividend / val) * 0.5;  
        } while(abs(val - last) > 1e-9); // precision
        return (int)val;        
    }
}

We check the current iteration tex_dd2d47104950bf04d637ede13bcc93b0 How to Implement Integer Square Root in C/C++? algorithms c / c++ math with the last tex_654955c7c0e86370b5bb0af977b98af4 How to Implement Integer Square Root in C/C++? algorithms c / c++ math , if the difference is smaller than e.g. 1e-9 (EPSILON), then we think we have got the desired precision.

Another similar problem is to check if a given integer is a valid perfect square.

Reference:

http://en.wikipedia.org/wiki/Newton’s_method

–EOF (The Ultimate Computing & Technology Blog) —

GD Star Rating
loading...
1427 words
Last Post: C Sharp Extension Method
Next Post: Understanding Tail Recursion - Visual Studio C++ - Assembly View

The Permanent URL is: How to Implement Integer Square Root in C/C++?

Leave a Reply