# Python Exponentiation Tutorial | Exponentiation In Python Tutorial

Exponentiation – Exponentiation can be used by using the builtin pow-function or the ** operator. Learn More about it here.

## Exponentiation using builtins: ** and pow()

Exponentiation can be used by using the builtin pow-function or the ** operator:

`2**3 # 8pow(2, 3) # 8`

For most (all in Python 2.x) arithmetic operations the result’s type will be that of the wider operand. This is not true for **; the following cases are exceptions from this rule:

`Base: int, exponent: int < 0:`
`2**-3`

### Out: 0.125 (result is a float)

This is also valid for Python 3.x.

Before Python 2.2.0, this raised a ValueError.

Base: int < 0 or float < 0, exponent: float != int

`(-2) ** (0.5) # also (-2.) ** (0.5)`

#### Out: (8.659560562354934e-17+1.4142135623730951j) (result is complex)

Before python 3.0.0, this raised a ValueError.

The operator module contains two functions that are equivalent to the **-operator:

`import operatoroperator.pow(4, 2) # 16operator.pow(4, 3) # 64`

or one could directly call the pow method:

`val1, val2 = 4, 2val1.pow(val2) # 16val2.rpow(val1) # 16`

## Square root: math.sqrt() and cmath.sqrt

The math module contains the math.sqrt()-function that can compute the square root of any number (that can be converted to a float) and the result will always be a float:

`import mathmath.sqrt(9) # 3.0math.sqrt(11.11) # 3.3331666624997918math.sqrt(Decimal('6.25')) # 2.5`

The math.sqrt() function raises a ValueError if the result would be complex:

`math.sqrt(-10)`
`ValueError: math domain error`

math.sqrt(x) is faster than math.pow(x, 0.5) or x ** 0.5 but the precision of the results is the same. The cmath module is extremely similar to the math module, except for the fact it can compute complex numbers and all of its results are in the form of a + bi. It can also use .sqrt():

`import cmathcmath.sqrt(4) # 2+0jcmath.sqrt(-4) # 2j`

What’s with the j? j is the equivalent to the square root of -1. All numbers can be put into the form a + bi, or in this case, a + bj. a is the real part of the number like the 2 in 2+0j. Since it has no imaginary part, b is 0. b represents part of the imaginary part of the number like the 2 in 2j. Since there is no real part in this, 2j can also be written as 0 + 2j.

## Modular exponentiation: pow() with 3 arguments

Supplying pow() with 3 arguments pow(a, b, c) evaluates the modular exponentiation ab mod c:

`pow(3, 4, 17) # 13`

## equivalent unoptimized expression:

`3 ** 4 % 17 # 13`

## steps:

`3 ** 4 # 8181 % 17 # 13For built-in types using modular exponentiation is only possible if:`

First argument is an int

Second argument is an int >= 0

Third argument is an int != 0

These restrictions are also present in python 3.x

For example one can use the 3-argument form of pow to define a modular inverse function:

`def modular_inverse(x, p):"""Find a such as a·x ≡ 1 (mod p), assuming p is prime."""return pow(x, p-2, p)`

[modular_inverse(x, 13) for x in range(1,13)]

## Exponentiation: Computing large integer roots

Even though Python natively supports big integers, taking the nth root of very large numbers can fail in Python.

`x = 2 ** 100cube = x ** 3`
`root = cube ** (1.0 / 3)`

OverflowError: long int too large to convert to float

When dealing with such large integers, you will need to use a custom function to compute the nth root of a number.

`def nth_root(x, n):Start with some reasonable bounds around the nth root. upper_bound = 1while upper_bound ** n <= x: upper_bound *= 2 lower_bound = upper_bound // 2 Keep searching for a better result as long as the bounds make sense. while lower_bound < upper_bound: mid = (lower_bound + upper_bound) // 2 mid_nth = mid ** n if lower_bound < mid and mid_nth < x: lower_bound = mid elif upper_bound > mid and mid_nth > x: upper_bound = midelse:Found perfect nth root. return midreturn mid + 1x = 2 ** 100cube = x ** 3root = nth_root(cube, 3)x == root`

## Exponentiation using the math module:math.pow()

The math-module contains another math.pow() function. The diﬀerence to the builtin pow()-function or ** operator is that the result is always a float:

`import mathmath.pow(2, 2) # 4.0math.pow(-2., 2) # 4.0`

Which excludes computations with complex inputs:

`math.pow(2, 2+0j)`

TypeError: can’t convert complex to float

and computations that would lead to complex results:

`math.pow(-2, 0.5)`

ValueError: math domain error

## Exponential function: math.exp() and cmath.exp()

Both the math and cmath-module contain the Euler number: e and using it with the builtin pow()-function or **-operator works mostly like math.exp():

