Difference Between the Built-In Pow() and Math.Pow() for Floats, in Python

Difference between the built-in pow() and math.pow() for floats, in Python?

Quick Check

From the signatures, we can tell that they are different:

pow(x, y[, z])

math.pow(x, y)

Also, trying it in the shell will give you a quick idea:

>>> pow is math.pow
False

Testing the differences

Another way to understand the differences in behaviour between the two functions is to test for them:

import math
import traceback
import sys

inf = float("inf")
NaN = float("nan")

vals = [inf, NaN, 0.0, 1.0, 2.2, -1.0, -0.0, -2.2, -inf, 1, 0, 2]

tests = set([])

for vala in vals:
for valb in vals:
tests.add( (vala, valb) )
tests.add( (valb, vala) )

for a,b in tests:
print("math.pow(%f,%f)"%(a,b) )
try:
print(" %f "%math.pow(a,b))
except:
traceback.print_exc()

print("__builtins__.pow(%f,%f)"%(a,b) )
try:
print(" %f "%__builtins__.pow(a,b))
except:
traceback.print_exc()

We can then notice some subtle differences. For example:

math.pow(0.000000,-2.200000)
ValueError: math domain error

__builtins__.pow(0.000000,-2.200000)
ZeroDivisionError: 0.0 cannot be raised to a negative power

There are other differences, and the test list above is not complete (no long numbers, no complex, etc...), but this will give us a pragmatic list of how the two functions behave differently. I would also recommend extending the above test to check for the type that each function returns. You could probably write something similar that creates a report of the differences between the two functions.

math.pow()

math.pow() handles its arguments very differently from the builtin ** or pow(). This comes at the cost of flexibility. Having a look at the source, we can see that the arguments to math.pow() are cast directly to doubles:

