Long integers and ways around xrange

Martin Manns mmanns at gmx.net
Sat Jan 16 20:04:09 CET 2010


Hi

As stated in the manual, xrange raises an OverflowError for 
long integer parameters. Looking for a xrange like generator 
for long integers, I found this in the manual 
(http://docs.python.org/library/functions.html):

> CPython implementation detail: xrange() is intended to be simple and
> fast. Implementations may impose restrictions to achieve this. The C
> implementation of Python restricts all arguments to native C longs
> (“short” Python integers), and also requires that the number of
> elements fit in a native C long. If a larger range is needed, an
> alternate version can be crafted using the itertools module:
> islice(count(start, step), (stop-start+step-1)//step).

However, count only accepts one parameter, so that this solution does
not work. Furthermore, islice only accepts positive values for step.

I came up with a solution that I have pasted below. 

Is there a standard long integer replacement for xrange? 
Do you have ideas for improving the code?

Best Regards

Martin

--------------------
File irange.py:


#! /usr/bin/env python
# -*- coding: utf-8 -*-

from itertools import count, imap, islice

def scount(n=0, step=1):
    """Count that supports a step attribute"""
    
    return imap(lambda x: x * step + n, count())

def irange(start, stop=None, step=1):
    """Range for long integers
    
    Usage: irange([start], stop, [step])
    
    Parameters
    ----------
    start: Integer, defaults to 0
    stop: Integer
    step: Integer, defaults to 1
    
    Note on long integers
    ---------------------
    
    Each of the three parameters can be long integers.
    If stop < start: start(stop-start+step-1) // step) must be a short integer.
    If stop > start: start(stop-start+step+1) // step) must be a short integer.
    
    """
    
    if start is None:
        raise TypeError, "range() integer argument expected, got NoneType"
    
    if stop is None:
        stop = start
        start = 0
    
    if step is None:
        step = 1
    
    if step > 0:
        if stop < start:
            return (_ for _ in [])
        return islice(scount(start, step), (stop-start+step-1) // step)
        
    elif step < 0:
        if stop > start:
            return (_ for _ in [])
        return islice(scount(start, step), (stop-start+step+1) // step)
        
    else:
        raise ValueError, "irange() step argument must not be zero"





--------------------
File test_irange.py


#! /usr/bin/env python
# -*- coding: utf-8 -*-

from irange import scount, irange 

# Unit test for irange.py (py.test)

class TestIrange(object):
    'Unit test for MainGridBase'
    __module__ = __name__

    def setup_method(self, method):
        pass

    def test_irange(self):
        test_values = [ \
         [2],
         [10000],
         [-23],
         (0, 1), 
         (0, 2),
         (0, 10000),
         (1, 2),
         (100, 1000),
         (4, 0),
         (4, -1),
         (2**65-512, 2**65),
         (-1, 1),
         (-100, 0),
         (0, 1, 1),
         (0, 2, 1),
         (0, 10, 1),
         (0, 100, 1),
         (0, -1, 1),
         (0, 2, 2),
         (0, 10, 3),
         (0, 100, 4),
         (0, 10000000, 600000),
         (0, 2**65, 2**60),
         (1, 0, -1),
         (10, 0, -1),
         (12312, 0, -1),
         (2**65, 0, -2**61),
         (1, 0, -2),
         (10, 0, -3),
         (12312, 0, -4),
         (2**65, 0, -2**60),
         (2**67, 0, -2**67+1000),
         (-10, 2, 1),
         (-2, 10, 1),
         (3, 100, 1),
         (10000000-1000, 10000000, 1),
         (2**65, 2**66, 2**63),
         (-120, 2**65, 2**63),
         (1, -2334234, -10000),
         (1, 10, 100),
         (10, 1, 100),
         (1, 10, -100),
         (1, 2, 2**65),
         (1, -2, 2**65),
        ]
        
        for val in test_values:
            assert list(irange(*val)) == range(*val)




More information about the Python-list mailing list