`import mathmath.e ** 2 # 7.3890560989306495math.exp(2) # 7.38905609893065import cmathcmath.e ** 2 # 7.3890560989306495cmath.exp(2) # (7.38905609893065+0j)`

However the result is diﬀerent and using the exponential function directly is more reliable than builtin exponentiation with base math.e:

`print(math.e ** 10) # 22026.465794806703print(math.exp(10)) # 22026.465794806718print(cmath.exp(10).real) # 22026.465794806718difference starts here ---------------^`

## Exponential function minus 1: math.expm1()

The math module contains the expm1()-function that can compute the expression math.e ** x – 1 for very small x with higher precision than math.exp(x) or cmath.exp(x) would allow:

`import mathprint(math.e ** 1e-3 - 1) # 0.0010005001667083846print(math.exp(1e-3) - 1) # 0.0010005001667083846print(math.expm1(1e-3)) # 0.0010005001667083417`

### ——————^

For very small x the diﬀerence gets bigger:

`print(math.e ** 1e-15 - 1) # 1.1102230246251565e-15print(math.exp(1e-15) - 1) # 1.1102230246251565e-15print(math.expm1(1e-15)) # 1.0000000000000007e-15`

### ^——————-

The improvement is significant in scientific computing. For example the Planck’s law contains an exponential function minus 1:

`def planks_law(lambda_, T):from scipy.constants import h, k, c # If no scipy installed hardcode these!return 2 * h * c ** 2 / (lambda_ ** 5 * math.expm1(h * c / (lambda_ * k * T)))def planks_law_naive(lambda_, T):from scipy.constants import h, k, c # If no scipy installed hardcode these!return 2 * h * c ** 2 / (lambda_ ** 5 * (math.e ** (h * c / (lambda_ * k * T)) - 1))planks_law(100, 5000) # 4.139080074896474e-19planks_law_naive(100, 5000) # 4.139080073488451e-19`

#### ^———-

`planks_law(1000, 5000) # 4.139080128493406e-23planks_law_naive(1000, 5000) # 4.139080233183142e-23`

## Magic methods and exponentiation: builtin, math and cmath

Supposing you have a class that stores purely integer values:

`class Integer(object):def init(self, value):self.value = int(value) # Cast to an integerdef repr(self):return '{cls}({val})'.format(cls=self.class.name, val=self.value)def pow(self, other, modulo=None):if modulo is None:print('Using pow')return self.class(self.value ** other)else:print('Using pow with modulo')return self.class(pow(self.value, other, modulo))def float(self):print('Using float')return float(self.value)def complex(self):print('Using complex')return complex(self.value, 0)`

Using the builtin pow function or ** operator always calls pow:

`Integer(2) ** 2 # Integer(4)`

### Prints: Using pow

`Integer(2) ** 2.5 # Integer(5)`

### Prints: Using pow

`pow(Integer(2), 0.5) # Integer(1)`

#### Prints: Using pow

`operator.pow(Integer(2), 3) # Integer(8)`
##### Prints: Using pow
`operator.pow(Integer(3), 3) # Integer(27)`

#### Prints: Using pow

The second argument of the pow() method can only be supplied by using the builtin-pow() or by directly calling the method:

`pow(Integer(2), 3, 4) # Integer(0)`
`Prints: Using pow with modulo`
`Integer(2).pow(3, 4) # Integer(0)`
`Prints: Using pow with modulo`

While the math-functions always convert it to a float and use the float-computation:

`import math`
`math.pow(Integer(2), 0.5) # 1.4142135623730951`
`Prints: Using float`

cmath-functions try to convert it to complex but can also fallback to float if there is no explicit conversion to complex:

`import cmathcath.exp(Integer(2)) # (7.38905609893065+0j)`
`Prints: Using complex`
`del Integer.complex # Deleting complex method - instances cannot be cast to complexcmath.exp(Integer(2)) # (7.38905609893065+0j)`
`Prints: Using float`

Neither math nor cmath will work if also the float()-method is missing:

`del Integer.float # Deleting complex methodmath.sqrt(Integer(2)) # also cmath.exp(Integer(2))`

TypeError: a float is required

## Exponentiation: Roots: nth-root with fractional exponents

While the math.sqrt function is provided for the specific case of square roots, it’s often convenient to use the exponentiation operator (**) with fractional exponents to perform nth-root operations, like cube roots.

The inverse of an exponentiation is exponentiation by the exponent’s reciprocal. So, if you can cube a number by putting it to the exponent of 3, you can find the cube root of a number by putting it to the exponent of 1/3.

`x = 3y = x ** 3y27z = y ** (1.0 / 3)z3.0z == xTrue`
SHARE