On Wed, Apr 13, 2016 at 2:48 PM, Nathaniel Smith <n...@pobox.com> wrote:
> On Apr 13, 2016 9:08 AM, "Robert Kern" <robert.k...@gmail.com> wrote: > > > > On Wed, Apr 13, 2016 at 3:17 AM, Antony Lee <antony....@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
_______________________________________________ NumPy-Discussion mailing list NumPy-Discussion@scipy.org https://mail.scipy.org/mailman/listinfo/numpy-discussion