So I guess what makes this tricky is that: - We want the behavior to the same for multiple-element arrays, single-element arrays, zero-dimensional arrays, and scalars -- the shape of the data shouldn't affect the semantics of **
- We also want the numpy scalar behavior to match the Python scalar behavior - For Python scalars, int ** (positive int) returns an int, but int ** (negative int) returns a float. - For arrays, int ** (positive int) and int ** (negative int) _have_ to return the same type, because in general output types are always a function of the input types and *can't* look at the specific values involved, and in specific because if you do array([2, 3]) ** array([2, -2]) you can't return an array where the first element is int and the second is float. Given these immutable and contradictory constraints, the last bad option IMHO would be that we make int ** (negative int) an error in all cases, and the error message can suggest that instead of writing np.array(2) ** -2 they should instead write np.array(2) ** -2.0 (And similarly for np.int64(2) ** -2 versus np.int64(2) ** -2.0.) Definitely annoying, but all the other options seem even more inconsistent and confusing, and likely to encourage the writing of subtly buggy code... (I especially have in mind numpy's habit of silently switching between scalars and zero-dimensional arrays -- so it's easy to write code that you think handles arbitrary array dimensions, and it even passes all your tests, but then it fails when someone passes in a different shape data and triggers some scalar/array inconsistency. E.g. if we make ** -2 work for scalars but not arrays, then this code: def f(arr): return np.sum(arr, axis=0) ** -2 works as expected for 1-d input, tests pass, everyone's happy... but as soon as you try to pass in higher dimensional integer input it will fail.) -n On Thu, May 19, 2016 at 2:37 PM, Charles R Harris <charlesr.har...@gmail.com> wrote: > Hi All, > > There are currently several pull requests apropos integer arrays/scalars to > integer powers and, because the area is messy and involves tradeoffs, I'd > like to see some discussion here on the list before proceeding. > > Scalars in 1.10 > > In [1]: 1 ** -1 > Out[1]: 1.0 > > In [2]: int16(1) ** -1 > Out[2]: 1 > > In [3]: int32(1) ** -1 > Out[3]: 1 > > In [4]: int64(1) ** -1 > Out[4]: 1.0 > > In [5]: 2 ** -1 > Out[5]: 0.5 > > In [6]: int16(2) ** -1 > Out[6]: 0 > > In [7]: int32(2) ** -1 > Out[7]: 0 > > In [8]: int64(2) ** -1 > Out[8]: 0.5 > > In [9]: 0 ** -1 > --------------------------------------------------------------------------- > ZeroDivisionError Traceback (most recent call last) > <ipython-input-9-fd405d6cf4bc> in <module>() > ----> 1 0 ** -1 > > ZeroDivisionError: 0.0 cannot be raised to a negative power > > In [10]: int16(0) ** -1 > /home/charris/.local/bin/ipython:1: RuntimeWarning: divide by zero > encountered in power > #!/usr/bin/python > /home/charris/.local/bin/ipython:1: RuntimeWarning: invalid value > encountered in power > #!/usr/bin/python > Out[10]: -9223372036854775808 > > In [11]: int32(0) ** -1 > Out[11]: -9223372036854775808 > > In [12]: int64(0) ** -1 > /home/charris/.local/bin/ipython:1: RuntimeWarning: divide by zero > encountered in long_scalars > #!/usr/bin/python > Out[12]: inf > > Proposed > > for non-zero numbers the return type should be float. > for zero numbers a zero division error should be raised. > > > Scalar Arrays in 1.10 > > In [1]: array(1, dtype=int16) ** -1 > Out[1]: 1 > > In [2]: array(1, dtype=int32) ** -1 > Out[2]: 1 > > In [3]: array(1, dtype=int64) ** -1 > Out[3]: 1 > > In [4]: array(2, dtype=int16) ** -1 > Out[4]: 0 > > In [5]: array(2, dtype=int32) ** -1 > Out[5]: 0 > > In [6]: array(2, dtype=int64) ** -1 > Out[6]: 0 > > In [7]: array(0, dtype=int16) ** -1 > /home/charris/.local/bin/ipython:1: RuntimeWarning: divide by zero > encountered in power > #!/usr/bin/python > /home/charris/.local/bin/ipython:1: RuntimeWarning: invalid value > encountered in power > #!/usr/bin/python > Out[7]: -9223372036854775808 > > In [8]: array(0, dtype=int32) ** -1 > Out[8]: -9223372036854775808 > > In [9]: array(0, dtype=int64) ** -1 > Out[9]: -9223372036854775808 > > In [10]: type(array(1, dtype=int64) ** -1) > Out[10]: numpy.int64 > > In [11]: type(array(1, dtype=int32) ** -1) > Out[11]: numpy.int64 > > In [12]: type(array(1, dtype=int16) ** -1) > Out[12]: numpy.int64 > > Note that the return type is always int64 in all these cases. However, type > is preserved in non-scalar arrays, although the value of int16 is not > compatible with int32 and int64 for zero division. > > In [22]: array([0]*2, dtype=int16) ** -1 > Out[22]: array([0, 0], dtype=int16) > > In [23]: array([0]*2, dtype=int32) ** -1 > Out[23]: array([-2147483648, -2147483648], dtype=int32) > > In [24]: array([0]*2, dtype=int64) ** -1 > Out[24]: array([-9223372036854775808, -9223372036854775808]) > > Proposed: > > Raise an ZeroDivisionError for zero division, that is, in the ufunc. > Scalar arrays to return scalar arrays > > > Thoughts? > > Chuck > > > > _______________________________________________ > NumPy-Discussion mailing list > NumPy-Discussion@scipy.org > https://mail.scipy.org/mailman/listinfo/numpy-discussion > -- Nathaniel J. Smith -- https://vorpus.org _______________________________________________ NumPy-Discussion mailing list NumPy-Discussion@scipy.org https://mail.scipy.org/mailman/listinfo/numpy-discussion