Which Is Faster in Python: X**.5 or Math.Sqrt(X)

Which is faster in Python: x**.5 or math.sqrt(x)?

math.sqrt(x) is significantly faster than x**0.5.

import math
N = 1000000
%%timeit
for i in range(N):
z=i**.5

10 loops, best of 3: 156 ms per loop

%%timeit
for i in range(N):
z=math.sqrt(i)

10 loops, best of 3: 91.1 ms per loop

Using Python 3.6.9 (notebook).

Which is more accurate, x**.5 or math.sqrt(x)?

Neither one is more accurate, they both diverge from the actual answer in equal parts:

>>> (8885558**0.5)**2
8885557.9999999981
>>> sqrt(8885558)**2
8885558.0000000019

>>> 2**1023.99999999999
1.7976931348498497e+308

>>> (sqrt(2**1023.99999999999))**2
1.7976931348498495e+308
>>> ((2**1023.99999999999)**0.5)**2
1.7976931348498499e+308

>>> ((2**1023.99999999999)**0.5)**2 - 2**1023.99999999999
1.9958403095347198e+292
>>> (sqrt(2**1023.99999999999))**2 - 2**1023.99999999999
-1.9958403095347198e+292

http://mail.python.org/pipermail/python-list/2003-November/238546.html

The math module wraps the platform C
library math functions of the same
names; math.pow() is most useful if
you need (or just want) high
compatibility with C extensions
calling C's pow().

__builtin__.pow() is the implementation of Python's infix **
operator, and deals with complex
numbers, unbounded integer powers, and
modular exponentiation too (the C
pow() doesn't handle any of those).

** is more complete. math.sqrt is probably just the C implementation of sqrt which is probably related to pow.

Python: why are * and ** faster than / and sqrt()?

The (somewhat unexpected) reason for your results is that Python seems to fold constant expressions involving floating-point multiplication and exponentiation, but not division. math.sqrt() is a different beast altogether since there's no bytecode for it and it involves a function call.

On Python 2.6.5, the following code:

x1 = 1234567890.0 / 4.0
x2 = 1234567890.0 * 0.25
x3 = 1234567890.0 ** 0.5
x4 = math.sqrt(1234567890.0)

compiles to the following bytecodes:

  # x1 = 1234567890.0 / 4.0
4 0 LOAD_CONST 1 (1234567890.0)
3 LOAD_CONST 2 (4.0)
6 BINARY_DIVIDE
7 STORE_FAST 0 (x1)

# x2 = 1234567890.0 * 0.25
5 10 LOAD_CONST 5 (308641972.5)
13 STORE_FAST 1 (x2)

# x3 = 1234567890.0 ** 0.5
6 16 LOAD_CONST 6 (35136.418286444619)
19 STORE_FAST 2 (x3)

# x4 = math.sqrt(1234567890.0)
7 22 LOAD_GLOBAL 0 (math)
25 LOAD_ATTR 1 (sqrt)
28 LOAD_CONST 1 (1234567890.0)
31 CALL_FUNCTION 1
34 STORE_FAST 3 (x4)

As you can see, multiplication and exponentiation take no time at all since they're done when the code is compiled. Division takes longer since it happens at runtime. Square root is not only the most computationally expensive operation of the four, it also incurs various overheads that the others do not (attribute lookup, function call etc).

If you eliminate the effect of constant folding, there's little to separate multiplication and division:

In [16]: x = 1234567890.0

In [17]: %timeit x / 4.0
10000000 loops, best of 3: 87.8 ns per loop

In [18]: %timeit x * 0.25
10000000 loops, best of 3: 91.6 ns per loop

math.sqrt(x) is actually a little bit faster than x ** 0.5, presumably because it's a special case of the latter and can therefore be done more efficiently, in spite of the overheads:

In [19]: %timeit x ** 0.5
1000000 loops, best of 3: 211 ns per loop

In [20]: %timeit math.sqrt(x)
10000000 loops, best of 3: 181 ns per loop

edit 2011-11-16: Constant expression folding is done by Python's peephole optimizer. The source code (peephole.c) contains the following comment that explains why constant division isn't folded:

    case BINARY_DIVIDE:
/* Cannot fold this operation statically since
the result can depend on the run-time presence
of the -Qnew flag */
return 0;

The -Qnew flag enables "true division" defined in PEP 238.

Is there any advantage using math.sqrt(num) over num**0.5 in Python

They is a subtle difference in their behavior. x**n first tries x.__pow__(n). If that call returns NotImplemented, then n.__rpow__(x) is called.

>>> (2).__pow__(0.5)
NotImplemented
>>> (0.5).__rpow__(2)
1.4142135623730951

math.sqrt(x) converts x to a float (a C double behind the scenes) and then calls the C math library.

>>> class F(object):
... def __init__(self, value):
... self.value = value
... def __float__(self):
... print("hi!")
... return float(self.value)
...
>>> a=F(2)
>>> math.sqrt(a)
hi!
1.4142135623730951

The difference is usually not important for the normal numeric types in Python but other numeric types can behave differently. gmpy2 implements arbitrary-precision arithmetic for integer and floating point. Values that cause an overflow in math.sqrt() can be handled by **.

>>> import gmpy2
>>> math.sqrt(gmpy2.mpz("1"*999))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
OverflowError: 'mpz' too large to convert to float
>>> gmpy2.mpz("1"*999)**0.5
mpfr('1.0540925533894598e+499')
>>>

Python - doing math with built-ins vs math module

If calculating square root of a constant integer, the ** operator maybe several times faster than sqrt, but when using a variable instead, sqrt is faster than both ** and math.sqrt:

In [38]: %timeit -n1000000 3**.5
1000000 loops, best of 3: 46.7 ns per loop

In [39]: %timeit -n1000000 sqrt(3)
1000000 loops, best of 3: 312 ns per loop

In [40]: %timeit -n1000000 math.sqrt(3)
1000000 loops, best of 3: 377 ns per loop

In [41]: x=3

In [42]: %timeit -n1000000 x**.5
1000000 loops, best of 3: 469 ns per loop

In [43]: %timeit -n1000000 sqrt(x)
1000000 loops, best of 3: 327 ns per loop

In [44]: %timeit -n1000000 math.sqrt(x)
1000000 loops, best of 3: 430 ns per loop

How do I calculate square root in Python?

Option 1: math.sqrt()

The math module from the standard library has a sqrt function to calculate the square root of a number. It takes any type that can be converted to float (which includes int) as an argument and returns a float.

>>> import math
>>> math.sqrt(9)
3.0

Option 2: Fractional exponent

The power operator (**) or the built-in pow() function can also be used to calculate a square root. Mathematically speaking, the square root of a equals a to the power of 1/2.

The power operator requires numeric types and matches the conversion rules for binary arithmetic operators, so in this case it will return either a float or a complex number.

>>> 9 ** (1/2)
3.0
>>> 9 ** .5 # Same thing
3.0
>>> 2 ** .5
1.4142135623730951

(Note: in Python 2, 1/2 is truncated to 0, so you have to force floating point arithmetic with 1.0/2 or similar. See Why does Python give the "wrong" answer for square root?)

This method can be generalized to nth root, though fractions that can't be exactly represented as a float (like 1/3 or any denominator that's not a power of 2) may cause some inaccuracy:

>>> 8 ** (1/3)
2.0
>>> 125 ** (1/3)
4.999999999999999

Edge cases

Negative and complex

Exponentiation works with negative numbers and complex numbers, though the results have some slight inaccuracy:

>>> (-25) ** .5  # Should be 5j
(3.061616997868383e-16+5j)
>>> 8j ** .5 # Should be 2+2j
(2.0000000000000004+2j)

Note the parentheses on -25! Otherwise it's parsed as -(25**.5) because exponentiation is more tightly binding than unary negation.

Meanwhile, math is only built for floats, so for x<0, math.sqrt(x) will raise ValueError: math domain error and for complex x, it'll raise TypeError: can't convert complex to float. Instead, you can use cmath.sqrt(x), which is more more accurate than exponentiation (and will likely be faster too):

>>> import cmath
>>> cmath.sqrt(-25)
5j
>>> cmath.sqrt(8j)
(2+2j)

Precision

Both options involve an implicit conversion to float, so floating point precision is a factor. For example:

>>> n = 10**30
>>> x = n**2
>>> root = x**.5
>>> n == root
False
>>> n - root # how far off are they?
0.0
>>> int(root) - n # how far off is the float from the int?
19884624838656

Very large numbers might not even fit in a float and you'll get OverflowError: int too large to convert to float. See Python sqrt limit for very large numbers?

Other types

Let's look at Decimal for example:

Exponentiation fails unless the exponent is also Decimal:

>>> decimal.Decimal('9') ** .5
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for ** or pow(): 'decimal.Decimal' and 'float'
>>> decimal.Decimal('9') ** decimal.Decimal('.5')
Decimal('3.000000000000000000000000000')

Meanwhile, math and cmath will silently convert their arguments to float and complex respectively, which could mean loss of precision.

decimal also has its own .sqrt(). See also calculating n-th roots using Python 3's decimal module

Python - doing math with built-ins vs math module

If calculating square root of a constant integer, the ** operator maybe several times faster than sqrt, but when using a variable instead, sqrt is faster than both ** and math.sqrt:

In [38]: %timeit -n1000000 3**.5
1000000 loops, best of 3: 46.7 ns per loop

In [39]: %timeit -n1000000 sqrt(3)
1000000 loops, best of 3: 312 ns per loop

In [40]: %timeit -n1000000 math.sqrt(3)
1000000 loops, best of 3: 377 ns per loop

In [41]: x=3

In [42]: %timeit -n1000000 x**.5
1000000 loops, best of 3: 469 ns per loop

In [43]: %timeit -n1000000 sqrt(x)
1000000 loops, best of 3: 327 ns per loop

In [44]: %timeit -n1000000 math.sqrt(x)
1000000 loops, best of 3: 430 ns per loop


Related Topics



Leave a reply



Submit