I chose these numbers randomly, but these results seem to be consistent --- a float exponent is 25%-50% faster than an integer one. How are these handled differently?
In [209]: %timeit -n 100000 -r 100 np.power(3.71242, 7)
100000 loops, best of 100: 3.45 µs per loop
In [210]: %timeit -n 100000 -r 100 np.power(3.71242, 7.0)
100000 loops, best of 100: 1.98 µs per loop
NumPy Arrays are faster than Python Lists because of the following reasons: An array is a collection of homogeneous data-types that are stored in contiguous memory locations.
power() function takes two main arguments: 1) The array of base 2). The np. power() returns the array with elements of the first array raised to the power element of the second array. This means if we have two arrays (of the same size ) arr1 and arr2, then numpy.
np.power
is a universal function (ufunc). These functions can be used on scalars and arrays which have a variety of different datatypes, but must first check the type of input values so that they can determine which internal loop to use to generate suitable output values.
If the input types do not map to any of the ufunc's predefined loops, the ufunc will try to cast the input values to suitable types (unless it is told otherwise). This checking and conversion of input values has a performance cost associated with it, explaining the timings observed in the question.
The types
attribute of a ufunc shows how input datatypes will map to an output datatype. Below is the list of mappings for np.power
:
>>> np.power.types # 'input input -> output'
['bb->b', 'BB->B', 'hh->h', 'HH->H', 'ii->i', 'II->I', 'll->l', 'LL->L', 'qq->q',
'QQ->Q', 'ee->e', 'ff->f', 'dd->d', 'gg->g', 'FF->F', 'DD->D', 'GG->G', 'OO->O']
Floating-point numbers belong to character code 'g'
, Python integers belong to 'l'
. A full list of these character codes can be found here.
Note that for this ufunc, the datatypes of the two input values must be the same. There is no mapping for a mix of float
and int
input datatypes, for example.
But we can still give np.power
different datatypes and let it cast the values to appropriate datatypes. For a float
and an int
, a float64
number is returned:
>>> np.power(3.71242, 7).dtype
dtype('float64')
Above you can see that the only input which maps to the float64
character code g
is two other g
values: 'gg->g'
.
So, behind the scenes, np.power(3.71242, 7)
took a Python float
and a Python int
and had to decide which it could safely recast and to what type. The int
value was safely promoted to a float type g
. The ufunc then knew which loop to run and returned another g
value.
For this reason, not mixing input datatypes results in better performance for np.power
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With