user21398
user21398

Reputation: 429

Cube root of negative numbers in a numpy array returns nan

From Numpy documentation:

>>> a = np.arange(10)**3
>>> a
array([  0,   1,   8,  27,  64, 125, 216, 343, 512, 729])
>>> a[2]
8
>>> a[2:5]
array([ 8, 27, 64])
>>> a[:6:2] = -1000    # equivalent to a[0:6:2] = -1000; from start to position 6, exclusive, set every 2nd element to -1000
>>> a
array([-1000,     1, -1000,    27, -1000,   125,   216,   343,   512,   729])
>>> a[ : :-1]                                 # reversed a
array([  729,   512,   343,   216,   125, -1000,    27, -1000,     1, -1000])
>>> 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

Could somebody explain me the last line of code? How does i to the power of 1/3 equal these numbers?

For example -1000^1/3 = nan? What part have I skipped over?

Upvotes: 2

Views: 3011

Answers (3)

aneroid
aneroid

Reputation: 15962

How does i to the power of 1/3 equal these numbers?

This is not just a NumPy or Python-specific feature. It's from math. (In your example, it's numpy handling the math instead of Python, by overriding __pow__ but it works with pure-Python numbers as well.)

>>> 2 ** 5  # 2 raised to 5
32
>>> 32 ** (1/5)  # 5th root of 32
2.0

x ** y (or "x raised to y"), 'y' can be:

  • x ** 2 : "x squared"
  • x ** 3 : "x cubed"
  • x ** 5 : "x raised to 5" or "5th power of x"

It can also be a fraction:

  • x ** (1/2) : "square root of x"
  • x ** (1/3) : "cube root of x"
  • x ** (1/5) : "5th root of x"

Here's a source which explains it better:

the Sqrt process actually undoes what the raising to the power of 2 had done; in other words, in some sense this is the "opposite" process of squaring. Recall from our algebraic rules for powers that a number to a power can be raised to a power again and all we do is multiply the powers; then note that the square root process can be written as raising to the power of ½:

Sqrt(2²) = (2²)½ = 2² × ½ = 2^1 = 2

And for a more mathematical proof: Why Is an Exponent of 1/2 the Same as a Square Root?

Upvotes: 0

Aniket Navlur
Aniket Navlur

Reputation: 1012

In Python, (-1000)**(1/3.) returns a complex number,

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

This happens because the way computer store numbers, 1/3 = 0.33333... is an irrational number which at some point gets approximated and therefore there is a loss in precision


>>> a = np.arange(10)**3
>>> a[:6:2] = -1000
>>> a
array([-1000,     1, -1000,    27, -1000,   125,   216,   343,   512,
         729], dtype=int32)
>>> for i in a:
     print((i)**(1/3.))


nan
1.0
nan
3.0
nan
4.999999999999999
5.999999999999999
6.999999999999999
7.999999999999999
8.999999999999998

Here the values in the ndarray a are of numpy.int32 type.
The code (i)**(1/3.) returns a result of type numpy.float64 since the second argument is a floating point.

>>> [type((i)**(1/3.)) for i in a]
[<class 'numpy.float64'>, <class 'numpy.float64'>, <class 'numpy.float64'>, <class 'numpy.float64'>, <class 'numpy.float64'>, <class 'numpy.float64'>, <class 'numpy.float64'>, <class 'numpy.float64'>, <class 'numpy.float64'>, <class 'numpy.float64'>]

(-1000)**(1/3.) is a complex number and cannot be stored as as numpy.float64 therefore nan


To avoid the nan you can change the dtype of the ndarray to numpy.complex and do the calculations

>>> b = a.astype(np.complex)
>>> b
array([-1000.+0.j,     1.+0.j, -1000.+0.j,    27.+0.j, -1000.+0.j,
         125.+0.j,   216.+0.j,   343.+0.j,   512.+0.j,   729.+0.j])

>>> for i in b:
     print((i)**(1/3.))


(4.999999999999999+8.660254037844384j)
(1+0j)
(4.999999999999999+8.660254037844384j)
(3+0j)
(4.999999999999999+8.660254037844384j)
(4.999999999999999+0j)
(5.999999999999999+0j)
(6.999999999999999+0j)
(7.999999999999999+0j)
(8.999999999999998+0j)

You can take the absolute values of these numbers using abs()

>>> for i in b:
     print(round(abs((i)**(1/3.))))


10.0
1.0
10.0
3.0
10.0
5.0
6.0
7.0
8.0
9.0

Upvotes: 3

Sapan Zaveri
Sapan Zaveri

Reputation: 518

There is inbuilt function in numpy to find cuberoot. Check this out:

print(np.cbrt(a))

Your output will be :

[-10.   1. -10.   3. -10.   5.   6.   7.   8.   9.]

Upvotes: 6

Related Questions