![](https://secure.gravatar.com/avatar/96dd777e397ab128fedab46af97a3a4a.jpg?s=120&d=mm&r=g)
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
![](https://secure.gravatar.com/avatar/97c543aca1ac7bbcfb5279d0300c8330.jpg?s=120&d=mm&r=g)
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.harris@gmail.com> wrote:
-- Nathaniel J. Smith -- https://vorpus.org
![](https://secure.gravatar.com/avatar/96dd777e397ab128fedab46af97a3a4a.jpg?s=120&d=mm&r=g)
On Thu, May 19, 2016 at 9:30 PM, Nathaniel Smith <njs@pobox.com> wrote:
Hmm, the Alexandrian solution. The main difficulty with this solution that this will likely to break working code. We could try it, or take the safe route of raising a (Visible)DeprecationWarning. The other option is to simply treat the negative power case uniformly as floor division and raise an error on zero division, but the difference from Python power would be highly confusing. I think I would vote for the second option with a DeprecationWarning. <snip> Chuck
![](https://secure.gravatar.com/avatar/96dd777e397ab128fedab46af97a3a4a.jpg?s=120&d=mm&r=g)
On Fri, May 20, 2016 at 12:35 PM, Charles R Harris < charlesr.harris@gmail.com> wrote:
I suspect that the different behavior of int64 on my system is due to inheritance from Python 2.7 int In [1]: isinstance(int64(1), int) Out[1]: True That different behavior is also carried over for Python 3. Chuck
![](https://secure.gravatar.com/avatar/97c543aca1ac7bbcfb5279d0300c8330.jpg?s=120&d=mm&r=g)
On Fri, May 20, 2016 at 11:35 AM, Charles R Harris <charlesr.harris@gmail.com> wrote:
Right, sorry, I was talking about the end goal -- there's a separate question of how we get there. Pretty much any solution is going to require some sort of deprecation cycle though I guess, and at least the deprecate -> error transition is a lot easier than the working -> working different transition.
So "floor division" here would mean that k ** -n == 0 for all k and n except for k == 1, right? In addition to the consistency issue, that doesn't seem like a behavior that's very useful to anyone... -n -- Nathaniel J. Smith -- https://vorpus.org
![](https://secure.gravatar.com/avatar/96dd777e397ab128fedab46af97a3a4a.jpg?s=120&d=mm&r=g)
On Fri, May 20, 2016 at 1:15 PM, Nathaniel Smith <njs@pobox.com> wrote:
And -1 as well. The virtue is consistancy while deprecating. Or we could just back out the current changes in master and throw in deprecation warnings. That has the virtue of simplicity and not introducing possible code breaks. Chuck
![](https://secure.gravatar.com/avatar/ad13088a623822caf74e635a68a55eae.jpg?s=120&d=mm&r=g)
On Fri, May 20, 2016 at 3:23 PM, Charles R Harris <charlesr.harris@gmail.com
wrote:
can numpy cast to float by default for power or **? At least then we always get correct numbers. Are there dominant usecases that require default return dtype int? AFAICS, it's always possible to choose the return dtype in np.power. Josef
![](https://secure.gravatar.com/avatar/97c543aca1ac7bbcfb5279d0300c8330.jpg?s=120&d=mm&r=g)
On May 20, 2016 12:44 PM, <josef.pktd@gmail.com> wrote: [...]
can numpy cast to float by default for power or **?
Maybe? The question is whether there are any valid use cases for getting ints back:
np.array([1, 2, 3]) ** 2 array([1, 4, 9])
It's not 100% obvious to me but intuitively this seems like an operation that we probably want to support? Especially since there's a reasonable range of int64 values that can't be represented exactly as floats. -n
![](https://secure.gravatar.com/avatar/ad13088a623822caf74e635a68a55eae.jpg?s=120&d=mm&r=g)
On Fri, May 20, 2016 at 6:54 PM, Nathaniel Smith <njs@pobox.com> wrote:
It would still be supported by the np.power function with dtype keyword for users that want to strictly control the dtype. The question is mainly for the operator ** which doesn't have options and there I think it's more appropriate for users that want correct numbers but not necessarily have or want to watch out for the dtype. Related: Python 3.4 returns complex for (-1)**0.5 while numpy returns nan. That's a similar case of upcasting if the result doesn't fit. Longterm I think it would still be nice if numpy could do value dependent type promotion. e.g. when a value is encountered that doesn't fit, then upcast the result at the cost of possibly having to copy the existing results. In the current setting the user has to decide in advance what the necessary maybe required dtype is supposed to be. (Of course I have no idea about the technical problems or computational cost of this.) (Julia dispatch seems to make it easier to construct new types. e.g. we could have a flexible dtype that is free to upcast to whatever is required for the calculation. just guessing) practicality: going from int to float is a common usecase and we would expect getting the correct numbers 2**(-2) -> promote complex is in most fields an unusual outcome for integer or float calculations (e.g. box-cox transformation for x>0 ) having suddenly complex numbers is weird, getting nans is standard float response -> don't promote I'm still largely in the python 2.x habit of adding a decimal points to numbers for float or a redundant `* 1.` in my code to avoid integer division or other weirdness. So, I never realized that ** in numpy doesn't always promote to float which I kind of thought it did. Maybe it's not yet time to drop all the decimal points or `* 1.` from the code? Josef
![](https://secure.gravatar.com/avatar/a5c6e0b8f64a8a1940f5b2d367c1db6e.jpg?s=120&d=mm&r=g)
On 5/19/2016 11:30 PM, Nathaniel Smith wrote:
Fwiw, Haskell has three exponentiation operators because of such ambiguities. I don't use C, but I think the contrasting decision there was to always return a double, which has a clear attraction since for any fixed-width integral type, most of the possible input pairs overflow the type. My core inclination would be to use (what I understand to be) the C convention that integer exponentiation always produces a double, but to support dtype-specific exponentiation with a function. But this is just a user's perspective. Cheers, Alan Isaac
![](https://secure.gravatar.com/avatar/ad13088a623822caf74e635a68a55eae.jpg?s=120&d=mm&r=g)
On Fri, May 20, 2016 at 4:27 PM, Warren Weckesser < warren.weckesser@gmail.com> wrote:
another question uint are positive so the division problem doesn't show up. So that could still handle a usecase for ints. I'm getting stronger in favor of float because raising an exception (or worse, nonsense) in half of the parameter spaces sounds ... (maybe kind of silly) Josef
![](https://secure.gravatar.com/avatar/851ff10fbb1363b7d6111ac60194cc1c.jpg?s=120&d=mm&r=g)
Hi All, As a final desired state, always returning float seems the best idea. It seems quite similar to division in this regard, where integer division works for some values, but not for all. This means not being quite consistent with python, but as Nathan pointed out, one cannot have value-dependent dtype's for arrays (and scalars should indeed behave the same way). If so, then like for division, in-place power should raise a `TypeError`. Obviously, one could have a specific function for integers (like `//` for division) for cases where it is really needed. Now, how to get there... Maybe we can learn from division? At least, I guess at some point `np.divide` became equivalent to `np.true_divide`? All the best, Marten
![](https://secure.gravatar.com/avatar/a5c6e0b8f64a8a1940f5b2d367c1db6e.jpg?s=120&d=mm&r=g)
Yes, I was referring to `pow`, but I had in mind the C++ version, which is overloaded: http://www.cplusplus.com/reference/cmath/pow/ Cheers, Alan On 5/20/2016 4:27 PM, Warren Weckesser wrote:
C doesn't have an exponentiation operator. The C math library has pow, powf and powl, which (like any C functions) are explicitly typed.
![](https://secure.gravatar.com/avatar/851ff10fbb1363b7d6111ac60194cc1c.jpg?s=120&d=mm&r=g)
The error on int ** (-int) is OK with me too (even though I prefer just returning floats). Having a `floor_pow` function may still be good with this solution too. -- Marten
![](https://secure.gravatar.com/avatar/a5c6e0b8f64a8a1940f5b2d367c1db6e.jpg?s=120&d=mm&r=g)
On 5/24/2016 10:03 AM, Marten van Kerkwijk wrote:
The error on int ** (-int) is OK with me too (even though I prefer just returning floats).
What exactly is the argument against *always* returning float (even for positive integer exponents)? Relevant context is: - int ** int will often ("usually") overflow - a numpy function cd meet specialized exponentiation needs Thanks, Alan Isaac
![](https://secure.gravatar.com/avatar/93a76a800ef6c5919baa8ba91120ee98.jpg?s=120&d=mm&r=g)
On Tue, May 24, 2016 at 9:41 AM, Alan Isaac <alan.isaac@gmail.com> wrote:
What exactly is the argument against *always* returning float (even for positive integer exponents)?
If we were starting over from scratch, I would agree with you, but the int ** 2 example feels quite compelling to me. I would guess there lots of code out there that expects the result to have integer dtype. As a contrived example, I might write np.arange(n) ** 2 to produce an indexer for the diagonal elements of an array.
![](https://secure.gravatar.com/avatar/a5c6e0b8f64a8a1940f5b2d367c1db6e.jpg?s=120&d=mm&r=g)
On 5/24/2016 1:36 PM, Eric Moore wrote:
How much code will break if we make that change?
Since even arange(10)**10 is already broken, there will probably not be much new breakage. But under any of the new proposals, *something* will break. So the question is, which shows the most foresight? Having (**) actually work seems worth quite a lot. Alan Isaac
![](https://secure.gravatar.com/avatar/97c543aca1ac7bbcfb5279d0300c8330.jpg?s=120&d=mm&r=g)
On Tue, May 24, 2016 at 10:36 AM, Eric Moore <ewm@redtetrahedron.org> wrote:
The current behavior for arrays is: # Returns int In [2]: np.arange(10) ** 2 Out[2]: array([ 0, 1, 4, 9, 16, 25, 36, 49, 64, 81]) # Returns nonsensical/useless results In [3]: np.arange(10) ** -1 /home/njs/.user-python3.5-64bit/bin/ipython:1: RuntimeWarning: divide by zero encountered in power #!/home/njs/.user-python3.5-64bit/bin/python3.5 /home/njs/.user-python3.5-64bit/bin/ipython:1: RuntimeWarning: invalid value encountered in power #!/home/njs/.user-python3.5-64bit/bin/python3.5 Out[3]: array([-9223372036854775808, 1, 0, 0, 0, 0, 0, 0, 0, 0]) -n -- Nathaniel J. Smith -- https://vorpus.org
![](https://secure.gravatar.com/avatar/79653c343e58afbfbedcfd11e7b668d7.jpg?s=120&d=mm&r=g)
Yes, I'm fully aware of that. I'm speaking toward changing the default result dtype. Raising an error for negative exponents is a fine idea. Changing np.arange(10)**3 to have a non-integer dtype seems like a big change. Speaking of this, that some of the integer array operation errors can be controlled via the np.seterr and some cannot should also be addressed longer term. Eric On Tue, May 24, 2016 at 3:05 PM, Nathaniel Smith <njs@pobox.com> wrote:
![](https://secure.gravatar.com/avatar/b4929294417e9ac44c17967baae75a36.jpg?s=120&d=mm&r=g)
On Tue, May 24, 2016 at 1:31 PM, Alan Isaac <alan.isaac@gmail.com> wrote:
Right, but you'd have to know to change your code when numpy makes this change. Your code will suddenly have a new datatype, that you may be passing into other code, which may generate different results, that will be hard to track down.
And at least as compelling is not have a**-2 fail
I imagine that's about an order of magnitude less common in real code, but an error seems an acceptable result to me, so I know I have to do a ** -2.0
and not being tricked by say np.arange(10)**10. The latter is a promise of hidden errors.
It's a well-understood promise though - you always have to be careful of integer overflow. Best, Matthew
![](https://secure.gravatar.com/avatar/a5c6e0b8f64a8a1940f5b2d367c1db6e.jpg?s=120&d=mm&r=g)
On 5/24/2016 1:41 PM, Matthew Brett wrote:
It's a well-understood promise though - you always have to be careful of integer overflow.
Of course. But **almost all** cases overflow. And "well understood" assume a certain sophistication of the user, while `arange` will certainly be used by beginners. Alan
![](https://secure.gravatar.com/avatar/97c543aca1ac7bbcfb5279d0300c8330.jpg?s=120&d=mm&r=g)
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.harris@gmail.com> wrote:
-- Nathaniel J. Smith -- https://vorpus.org
![](https://secure.gravatar.com/avatar/96dd777e397ab128fedab46af97a3a4a.jpg?s=120&d=mm&r=g)
On Thu, May 19, 2016 at 9:30 PM, Nathaniel Smith <njs@pobox.com> wrote:
Hmm, the Alexandrian solution. The main difficulty with this solution that this will likely to break working code. We could try it, or take the safe route of raising a (Visible)DeprecationWarning. The other option is to simply treat the negative power case uniformly as floor division and raise an error on zero division, but the difference from Python power would be highly confusing. I think I would vote for the second option with a DeprecationWarning. <snip> Chuck
![](https://secure.gravatar.com/avatar/96dd777e397ab128fedab46af97a3a4a.jpg?s=120&d=mm&r=g)
On Fri, May 20, 2016 at 12:35 PM, Charles R Harris < charlesr.harris@gmail.com> wrote:
I suspect that the different behavior of int64 on my system is due to inheritance from Python 2.7 int In [1]: isinstance(int64(1), int) Out[1]: True That different behavior is also carried over for Python 3. Chuck
![](https://secure.gravatar.com/avatar/97c543aca1ac7bbcfb5279d0300c8330.jpg?s=120&d=mm&r=g)
On Fri, May 20, 2016 at 11:35 AM, Charles R Harris <charlesr.harris@gmail.com> wrote:
Right, sorry, I was talking about the end goal -- there's a separate question of how we get there. Pretty much any solution is going to require some sort of deprecation cycle though I guess, and at least the deprecate -> error transition is a lot easier than the working -> working different transition.
So "floor division" here would mean that k ** -n == 0 for all k and n except for k == 1, right? In addition to the consistency issue, that doesn't seem like a behavior that's very useful to anyone... -n -- Nathaniel J. Smith -- https://vorpus.org
![](https://secure.gravatar.com/avatar/96dd777e397ab128fedab46af97a3a4a.jpg?s=120&d=mm&r=g)
On Fri, May 20, 2016 at 1:15 PM, Nathaniel Smith <njs@pobox.com> wrote:
And -1 as well. The virtue is consistancy while deprecating. Or we could just back out the current changes in master and throw in deprecation warnings. That has the virtue of simplicity and not introducing possible code breaks. Chuck
![](https://secure.gravatar.com/avatar/ad13088a623822caf74e635a68a55eae.jpg?s=120&d=mm&r=g)
On Fri, May 20, 2016 at 3:23 PM, Charles R Harris <charlesr.harris@gmail.com
wrote:
can numpy cast to float by default for power or **? At least then we always get correct numbers. Are there dominant usecases that require default return dtype int? AFAICS, it's always possible to choose the return dtype in np.power. Josef
![](https://secure.gravatar.com/avatar/97c543aca1ac7bbcfb5279d0300c8330.jpg?s=120&d=mm&r=g)
On May 20, 2016 12:44 PM, <josef.pktd@gmail.com> wrote: [...]
can numpy cast to float by default for power or **?
Maybe? The question is whether there are any valid use cases for getting ints back:
np.array([1, 2, 3]) ** 2 array([1, 4, 9])
It's not 100% obvious to me but intuitively this seems like an operation that we probably want to support? Especially since there's a reasonable range of int64 values that can't be represented exactly as floats. -n
![](https://secure.gravatar.com/avatar/ad13088a623822caf74e635a68a55eae.jpg?s=120&d=mm&r=g)
On Fri, May 20, 2016 at 6:54 PM, Nathaniel Smith <njs@pobox.com> wrote:
It would still be supported by the np.power function with dtype keyword for users that want to strictly control the dtype. The question is mainly for the operator ** which doesn't have options and there I think it's more appropriate for users that want correct numbers but not necessarily have or want to watch out for the dtype. Related: Python 3.4 returns complex for (-1)**0.5 while numpy returns nan. That's a similar case of upcasting if the result doesn't fit. Longterm I think it would still be nice if numpy could do value dependent type promotion. e.g. when a value is encountered that doesn't fit, then upcast the result at the cost of possibly having to copy the existing results. In the current setting the user has to decide in advance what the necessary maybe required dtype is supposed to be. (Of course I have no idea about the technical problems or computational cost of this.) (Julia dispatch seems to make it easier to construct new types. e.g. we could have a flexible dtype that is free to upcast to whatever is required for the calculation. just guessing) practicality: going from int to float is a common usecase and we would expect getting the correct numbers 2**(-2) -> promote complex is in most fields an unusual outcome for integer or float calculations (e.g. box-cox transformation for x>0 ) having suddenly complex numbers is weird, getting nans is standard float response -> don't promote I'm still largely in the python 2.x habit of adding a decimal points to numbers for float or a redundant `* 1.` in my code to avoid integer division or other weirdness. So, I never realized that ** in numpy doesn't always promote to float which I kind of thought it did. Maybe it's not yet time to drop all the decimal points or `* 1.` from the code? Josef
![](https://secure.gravatar.com/avatar/a5c6e0b8f64a8a1940f5b2d367c1db6e.jpg?s=120&d=mm&r=g)
On 5/19/2016 11:30 PM, Nathaniel Smith wrote:
Fwiw, Haskell has three exponentiation operators because of such ambiguities. I don't use C, but I think the contrasting decision there was to always return a double, which has a clear attraction since for any fixed-width integral type, most of the possible input pairs overflow the type. My core inclination would be to use (what I understand to be) the C convention that integer exponentiation always produces a double, but to support dtype-specific exponentiation with a function. But this is just a user's perspective. Cheers, Alan Isaac
![](https://secure.gravatar.com/avatar/ad13088a623822caf74e635a68a55eae.jpg?s=120&d=mm&r=g)
On Fri, May 20, 2016 at 4:27 PM, Warren Weckesser < warren.weckesser@gmail.com> wrote:
another question uint are positive so the division problem doesn't show up. So that could still handle a usecase for ints. I'm getting stronger in favor of float because raising an exception (or worse, nonsense) in half of the parameter spaces sounds ... (maybe kind of silly) Josef
![](https://secure.gravatar.com/avatar/851ff10fbb1363b7d6111ac60194cc1c.jpg?s=120&d=mm&r=g)
Hi All, As a final desired state, always returning float seems the best idea. It seems quite similar to division in this regard, where integer division works for some values, but not for all. This means not being quite consistent with python, but as Nathan pointed out, one cannot have value-dependent dtype's for arrays (and scalars should indeed behave the same way). If so, then like for division, in-place power should raise a `TypeError`. Obviously, one could have a specific function for integers (like `//` for division) for cases where it is really needed. Now, how to get there... Maybe we can learn from division? At least, I guess at some point `np.divide` became equivalent to `np.true_divide`? All the best, Marten
![](https://secure.gravatar.com/avatar/a5c6e0b8f64a8a1940f5b2d367c1db6e.jpg?s=120&d=mm&r=g)
Yes, I was referring to `pow`, but I had in mind the C++ version, which is overloaded: http://www.cplusplus.com/reference/cmath/pow/ Cheers, Alan On 5/20/2016 4:27 PM, Warren Weckesser wrote:
C doesn't have an exponentiation operator. The C math library has pow, powf and powl, which (like any C functions) are explicitly typed.
![](https://secure.gravatar.com/avatar/851ff10fbb1363b7d6111ac60194cc1c.jpg?s=120&d=mm&r=g)
The error on int ** (-int) is OK with me too (even though I prefer just returning floats). Having a `floor_pow` function may still be good with this solution too. -- Marten
![](https://secure.gravatar.com/avatar/a5c6e0b8f64a8a1940f5b2d367c1db6e.jpg?s=120&d=mm&r=g)
On 5/24/2016 10:03 AM, Marten van Kerkwijk wrote:
The error on int ** (-int) is OK with me too (even though I prefer just returning floats).
What exactly is the argument against *always* returning float (even for positive integer exponents)? Relevant context is: - int ** int will often ("usually") overflow - a numpy function cd meet specialized exponentiation needs Thanks, Alan Isaac
![](https://secure.gravatar.com/avatar/93a76a800ef6c5919baa8ba91120ee98.jpg?s=120&d=mm&r=g)
On Tue, May 24, 2016 at 9:41 AM, Alan Isaac <alan.isaac@gmail.com> wrote:
What exactly is the argument against *always* returning float (even for positive integer exponents)?
If we were starting over from scratch, I would agree with you, but the int ** 2 example feels quite compelling to me. I would guess there lots of code out there that expects the result to have integer dtype. As a contrived example, I might write np.arange(n) ** 2 to produce an indexer for the diagonal elements of an array.
![](https://secure.gravatar.com/avatar/a5c6e0b8f64a8a1940f5b2d367c1db6e.jpg?s=120&d=mm&r=g)
On 5/24/2016 1:36 PM, Eric Moore wrote:
How much code will break if we make that change?
Since even arange(10)**10 is already broken, there will probably not be much new breakage. But under any of the new proposals, *something* will break. So the question is, which shows the most foresight? Having (**) actually work seems worth quite a lot. Alan Isaac
![](https://secure.gravatar.com/avatar/97c543aca1ac7bbcfb5279d0300c8330.jpg?s=120&d=mm&r=g)
On Tue, May 24, 2016 at 10:36 AM, Eric Moore <ewm@redtetrahedron.org> wrote:
The current behavior for arrays is: # Returns int In [2]: np.arange(10) ** 2 Out[2]: array([ 0, 1, 4, 9, 16, 25, 36, 49, 64, 81]) # Returns nonsensical/useless results In [3]: np.arange(10) ** -1 /home/njs/.user-python3.5-64bit/bin/ipython:1: RuntimeWarning: divide by zero encountered in power #!/home/njs/.user-python3.5-64bit/bin/python3.5 /home/njs/.user-python3.5-64bit/bin/ipython:1: RuntimeWarning: invalid value encountered in power #!/home/njs/.user-python3.5-64bit/bin/python3.5 Out[3]: array([-9223372036854775808, 1, 0, 0, 0, 0, 0, 0, 0, 0]) -n -- Nathaniel J. Smith -- https://vorpus.org
![](https://secure.gravatar.com/avatar/79653c343e58afbfbedcfd11e7b668d7.jpg?s=120&d=mm&r=g)
Yes, I'm fully aware of that. I'm speaking toward changing the default result dtype. Raising an error for negative exponents is a fine idea. Changing np.arange(10)**3 to have a non-integer dtype seems like a big change. Speaking of this, that some of the integer array operation errors can be controlled via the np.seterr and some cannot should also be addressed longer term. Eric On Tue, May 24, 2016 at 3:05 PM, Nathaniel Smith <njs@pobox.com> wrote:
![](https://secure.gravatar.com/avatar/b4929294417e9ac44c17967baae75a36.jpg?s=120&d=mm&r=g)
On Tue, May 24, 2016 at 1:31 PM, Alan Isaac <alan.isaac@gmail.com> wrote:
Right, but you'd have to know to change your code when numpy makes this change. Your code will suddenly have a new datatype, that you may be passing into other code, which may generate different results, that will be hard to track down.
And at least as compelling is not have a**-2 fail
I imagine that's about an order of magnitude less common in real code, but an error seems an acceptable result to me, so I know I have to do a ** -2.0
and not being tricked by say np.arange(10)**10. The latter is a promise of hidden errors.
It's a well-understood promise though - you always have to be careful of integer overflow. Best, Matthew
![](https://secure.gravatar.com/avatar/a5c6e0b8f64a8a1940f5b2d367c1db6e.jpg?s=120&d=mm&r=g)
On 5/24/2016 1:41 PM, Matthew Brett wrote:
It's a well-understood promise though - you always have to be careful of integer overflow.
Of course. But **almost all** cases overflow. And "well understood" assume a certain sophistication of the user, while `arange` will certainly be used by beginners. Alan
participants (11)
-
Alan Isaac
-
Antoine Pitrou
-
Charles R Harris
-
Eric Moore
-
josef.pktd@gmail.com
-
Marten van Kerkwijk
-
Matthew Brett
-
Nathaniel Smith
-
R Schumacher
-
Stephan Hoyer
-
Warren Weckesser