DJCowley
DJCowley

Reputation: 83

Why doesn't numpy.power act element-wise on arrays when the exponent is negative?

What is the difference between numpy.power or ** for negative exponents and / when working with arrays? and why does numpy.power not act element-wise as described in the documentation.

For example, using python 2.7.3:

>>> from __future__ import division
>>> import numpy as np   
>>> A = arange(9).reshape(3,3)
>>> A
array([[0, 1, 2],
       [3, 4, 5],
       [6, 7, 8]])

It appears that ** and numpy.power are not acting element-wise when the exponent is negative

>>> A**-1
array([[-9223372036854775808,                    1,                    0],
       [                   0,                    0,                    0],
       [                   0,                    0,                    0]])
>>> np.power(A, -1)
array([[-9223372036854775808,                    1,                    0],
       [                   0,                    0,                    0],
       [                   0,                    0,                    0]])

Whereas / is acting element-wise

>>> 1/A
array([[        inf,  1.        ,  0.5       ],
       [ 0.33333333,  0.25      ,  0.2       ],
       [ 0.16666667,  0.14285714,  0.125     ]])

I have no such problems when the exponent is positive. Why does it behave differently for negative exponents?

Upvotes: 2

Views: 6142

Answers (2)

Daniel
Daniel

Reputation: 19547

This is primarily an issue of casting. Operators naturally assume that you do not wish to upcast a number to a different type. The closest value of 2**-1 with integers is 0, this can be verified int(2**-1) >>>0.

First create array A of type int:

A = np.arange(9).reshape(3,3)
>>> A.dtype
dtype('int64')

Copy array A to A_float as type float:

>>> A_float = A.astype(float)
>>> A_float.dtype
dtype('float64')

Run the **-1 operation on both:

>>> A_float**-1
array([[        inf,  1.        ,  0.5       ],
       [ 0.33333333,  0.25      ,  0.2       ],
       [ 0.16666667,  0.14285714,  0.125     ]])

>>> A**-1
array([[-9223372036854775808,                    1,                    0],
       [                   0,                    0,                    0],
       [                   0,                    0,                    0]])

Observe numpy does not automatically assume you want to complete this operation as float and attempts to accomplish this with integers. If you signify a float in either operand you will obtain a float output due to the "safe" casting rules:

>>> A**-1.0
array([[        inf,  1.        ,  0.5       ],
       [ 0.33333333,  0.25      ,  0.2       ],
       [ 0.16666667,  0.14285714,  0.125     ]])

Another option is to force np.power to cast the operation as a float:

>>> np.power(A,-1,dtype=float)
array([[        inf,  1.        ,  0.5       ],
       [ 0.33333333,  0.25      ,  0.2       ],
       [ 0.16666667,  0.14285714,  0.125     ]])

I am not sure why you are obtaining a float result with 1/A. 1.0/A works just fine however.

Upvotes: 5

Sudeep Juvekar
Sudeep Juvekar

Reputation: 5068

** or np.power is working, but is performing integer division. Moreover, performing same operations in ipython results in RuntimeWarning of zero division.

RuntimeWarning: divide by zero encountered in true_divide

Now, we can turn same operations into float division by turning operand into float array

A = np.array([[0., 1., 2.], [3., 4., 5.], [6., 7., 8.]])

Then, 1/, ** and np.power behave identically

Upvotes: 2

Related Questions