Почему python не обрабатывает очень большие числа во всех областях? - PullRequest
5 голосов
/ 23 января 2012

Я делаю загадку, где мне приходится иметь дело с числами порядка 10 ^ 18.Однако я считаю, что python не может обрабатывать очень большие числа во всех областях.

Конкретно, если мы присваиваем = 1000000000000000000 (10 ^ 18) и выполняем базовые арифметические вычисления (+, -, /*), отвечая.Тем не менее, он показывает OverflowError, когда я использую его в 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

Я использовал Python 2.7.

  1. Как я могу справиться с такими случаями?с головоломками с такими номерами.(Учебник / ссылка на книгу приветствуются)
  2. Почему Python не может справиться с этим в range () / xrange ()

Я хотел бы сделать это на python2.7 с использованием встроенных функций.Разве это не возможно?

Ответы [ 2 ]

10 голосов
/ 23 января 2012

В Python 2.x range и xrange ограничены работой с C long, и ваши большие целые числа слишком велики для этого.Это ограничение просто связано с вариантами реализации, сделанными для range и xrange.

В Python 3.x ограничение было снято, и вы можете выполнить range() с очень большими целыми числами.

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

В официальном списке изменений для Python 3 есть следующее:

range() теперь ведет себя как xrange(), используемый для себя, за исключением того, что он работаетсо значениями произвольного размера.Последний больше не существует.


В Python 2.x функция range() вернула список.Ясно, что нет надежды выделить память для всех элементов для очень больших диапазонов.Функция xrange() возвращает объект xrange.Документация описывает его как «непрозрачный тип последовательности, который выдает те же значения, что и соответствующий список, без фактического сохранения их всех одновременно».Далее в документации говорится:

xrange() предназначен для того, чтобы быть простым и быстрым.Реализации могут налагать ограничения для достижения этой цели.Реализация Python на C ограничивает все аргументы собственными длинными значениями C («короткими» целыми числами Python), а также требует, чтобы количество элементов помещалось в собственные длинные значения C.

Это объясняет ограничения в Python2.x.


Я не совсем уверен, что вы можете сделать с новой поддержкой Python 3 для очень больших диапазонов.Например, я бы не рекомендовал вам попробовать это:

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

Это будет работать долго.


В комментариях вы указываете, что пишете код для подсчетак большому количеству.Вы можете сделать это тривиально в Python с помощью следующего кода:

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

Но вы обнаружите, что если N большое число, то это займет очень много времени.По вашему вопросу не обойтись без значений N порядка 2 18 .

1 голос
/ 23 января 2012

Ваша проблема в том, что range () в Python 2.7 создает явный список каждого значения в диапазоне - у вас просто недостаточно ресурсов для создания такого списка.

Python 3 исправляет это поведение - и вычисляет значения только по запросу ... как по выражению генератора.

Функция Pyrange 2 xrange () не поможет вам, поскольку она ограничена в регистрации значений ... что было компромиссом для Python 2, чтобы избежать огромных накладных расходов на range () для любых чисел, которые не являются тривиальными маленький.

Одним из подходов может быть определение собственного генератора, который перебирает произвольные целые числа - что-то вроде:

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

Мое подозрение, однако, заключается в том, что это, вероятно, ошибка в более широкой схеме вещей - поскольку у вас вряд ли будет достаточно ресурсов обработки, чтобы перебирать каждое значение в 32-разрядном целом числе - не говоря уже о целочисленном диапазоне, большем чем у (32-битного) регистра. Я подозреваю, что есть более эффективный способ решения вашей проблемы, который не зависит от диапазона.

...