2

A negative numpy.float64 exponentiated with a fractional (i.e., decimal, i.e., rational) number will yield a nan result and a warning.

The same number using Python's float type returns a complex result.

Here is a minimal example using Python 3.6.6 (for a comment on Python 2.7.15, see below):

>>> import numpy as np
>>> f = -2.0
>>> npf = np.float64(-2.0)
>>> f**1.1
(-2.0386342710747223-0.6623924280875919j)
>>> npf ** 1.1
__main__:1: RuntimeWarning: invalid value encountered in double_scalars
nan

I tried the numpy.power function getting a different warning and the same result.

>>> np.power(f, 1.1)
__main__:1: RuntimeWarning: invalid value encountered in power
nan
>>> np.power(npf, 1.1)
nan

The warning in the latter appears only after whatever is executed first.

I ran into this using numpy.arrays of floats, which in all other cases(?) just behave the same as Python floats. The conversion from float to numpy.float64 happens implicitly so it took me a while to find the source of the problem.

Now, I can get around this by explicitly converting to or specifying the dtype when creating the array as numpy.complex:

>>> npc = np.complex(-2.0)
>>> npc ** 1.1
(-2.0386342710747223-0.6623924280875919j)
>>> np.power(npc, 1.1)
(-2.0386342710747223-0.66239242808759191j)

(note the different precision of the output O_o, I can live with that, though)

My question is: Why?? Why doesn't numpy return a numpy.complex when necessary. It does convert to numpy.float64 when, e.g., dividing a numpy.int64:

>>> ai = np.array([1])
>>> ai.dtype
dtype('int64')
>>> ai/2
array([ 0.5])
>>> (ai/2).dtype
dtype('float64')

Why not apply the same philosophy when numpy.float64 is not capable of expressing the result of a calculation and use numpy.complex64 instead?

comment on Python 2.7.15: with this version, exponentiating a float with a fractional number throws an exception, explicitly using complex solves the problem:

>>> f ** 1.1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: negative number cannot be raised to a fractional power
>>> complex(-2.0) ** 1.1
(-2.0386342710747223-0.6623924280875919j)

This is equivalent to the behaviour of numpy.

steffen
  • 8,572
  • 11
  • 52
  • 90
  • 1
    Same reason [you can't raise a numpy integer to a negative power](https://stackoverflow.com/questions/43287311/why-cant-i-raise-to-a-negative-power-in-numpy); the output dtype is based on the input dtypes, not the input values. – user2357112 Oct 08 '18 at 19:00
  • @user2357112: the output dtype is *not* based on the input dtypes, at least not consistently, as shown in the example where a `numpy.int64` is divided and yields a `numpy.float64` result. – steffen Oct 08 '18 at 19:57
  • And if you tried that with any other `numpy.int64`, you would also get a `numpy.float64`. It doesn't matter what the value of the int64 is; knowing the dtypes of the inputs is enough to know that the result will be a float64. – user2357112 Oct 08 '18 at 19:59
  • You may have misinterpreted my first comment as saying that the operation doesn't matter for determining the dtype. The operation matters; different operations on two int64 values can give different dtypes, but the same operation on different int64 values will have a consistent output dtype, barring type "demotion" on mixed scalar/array operations. – user2357112 Oct 08 '18 at 20:04
  • @user2357112 : yes, now I see... you are right. And while in the case of the division it is not a big deal going from int64 to float64, it *is* (e.g. memory-wise) going from float64 to complex. mmhh.. makes sense and I don't like it O_o – steffen Oct 10 '18 at 05:30

1 Answers1

0

Probably the numpy developers just did not think to cover this case. You could put up an issue on Github. Otherwise, you will just have to do the complex conversion explicitly. It would be good to put in the issue so that the numpy developers can work on it.

HackerBoss
  • 829
  • 7
  • 16