Integer arithmetic

Alex Martelli aleax at
Wed Mar 26 13:38:25 CET 2003

Daniel Timothy Bentley wrote:

> It seems like so long as there's a distinction in the language between
> ints and longs, there should be a way to create ints reliably.
> If
> int(foo % sys.maxint)
> is such a call, great.  Is this guaranteed to work?  I don't know.

It's guaranteed to do funny things indeed!

>>> int(-23 % sys.maxint)

a % b, for b>0, always return an x such that 0 <= x < b.  That is
most definitely NOT what you want in this case for a<0... and I
suspect that this would also not be what you want:

>>> int(sys.maxint % sys.maxint)

yet it IS totally guaranteed by the semantics of %.

> Basically, if you're going to say ints and longs are separate types, I
> think there should be a way to makes ints from longs fairly reliably.  I
> don't think that's a niche, I think it's something a consistent language
> should provice.

Well, your proposed expression DOES "make ints from longs fairly reliably",
it's just that I think the ints it makes are probably not the ones you'd
like to get (except for 0<=foo<sys.maxint).

I think you want something like: int(cmp(foo,0)*(abs(foo) & sys.maxint)).

Me, I think it's better to incapsulate the "conversion to int ignoring
overflow" in a function, using an if/else:

def toint(foo):
    if foo>=0: return int(foo&sys.maxint)
    else: return -int(-foo&sys.maxint)

and I'd further factor out the "int(X&sys.maxint)" part because I loathe
duplicated code.  But that brings us right back to the same suggestion
I already gave you, with a tiny perhaps-improvement:

def mask(x, themask=sys.maxint): return int(x & themask)

def toint(x):
    if x>=0: return mask(x)
    else: return -mask(-x)

I originally proposed using a literal 2**32-1 as the default value
of themask (because I think that is likely to be more useful for
the purpose of simulating an abstract machine's arithmetic), now
we're using sys.maxint instead (thus putting ourselves at the mercy
of the specific machine we're running on), big deal.

> Maybe python is moving towards a day where ints and longs are completely
> indistinguishable.  This probably wouldn't be a bad thing, from many

That's what PEP 237 states, yes.

> standpoints.  But until that day comes, I think that there should be a way
> to construct an object without getting an exception.  I guess it's more a

There are many, depending on what object you want...;-).

You seem adamantly convinced that "mask off however many least-significant
bits the current machine allows into an int" is the one and obvious way
of constructing an int from a long, when the long has more significant bits
that will fit into an int, but I think this is unproven.  Why shouldn't
some other application prefer, e.g.:

def toint(x):
    try: return int(x)
    except OverflowError: return [sys.maxint,-sys.maxint][x<0]

i.e. a "saturating" conversion (warning: doesn't work in 2.3 since
int(alongthatstoobig) just returns the long rather than an int, NOT
raising any exception whatsoever...).

> matter of taste whether the implentation or the interface-user should do
> it, but since one still allows the other, I'd say the implementation
> probably should.

"In the face of ambiguity, refuse the temptation to guess", and I
think it's NOT obvious how N>32 bits should be squeezed into 32 (the
idea of choosing the LEAST significant ones may look obvious to you,
but I'd suggest thinking again about it, in terms of application
needs rather than traditional behavior of hardware components...:-).

> I like the flexibility python provides, but it seems that there might be
> cracks where orthogonality or consistency of interface have cracks; which
> makes sense in an evovling language.  If I managed to arrive at python at
> a point where this "problem" was just begotten and there's a good chance
> it will go away soon, perfect.  But I stil think there's an elegant
> solution to be had, that works across implementations.  Is it sys.maxint?
> Maybe.  Silent exceptions, like Java will do for math stuff?  Maybe.  I'm
> getting the impression the solution is maxint, so great.  Thanks.

If taking just as many LSB's as sys.maxint happens to have is what your
application needs, then yes, sys.maxint (plus some care about sign!)
is indeed "the solution".  As to what needs your application actually
happens to have, well, that's something that only you, as the designer
thereof, can determine -- the language sure can't do it for you!


More information about the Python-list mailing list