[Numpy-discussion] Floor divison on int returns float

Charles R Harris charlesr.harris at gmail.com
Wed Apr 13 17:49:15 EDT 2016


On Wed, Apr 13, 2016 at 2:48 PM, Nathaniel Smith <njs at pobox.com> wrote:

> On Apr 13, 2016 9:08 AM, "Robert Kern" <robert.kern at gmail.com> wrote:
> >
> > On Wed, Apr 13, 2016 at 3:17 AM, Antony Lee <antony.lee at berkeley.edu>
> wrote:
> > >
> > > This kind of issue (see also
> https://github.com/numpy/numpy/issues/3511) has become more annoying now
> that indexing requires integers (indexing with a float raises a
> VisibleDeprecationWarning).  The argument "dividing an uint by an int may
> give a result that does not fit in an uint nor in an int" does not sound
> very convincing to me,
> >
> > It shouldn't because that's not the rule that numpy follows. The range
> of the result is never considered. Both *inputs* are cast to the same type
> that can represent the full range of either input type (for that matter,
> the actual *values* of the inputs are also never considered). In the case
> of uint64 and int64, there is no really good common type (the integer
> hierarchy has to top out somewhere), but float64 merely loses resolution
> rather than cutting off half of the range of uint64.
>
> Let me play devil's advocate for a moment, since I've just been
> playing out this debate in my own mind and you've done a good job of
> articulating the case for that side :-).
>
> The counter argument is: it doesn't really matter about having a
> common type or not; what matters is whether the operation can be
> defined sensibly. For uint64 <op> int64, this is actually not a
> problem: we provide 2s complement signed ints, so uint64 and int64 are
> both integers-mod-2**64, just choosing different representatives for
> the equivalence classes in the upper half of the ring. In particular,
> the uint64 and int64 ranges are isomorphic to each other.
>
> or with less jargon: casting between uint64 and int64 commutes with
> all arithmetic operations, so you actually get the same result
> performing the operation in infinite precision and then casting to
> uint64 or int64, or casting both operations to uint64 or int64 and
> then casting the result to uint64 or int64. Basically the operations
> are totally well-defined even if we stick within integers, and the
> casting is just another form of integer wraparound; we're already
> happy to tolerate wraparound for int64 <op> int64 or uint64 <op>
> uint64, so it's not entirely clear why we go all the way to float to
> avoid it for uint64 <op> int64.
>
> [On second thought... I'm actually not 100% sure that the
> all-operations-commute-with-casting thing is true in the case of //'s
> rounding behavior. I would have to squint a lot to figure that out. I
> guess comparison operations are another exception -- a < b !=
> np.uint64(a) < np.uint64(b) in general.]
>

I looked this up once, `C` returns unsigned in the scalar case when both
operands have the same width. See Usual Arithmetic Conversions
<https://www.securecoding.cert.org/confluence/display/c/INT02-C.+Understand+integer+conversion+rules>.
I think that is not a bad choice, but there is the back compatibility
problem, plus it is a bit exceptional.

Chuck
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/numpy-discussion/attachments/20160413/de6fdc7d/attachment.html>


More information about the NumPy-Discussion mailing list