8

I have started learning Python recently and I've been going through the NumPy official quickstart guide which includes this example for iterating.

>>> a
array([-1000,     1, -1000,    27, -1000,   125,   216,   343,   512,   
729])
>>> for i in a:
...     print(i**(1/3.))
...
nan
1.0
nan
3.0
nan
5.0
6.0
7.0
8.0
9.0

However, if I just try to raise -1000 to the power of (1/3.) outside of the loop it returns a value.

>>> -1000**(1/3.)
-9.999999999999998

With parentheses around -1000 it also returns a value.

>>> (-1000)**(1/3.)
(5+8.660254037844384j)

Why is it that the same action returns nan in the for loop? I'm using Python 3.6.3 :: Anaconda custom (64-bit). I also tried with different fractions that do not round up and it's the same. With a fraction that rounds up to .0 it works though.

I couldn't find a similar question. Excuse me if I'm missing something very obvious.

Edit: A few comments mentioned that the question duplicates NumPy, RuntimeWarning: invalid value encountered in power and it's true, the problem was I didn't see such an error. The discussion there, however, seems to include a few possible workarounds.

Nikolay D
  • 329
  • 3
  • 11
  • You have a point, I'll edit it. – Nikolay D Feb 28 '18 at 12:01
  • @DeepSpace I get the same as OP does with vanilla Python 3.6. Same [here](https://repl.it/repls/BonyWhimsicalKilobyte) too – Ma0 Feb 28 '18 at 12:03
  • @Ev.Kounis Yeah, managed to reproduce this. This only seems to happen with specific numbers – DeepSpace Feb 28 '18 at 12:04
  • 1
    `np.power(-1000, 1/3.)` to reproduce. – ayhan Feb 28 '18 at 12:05
  • 1
    Here's a possible duplicate: https://stackoverflow.com/questions/45384602/numpy-runtimewarning-invalid-value-encountered-in-power – ayhan Feb 28 '18 at 12:07
  • @Ev.Kounis I tried with various negative numbers and fractions, the result was always `nan` if the fraction doesn't round. – Nikolay D Feb 28 '18 at 12:07
  • @ayhan thank you, as there was no RuntimeWarning I couldn't look it up like that. – Nikolay D Feb 28 '18 at 12:09
  • 1
    Possible duplicate of [NumPy, RuntimeWarning: invalid value encountered in power](https://stackoverflow.com/questions/45384602/numpy-runtimewarning-invalid-value-encountered-in-power) – Ma0 Feb 28 '18 at 12:09
  • 1
    numpy.int32 type behaves differently than python int type – CrazyElf Feb 28 '18 at 12:11
  • @NikolayD Probably your environment is silencing those warnings. I think Canopy was doing something like that. – ayhan Feb 28 '18 at 12:16

2 Answers2

11

Exponentiation in python has higher precedence than the negative operator. Thus -1000**(1/3) is equivalent to -(1000**(1/3)).

When you doing this operation inside the loop you get (-1000)**(1/3). This equal to 10 * (-1**(1/3)) which a complex number. Now the array you have, uses a default data type since you did not define any that is determined according to the documentation as follows:

dtype : data-type, optional

The desired data-type for the array. If not given, then the type will be determined as the minimum type required to hold the objects in the sequence. This argument can only be used to ‘upcast’ the array. For downcasting, use the .astype(t) method.

So it is probably np.int16.

Putting all the information together, we can conclude that your array is not equipped with the appropriate dtype attribute to be able to hold the result of (-1000)**(1/3) even though the result exists.

This does not happen outside arrays since there, no dtype is assumed.


Fix \ Workaround:

>>> a = np.array([-1000, 1], dtype=np.complex)
>>> for i in a:
...     print(i**(1/3.))
...
(5+8.66025403784j)
(1+0j)
Community
  • 1
  • 1
DAle
  • 8,990
  • 2
  • 26
  • 45
  • @Ev. Kounis, thanks for promoting this answer to the upper level. – DAle Feb 28 '18 at 12:31
  • If you want to work with complex numbers, there are of course numpy datatypes you can use for that as well, for example `complex128`, which uses a 64 bit float each for the real and imaginary parts. – Håken Lid Feb 28 '18 at 12:34
  • 1
    @HåkenLid We are doing that in the **Fix** section of the answer. – Ma0 Feb 28 '18 at 12:35
  • should take | | of the complex number, not many people would know that is 10. – Gijs Den Hollander Feb 28 '18 at 12:37
  • It's not that the array is not 'able to hold' the result since the result will be in a distinct array, in fact `np.arange(-10, 10, dtype=np.int8)**(1j/3j)` works fine. It is more likely to be something related to [type promotion rules](https://docs.scipy.org/doc/numpy/reference/generated/numpy.result_type.html) (Sorry, couldn't find a good reference) – Paul Panzer Feb 28 '18 at 12:49
  • Thank you for the detailed answer! – Nikolay D Feb 28 '18 at 13:01
0

This is just a short cut to fix it for your question.

 def ownpow(a, b):
        if a > 0:
            return a**b
        if a < 0:
            temp = abs(a)**b
            return -1*temp

    a= np.array([-1000,     1, -1000,    27, -1000,   125,   216,   343,   512,  729]) 

    for i in a:
        print(ownpow(i,(1/3.)))

apparent numpy array values cannot be raised to negative number, as this could result in complex numbers.