round(numpy.float64(0.0)) is a numpy.float64
![](https://secure.gravatar.com/avatar/225f9598f1d35baa94f2e1cc5bee6103.jpg?s=120&d=mm&r=g)
Hello, Is it normal, expected and desired that : round(numpy.float64(0.0)) is a numpy.float64 while round(numpy.float(0.0)) is an integer? I find it disturbing and misleading. What do you think? Has it already been discussed somewhere else? Best regards, Olivier
![](https://secure.gravatar.com/avatar/7857f26c1ef2e9bdbfa843f9087710f7.jpg?s=120&d=mm&r=g)
numpy.float is an alias to the python float builtin. https://github.com/numpy/numpy/issues/3998 On Thu, Mar 22, 2018 at 2:26 PM Olivier <oc-spam66@laposte.net> wrote:
![](https://secure.gravatar.com/avatar/97c543aca1ac7bbcfb5279d0300c8330.jpg?s=120&d=mm&r=g)
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? -n On Thu, Mar 22, 2018 at 12:32 PM, Nathan Goldbaum <nathan12343@gmail.com> wrote:
-- Nathaniel J. Smith -- https://vorpus.org
![](https://secure.gravatar.com/avatar/97c543aca1ac7bbcfb5279d0300c8330.jpg?s=120&d=mm&r=g)
On Mon, Mar 26, 2018 at 6:24 PM, Nathaniel Smith <njs@pobox.com> wrote:
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.: In [4]: round(1e50) Out[4]: 100000000000000007629769841091887003294964970946560 In [5]: round(np.float64(1e50)) Out[5]: 1e+50 In [6]: np.uint64(round(np.float64(1e50))) Out[6]: 0 (Actually that last case illustrates another weird inconsistency: np.uint64(1e50) -> OverflowError, but np.uint64(np.float64(1e50)) -> 0. I have no idea what's going on there.) -n -- Nathaniel J. Smith -- https://vorpus.org
![](https://secure.gravatar.com/avatar/764323a14e554c97ab74177e0bce51d4.jpg?s=120&d=mm&r=g)
On Mon, Mar 26, 2018 at 6:28 PM, Nathaniel Smith <njs@pobox.com> wrote:
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 the input can use np.around(). -- Robert Kern
![](https://secure.gravatar.com/avatar/ad13088a623822caf74e635a68a55eae.jpg?s=120&d=mm&r=g)
On Mon, Mar 26, 2018 at 10:29 PM, Robert Kern <robert.kern@gmail.com> wrote:
same would need to apply for ceil, floor, trunc, I guess. 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.
(I'm currently using Python 3.4.4) Josef
![](https://secure.gravatar.com/avatar/764323a14e554c97ab74177e0bce51d4.jpg?s=120&d=mm&r=g)
On Mon, Mar 26, 2018 at 10:03 PM, <josef.pktd@gmail.com> wrote:
On Mon, Mar 26, 2018 at 10:29 PM, Robert Kern <robert.kern@gmail.com>
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__().
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
![](https://secure.gravatar.com/avatar/7857f26c1ef2e9bdbfa843f9087710f7.jpg?s=120&d=mm&r=g)
numpy.float is an alias to the python float builtin. https://github.com/numpy/numpy/issues/3998 On Thu, Mar 22, 2018 at 2:26 PM Olivier <oc-spam66@laposte.net> wrote:
![](https://secure.gravatar.com/avatar/97c543aca1ac7bbcfb5279d0300c8330.jpg?s=120&d=mm&r=g)
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? -n On Thu, Mar 22, 2018 at 12:32 PM, Nathan Goldbaum <nathan12343@gmail.com> wrote:
-- Nathaniel J. Smith -- https://vorpus.org
![](https://secure.gravatar.com/avatar/97c543aca1ac7bbcfb5279d0300c8330.jpg?s=120&d=mm&r=g)
On Mon, Mar 26, 2018 at 6:24 PM, Nathaniel Smith <njs@pobox.com> wrote:
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.: In [4]: round(1e50) Out[4]: 100000000000000007629769841091887003294964970946560 In [5]: round(np.float64(1e50)) Out[5]: 1e+50 In [6]: np.uint64(round(np.float64(1e50))) Out[6]: 0 (Actually that last case illustrates another weird inconsistency: np.uint64(1e50) -> OverflowError, but np.uint64(np.float64(1e50)) -> 0. I have no idea what's going on there.) -n -- Nathaniel J. Smith -- https://vorpus.org
![](https://secure.gravatar.com/avatar/764323a14e554c97ab74177e0bce51d4.jpg?s=120&d=mm&r=g)
On Mon, Mar 26, 2018 at 6:28 PM, Nathaniel Smith <njs@pobox.com> wrote:
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 the input can use np.around(). -- Robert Kern
![](https://secure.gravatar.com/avatar/ad13088a623822caf74e635a68a55eae.jpg?s=120&d=mm&r=g)
On Mon, Mar 26, 2018 at 10:29 PM, Robert Kern <robert.kern@gmail.com> wrote:
same would need to apply for ceil, floor, trunc, I guess. 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.
(I'm currently using Python 3.4.4) Josef
![](https://secure.gravatar.com/avatar/764323a14e554c97ab74177e0bce51d4.jpg?s=120&d=mm&r=g)
On Mon, Mar 26, 2018 at 10:03 PM, <josef.pktd@gmail.com> wrote:
On Mon, Mar 26, 2018 at 10:29 PM, Robert Kern <robert.kern@gmail.com>
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__().
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
participants (5)
-
josef.pktd@gmail.com
-
Nathan Goldbaum
-
Nathaniel Smith
-
Olivier
-
Robert Kern