# 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)

```