Integer square root in python

Is there an integer square root somewhere in python, or in standard libraries? I want it to be exact (ie return an integer), and bark if there's no solution.

At the moment I rolled my own naive one:

def isqrt(n):
    i = int(math.sqrt(n) + 0.5)
    if i**2 == n:
        return i
    raise ValueError('input was not a perfect square')

But it's ugly and I don't really trust it for large integers. I could iterate through the squares and give up if I've exceeded the value, but I assume it would be kinda slow to do something like that. Also I guess I'd probably be reinventing the wheel, something like this must surely exist in python already...


Newton's method works perfectly well on integers:

def isqrt(n):
    x = n
    y = (x + 1) // 2
    while y < x:
        x = y
        y = (x + n // x) // 2
    return x

This returns the largest integer x for which x * x does not exceed n. If you want to check if the result is exactly the square root, simply perform the multiplication to check if n is a perfect square.

I discuss this algorithm, and three other algorithms for calculating square roots, at my blog.


Sorry for the very late response; I just stumbled onto this page. In case anyone visits this page in the future, the python module gmpy2 is designed to work with very large inputs, and includes among other things an integer square root function.

Example:

>>> import gmpy2
>>> gmpy2.isqrt((10**100+1)**2)
mpz(10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001L)
>>> gmpy2.isqrt((10**100+1)**2 - 1)
mpz(10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000L)

Granted, everything will have the "mpz" tag, but mpz's are compatible with int's:

>>> gmpy2.mpz(3)*4
mpz(12)

>>> int(gmpy2.mpz(12))
12

See my other answer for a discussion of this method's performance relative to some other answers to this question.

Download: https://code.google.com/p/gmpy/


Long-hand square root algorithm

It turns out that there is an algorithm for computing square roots that you can compute by hand, something like long-division. Each iteration of the algorithm produces exactly one digit of the resulting square root while consuming two digits of the number whose square root you seek. While the "long hand" version of the algorithm is specified in decimal, it works in any base, with binary being simplest to implement and perhaps the fastest to execute (depending on the underlying bignum representation).

Because this algorithm operates on numbers digit-by-digit, it produces exact results for arbitrarily large perfect squares, and for non-perfect-squares, can produce as many digits of precision (to the right of the decimal place) as desired.

There are two nice writeups on the "Dr. Math" site that explain the algorithm:

  • Square Roots in Binary
  • Longhand Square Roots
  • And here's an implementation in Python:

    def exact_sqrt(x):
        """Calculate the square root of an arbitrarily large integer. 
    
        The result of exact_sqrt(x) is a tuple (a, r) such that a**2 + r = x, where
        a is the largest integer such that a**2 <= x, and r is the "remainder".  If
        x is a perfect square, then r will be zero.
    
        The algorithm used is the "long-hand square root" algorithm, as described at
        http://mathforum.org/library/drmath/view/52656.html
    
        Tobin Fricke 2014-04-23
        Max Planck Institute for Gravitational Physics
        Hannover, Germany
        """
    
        N = 0   # Problem so far
        a = 0   # Solution so far
    
        # We'll process the number two bits at a time, starting at the MSB
        L = x.bit_length()
        L += (L % 2)          # Round up to the next even number
    
        for i in xrange(L, -1, -1):
    
            # Get the next group of two bits
            n = (x >> (2*i)) & 0b11
    
            # Check whether we can reduce the remainder
            if ((N - a*a) << 2) + n >= (a<<2) + 1:
                b = 1
            else:
                b = 0
    
            a = (a << 1) | b   # Concatenate the next bit of the solution
            N = (N << 2) | n   # Concatenate the next bit of the problem
    
        return (a, N-a*a)
    

    You could easily modify this function to conduct additional iterations to calculate the fractional part of the square root. I was most interested in computing roots of large perfect squares.

    I'm not sure how this compares to the "integer Newton's method" algorithm. I suspect that Newton's method is faster, since it can in principle generate multiple bits of the solution in one iteration, while the "long hand" algorithm generates exactly one bit of the solution per iteration.

    Source repo: https://gist.github.com/tobin/11233492

    链接地址: http://www.djcxy.com/p/86636.html

    上一篇: 没有使用sqrt函数查找平方根?

    下一篇: 在python中的整数平方根