Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using exponentiation **0.5 less efficient than math.sqrt?

A quote from "Python Programming: An Introduction to Computer Science"

We could have taken the square root using exponentiation **. Using math.sqrt is somewhat more efficient.

"Somewhat", but to what extent, and how?

like image 909
Robert Avatar asked Jul 09 '11 21:07

Robert


People also ask

Is math sqrt faster than Numpy sqrt?

It turns out that the sqrt() function from the standard Python math module is about seven times faster than the corresponding sqrt() function from numpy. As a side note, I learned that it is slightly faster (5-10%) to use the form “from math import sqrt” than it is to use “import math” and “math. sqrt()”.

Is math sqrt slow?

The interviewer is right. sqrt() is "slow," not slow. Fundamentally, the operation is more complex than an addition or division.

How to write √ in Python?

sqrt() function is an inbuilt function in Python programming language that returns the square root of any number. Syntax: math.sqrt(x) Parameter: x is any number such that x>=0 Returns: It returns the square root of the number passed in the parameter.

Does math sqrt return a float Python?

The return value of sqrt() is the square root of x , as a floating point number. In the example, this would be 5.0 . Let's take a look at some examples of how to (and how not to) use sqrt() .


3 Answers

Theoretically, hammar's answer and duffymo's answer are good guesses. But in practice, on my machine, it's not more efficient:

>>> import timeit
>>> timeit.timeit(stmt='[n ** 0.5 for n in range(100)]', setup='import math', number=10000)
0.15518403053283691
>>> timeit.timeit(stmt='[math.sqrt(n) for n in range(100)]', setup='import math', number=10000)
0.17707490921020508

Part of the problem is the . operation. If you import sqrt directly into the namespace, you get a slight improvement.

>>> timeit.timeit(stmt='[sqrt(n) for n in range(100)]', setup='from math import sqrt', number=10000)
0.15312695503234863

Key word there: slight.

Further testing indicates that as the number gets larger, the benefit you get from using sqrt increases. But still not by a lot!

>>> timeit.timeit(stmt='[n ** 0.5 for n in range(1000000)]', setup='import math', number=1)
0.18888211250305176
>>> timeit.timeit(stmt='[math.sqrt(n) for n in range(1000000)]', setup='import math', number=1)
0.18425297737121582
>>> timeit.timeit(stmt='[sqrt(n) for n in range(1000000)]', setup='from math import sqrt', number=1)
0.1571958065032959
like image 87
senderle Avatar answered Oct 14 '22 01:10

senderle


No need to guess the implementation, we can read the code!

math.sqrt is a thin wrapper about sqrt from the standard C library: see mathmodule.c, line 956

The ** operator has multiple implementations depending on the types of the arguments, but in the case of a floating-point exponent, it eventually dispatches to pow from the standard C library (see floatobject.c line 783).

Modern CPUs often have special square root instructions which general exponentiation routines don't use (compare and contrast the implementations of pow and sqrt in glibc for x86-64, for example). But once all the interpreter overhead is added (byte codes, type checking, method dispatch etc), the difference in raw speed doesn't matter all that much, and can be dominated by issues like whether you call sqrt directly or look it up via the math module (as shown by the timings in other answers).

like image 21
Gareth Rees Avatar answered Oct 14 '22 02:10

Gareth Rees


** has to support any exponent while math.sqrt knows it's always 0.5. math.sqrt can therefore use a more specialized (and therefore probably more efficient) algorithm.

like image 38
hammar Avatar answered Oct 14 '22 02:10

hammar