Integer arithmetic

Alex Martelli aleax at aleax.it
Thu Mar 27 02:11:40 EST 2003


Bengt Richter wrote:

> On Wed, 26 Mar 2003 12:38:25 GMT, Alex Martelli <aleax at aleax.it> wrote:
>>Daniel Timothy Bentley wrote:
> [...]
>>
>>> 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)
>>
> The above doesn't match typical hardware and C-style int behavior:

Right, it doesn't replicate the asymmetry thus typically found.  You
have to specialcase that.  In 2.2 it's easiest and fastest to:

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

but in 2.3 int(foo) won't raise OverflowError, so if you need to
reproduce the asymmetry you can do something like:

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

or you can swap the order of the first two guarded returns, if
you like, since their guards are mutually exclusive of course:

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

the second one is probably going to be marginally faster in
practical use (fewer calls with -sys.maxint-1 than with >=0
arguments), and another tiny performance enhancement is:

def toint(foo, themask=sys.maxint, anomaly=-sys.maxint-1):
    if foo>=0: return int(foo&themask)
    elif foo==anomaly: return int(foo)
    else: return -int(-foo&themask)

(probably too tiny to measure in most applications).


Alex





More information about the Python-list mailing list