static PyObject *
math_pow(PyObject *self, PyObject *args)
{
PyObject *ox, *oy;
double r, x, y;
int odd_y;

if (! PyArg_UnpackTuple(args, "pow", 2, 2, &ox, &oy))
return NULL;
x = PyFloat_AsDouble(ox);
y = PyFloat_AsDouble(oy);
/*...*/

The checks are then carried out against the doubles for validity, and then the result is passed to the underlying C math library.

builtin pow()

The built-in pow() (same as the ** operator) on the other hand behaves very differently, it actually uses the Objects's own implementation of the ** operator, which can be overridden by the end user if need be by replacing a number's __pow__(), __rpow__() or __ipow__(), method.

For built-in types, it is instructive to study the difference between the power function implemented for two numeric types, for example, floats, long and complex.

Overriding the default behaviour

Emulating numeric types is described here. essentially, if you are creating a new type for numbers with uncertainty, what you will have to do is provide the __pow__(), __rpow__() and possibly __ipow__() methods for your type. This will allow your numbers to be used with the operator:

class Uncertain:
def __init__(self, x, delta=0):
self.delta = delta
self.x = x
def __pow__(self, other):
return Uncertain(
self.x**other.x,
Uncertain._propagate_power(self, other)
)
@staticmethod
def _propagate_power(A, B):
return math.sqrt(
((B.x*(A.x**(B.x-1)))**2)*A.delta*A.delta +
(((A.x**B.x)*math.log(B.x))**2)*B.delta*B.delta
)

In order to override math.pow() you will have to monkey patch it to support your new type:

def new_pow(a,b):
_a = Uncertain(a)
_b = Uncertain(b)
return _a ** _b

math.pow = new_pow

Note that for this to work you'll have to wrangle the Uncertain class to cope with an Uncertain instance as an input to __init__()

Difference between Python built-in pow and math pow for large integers

math.pow() always returns a floating-point number, so you are limited by the precision of float (almost always an IEEE 754 double precision number). The built-in pow() on the other hand will use Python's arbitrary precision integer arithmetic when called with integer arguments.

What is the difference between Python's built-in `pow` function and the `**` operator?

I found one use for the pow function over the ** operator. First, ** is really raise to a power and apply an optional modulus, as in a**b % c. But if you include the %, its value can't be None. 2**3 % None is an error. pow is really pow(x, y, z=None).

So, if I want to raise a derived value to a power, I could use the operator

>>> def powerizer(db, index, modulus=None):
... x, y = db.get(index)
... return x**y % modulus
...
>>> db = {"foo":[9,3]}
>>> powerizer(db, "foo", 10)
9

But it fails on the default None modulus.

>>> powerizer(db, "foo")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in powerizer
TypeError: unsupported operand type(s) for %: 'int' and 'NoneType'

pow function to the rescue

>>> def powerizer(db, index, modulus=None):
... x, y = db.get(index)
... return pow(x, y, modulus)
...
>>> powerizer(db, "foo", 10)
9
>>> powerizer(db, "foo")
729

Exponentials in python: x**y vs math.pow(x, y)

Using the power operator ** will be faster as it won’t have the overhead of a function call. You can see this if you disassemble the Python code:

>>> dis.dis('7. ** i')
1 0 LOAD_CONST 0 (7.0)
3 LOAD_NAME 0 (i)
6 BINARY_POWER
7 RETURN_VALUE
>>> dis.dis('pow(7., i)')
1 0 LOAD_NAME 0 (pow)
3 LOAD_CONST 0 (7.0)
6 LOAD_NAME 1 (i)
9 CALL_FUNCTION 2 (2 positional, 0 keyword pair)
12 RETURN_VALUE
>>> dis.dis('math.pow(7, i)')
1 0 LOAD_NAME 0 (math)
3 LOAD_ATTR 1 (pow)
6 LOAD_CONST 0 (7)
9 LOAD_NAME 2 (i)
12 CALL_FUNCTION 2 (2 positional, 0 keyword pair)
15 RETURN_VALUE

Note that I’m using a variable i as the exponent here because constant expressions like 7. ** 5 are actually evaluated at compile time.

Now, in practice, this difference does not matter that much, as you can see when timing it:

>>> from timeit import timeit
>>> timeit('7. ** i', setup='i = 5')
0.2894785532627111
>>> timeit('pow(7., i)', setup='i = 5')
0.41218495570683444
>>> timeit('math.pow(7, i)', setup='import math; i = 5')
0.5655053168791255

So, while pow and math.pow are about twice as slow, they are still fast enough to not care much. Unless you can actually identify the exponentiation as a bottleneck, there won’t be a reason to choose one method over the other if clarity decreases. This especially applies since pow offers an integrated modulo operation for example.


Alfe asked a good question in the comments above:

timeit shows that math.pow is slower than ** in all cases. What is math.pow() good for anyway? Has anybody an idea where it can be of any advantage then?

The big difference of math.pow to both the builtin pow and the power operator ** is that it always uses float semantics. So if you, for some reason, want to make sure you get a float as a result back, then math.pow will ensure this property.

Let’s think of an example: We have two numbers, i and j, and have no idea if they are floats or integers. But we want to have a float result of i^j. So what options do we have?

  • We can convert at least one of the arguments to a float and then do i ** j.
  • We can do i ** j and convert the result to a float (float exponentation is automatically used when either i or j are floats, so the result is the same).
  • We can use math.pow.

So, let’s test this:

>>> timeit('float(i) ** j', setup='i, j = 7, 5')
0.7610865891750791
>>> timeit('i ** float(j)', setup='i, j = 7, 5')
0.7930400942188385
>>> timeit('float(i ** j)', setup='i, j = 7, 5')
0.8946636625872202
>>> timeit('math.pow(i, j)', setup='import math; i, j = 7, 5')
0.5699394063529439

As you can see, math.pow is actually faster! And if you think about it, the overhead from the function call is also gone now, because in all the other alternatives we have to call float().


In addition, it might be worth to note that the behavior of ** and pow can be overridden by implementing the special __pow__ (and __rpow__) method for custom types. So if you don’t want that (for whatever reason), using math.pow won’t do that.

Why is math.pow returning different values than the ** operator?

math.pow always converts it’s arguments to floats first, which are only approximations.

The ** operator uses integers that can never overflow, which means that it always gives a correct result.

Math.pow vs ** casted as a Decimal in Python?

The difference is, as you imply, that math.pow() converts the inputs to floats as stated in the documentation: "Unlike the built-in ** operator, math.pow() converts both its arguments to type float."

Therefore math.pow() also delivers a float as answer, independently of whether the input is Decimal (or int) or whatever. When using numbers that are not exactly representable as a float(but is as Decimal) you are likely to get a more precise answer using the ** operator.

This explains why your loop gives a more exact result in case of using ** since you are working with Decimal numbers raised to an integer. In the second case, you are inadvertently using floats for both calculations and then converting the result to Decimal when the operation is already executed. If you instead work with explicit Decimal values you will see the difference:

>>> Decimal('.8')**500
Decimal('3.507466211043403874762758796E-49')
>>> Decimal(math.pow(Decimal('.8'), 500))
Decimal('3.50746621104350087215129555150772856244326043764431058846880005304485310211166734705824986213804838358790165633656170035364028902957755917668691836297512054443359375E-49')

Thus, in the second case, the Decimal value is automatically casted to a float and the result is the same as for your example above. In the first case, however, the calculation is executed in the Decimal domain and yields a slightly different result.

Python math.pow function needs float()

The problem is not your first argument, but your second. Check out what r is assigned to (In a pinch, add print(repr(r)) just before the pow line. Most likely, you assigned it by accident to a value you don't want - you wanted to write

r = input()

, which calls the input function, but you wrote

r = input

which just creates an alias for input named r.



Related Topics



Leave a reply



Submit