5

I am doing a puzzle where I have to deal with numbers of order 10^18. However, I find python isn't able to handle very large numbers in all areas.

To be specific, if we assign a = 1000000000000000000 (10^18) and do basic arithmetic calculations (+, -, /, *), its responding. However, its showing OverflowError when I use it in range()

>>> a = 1000000000000000000
>>> a/2
500000000000000000L
>>> a*2
2000000000000000000L
>>> a+a
2000000000000000000L
>>> a*a
1000000000000000000000000000000000000L
>>> range(a)

Traceback (most recent call last):
  File "<pyshell#5>", line 1, in <module>
    range(a)
OverflowError: range() result has too many items
>>> xrange(a)

Traceback (most recent call last):
  File "<pyshell#6>", line 1, in <module>
    xrange(a)
OverflowError: Python int too large to convert to C long

I used Python 2.7.

  1. How can I handle such cases?, Whats the best way to deal with puzzles holding such numbers. (A tutorial/ book reference would be appreciated)
  2. Why Python isn't able to handle it in range()/ xrange()

I would like to do it in python 2.7 using inbuild functions. Isn't that possible?

Surya
  • 4,824
  • 6
  • 38
  • 63
  • 2
    Possible duplicate http://stackoverflow.com/questions/1482480/xrange2100-overflowerror-long-int-too-large-to-convert-to-int – shadyabhi Jan 23 '12 at 13:03
  • 2
    I doubt you're going about solving your puzzle the right way. Counting to 10^18 with python on a computer of today would take somewhere in the order of 10000 years. – Lauritz V. Thaulow Jan 23 '12 at 13:50
  • itertools.count() seems to be a option for it but counting is taking very long time. Is there any other efficient option (considering situations where we need to count large values; solving puzzles) – Surya Jan 23 '12 at 13:57
  • @lazyr: Okay, then could you please tell me how can I actually deal such things (I don't expect you to answer about the topic but looking for a tail so that I can search on it) – Surya Jan 23 '12 at 14:00
  • 1
    @Surya What are you trying to do? You can't hope to count up to `1000000000000000000000000000000000000`. That will take forever. – David Heffernan Jan 23 '12 at 14:05
  • 1
    There is no efficient way to count so many numbers, because there are so many of them. I think your best bet would be to update the question with a link to or description of your puzzle and ask for a _hint_ on how to proceed. – Lauritz V. Thaulow Jan 23 '12 at 14:07
  • Well, its from a competition, as its still going on, I can't mention about it. All I can say is that there is an equation which generates values depending upon previous values. So, N is the number of values it has to generate. Here N = 10^8. – Surya Jan 23 '12 at 15:46
  • As you might have solved some puzzles of similar kind where you might have dealt with large numbers, what are the methods we should use in such cases. As its clear that we can't count till 10^8, what's might be the other way? – Surya Jan 23 '12 at 15:48
  • 1
    Sounds like you're dealing with a recurrence relation, and that the reason the question has such large numbers is to make sure the problem cannot be solved by brute force. I would try to [solve the relation](http://en.wikipedia.org/wiki/Recurrence_relation#Solving) and get a forumla that directly yields the Nth number. If that fails, try to reason about which numbers may _not_ be part of the series, so that you can exclude a large portion of the numbers you need to search. – Lauritz V. Thaulow Jan 23 '12 at 20:41
  • I'm curious about your puzzle and would like to have a go at it. Could you please state the problem here once the competition is over? – Lauritz V. Thaulow Jan 25 '12 at 09:39
  • 1
    None of these comments address the question, but seem to attack the example. See xrange discussion below. A) the range results need to be stored somewhere in real time, this requires enormous amounts of storage, real or virtual. You will have the same issue in many languages trying to define huge static arrays. B) Much of Python is just a wrapper for 'C', (see "long" type discussion below). The practicality of the example, how long it will take etc. is not relevant. – mckenzm Jan 02 '15 at 00:00

2 Answers2

10

In Python 2.x, range and xrange are limited to working with C long and your large integers are just too big for that. This limitation is simply due to the implementation choices made for range and xrange.

In Python 3.x the limitation has been removed and you can perform range() with very large integers.

>>> range(2**128)
range(0, 340282366920938463463374607431768211456)

The official list of changes for Python 3 has this to say:

range() now behaves like xrange() used to behave, except it works with values of arbitrary size. The latter no longer exists.


In Python 2.x the range() function returned a list. Clearly there's no hope of allocating memory for all the elements for very large ranges. The xrange() function returns an xrange object. The documentation describes it as "an opaque sequence type which yields the same values as the corresponding list, without actually storing them all simultaneously". The documentation goes on to say this:

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.

This explains the limitations in Python 2.x.


I'm not quite sure what you can usefully do with the new Python 3 support for very large ranges. For example, I would not recommend you try this:

2**128 in range(2**128)

That will run for a long time.


You indicate in the comments that you are writing code to count up to a large number. You can do this trivially in Python with code like this:

i = 0
while i<N:
    doSomething(i)
    i += 1

But you will discover that if N is a large number then this will take a very long time. There's not any getting around that for values of N of the order 218 as per your question.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • I think I should find another way for the solution as reaching N is typically impossible. – Surya Jan 23 '12 at 15:37
  • 3
    Minor: in modern Python 3, `2**128 in range(2**128)` will run instantly because `__contains__` has been special-cased. – DSM Dec 29 '14 at 20:53
1

Your problem is that range() in Python 2.7 constructs an explicit list of every value in the range - you simply don't have enough resources to construct such a list.

Python 3 corrects this behaviour - and only calculates the values on demand... as if by a generator expression.

The Python 2 xrange() function isn't going to help you as it is constrained to register values... which was a compromise for Python 2 to avoid the huge overhead of range() for any numbers that are not trivially small.

One approach might be to define your own generator which iterates over arbitrary integers - something like:

def genrange(min,max,stride=1):
    val=min
    while val<max:
        yield val
        val+=stride

My suspicion, however, is that this is probably a mistake in the bigger scheme of things - as you're unlikely to have sufficient processing resources to iterate through every value in a 32 bit integer - let alone for an integer range larger than that of a (32bit) register. I suspect there's a better way to address your problem which doesn't depend upon a range in the first place.

aSteve
  • 1,956
  • 1
  • 20
  • 35
  • This could be a way (may not be efficient) to have a function like range(). However, I could have straight away used while() rather than putting it in a function. I think it would even reduce time complexity. (Not sure) – Surya Jan 23 '12 at 13:54