On Mon, Mar 26, 2018 at 10:03 PM,
On Mon, Mar 26, 2018 at 10:29 PM, Robert Kern
On Mon, Mar 26, 2018 at 6:28 PM, Nathaniel Smith
wrote: On Mon, Mar 26, 2018 at 6:24 PM, Nathaniel Smith
wrote: Even knowing that, it's still confusing that round(np.float64(0.0)) isn't the same as round(0.0). The reason is a Python 2 / Python 3 thing: in Python 2, round returns a float, while on Python 3, it returns an integer – but numpy still uses the python 2 behavior everywhere.
I'm not sure if it's possible or worthwhile to change this. If we'd changed it when we first added python 3 support then it would have been easy (and obviously a good idea), but at this point it might be tricky?
Oh right, and I forgot: part of the reason it's tricky is that it really would have to return a Python 'int', *not* any of numpy's integer types, because floats have a much larger range than numpy integers, e.g.:
I don't think that's the tricky part. We don't have to change anything but our implementation of Python 3's __round__() special method for np.generic scalar types, which would be straightforward. The only issue, besides backwards compatibility, is that it would introduce a new inconsistency between scalars and arrays (which can't use the Python ints). However, that's "paid for" by the increased compatibility with the rest of Python. For a special method that is used for to interoperate with a Python builtin function, that's probably the more important consistency to worry about.
As for the backwards compatibility concern, I don't think it would matter much. Everyone who has written code that expects round(np.float64(...)) to return a np.float64 is probably already wrapping that with int() anyways. Anyone who really wants to keep the scalar type of the output same as
wrote: the
input can use np.around().
same would need to apply for ceil, floor, trunc, I guess.
ceil and floor don't have __special__ methods for them; math.ceil() and math.floor() do not defer their implementation to the type. math.trunc() might (there is a __trunc__), but it looks like math.trunc(np.float64(...)) already returns an int. I'm not suggesting changing np.ceil(), np.floor(), etc. Nor am I suggesting that we change np.around(), np.round(), or the .round() method on scalar types. Only .__round__().
However, np.round has a decimal argument that I use pretty often and that needs to return a float
np.round(5.33333, 2) 5.3300000000000001
Python makes the return type conditional on whether ndigits is used or not AFAICS.
round(5.33333, 0) 5.0 round(5.33333) 5
Sorry, I took that as a given. If someone followed my suggestion to implement np.generic.__round__, yes, they I intended that they handle both cases correctly. But also, to reiterate, I'm not suggesting that we change np.round(). Only the behavior of numpy scalar types under the builtin round() function. -- Robert Kern