Обработка очень больших чисел в Python


140

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

class PokerCard:
    faces = '23456789TJQKA'
    suits = 'cdhs'
    facePrimes = [11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 53, 59, 61]
    suitPrimes = [2, 3, 5, 7]

И

    def HashVal(self):
      return PokerCard.facePrimes[self.cardFace] * PokerCard.suitPrimes[self.cardSuit]

Это дало бы каждой руке числовое значение, которое по модулю могло бы сказать мне, сколько королей в руке или сколько сердец. Например, любая рука с пятью или более трефами делится поровну на 2 ^ 5; любая рука с четырьмя королями делится поровну на 59 ^ 4 и т. д.

Проблема состоит в том, что комбинация из семи карт, такая как AcAdAhAsKdKhKs, имеет значение хеш-функции приблизительно 62,7 квадриллиона, что потребует значительно больше 32 бит для внутреннего представления. Есть ли способ хранить такие большие числа в Python, который позволит мне выполнять над ним арифметические операции?


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

3
У меня есть предложение: вместо использования отдельных переменных для значений карт и представлений, я предлагаю использовать словари. (Так лица = {'2': 11, '3': 13, '4': 17, '5': 19, '6': 23, '7': 29, '8': 31, '9' : 37, 'T': 41, 'J': 43, 'Q': 53, 'K': 59, 'A': 61} и костюмы = {'c': 2, 'd': 3, ' h ': 5,' s ': 7}.)
JAB

Ответы:


177

Python поддерживает целочисленный тип "bignum", который может работать с произвольно большими числами. В Python 2.5+ этот тип вызывается longи отличается от intтипа, но интерпретатор будет автоматически использовать тот, который больше подходит. В Python 3.0+ этот intтип был полностью удален.

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

Вы можете найти все подробности в PEP 0237 .


2
Вопрос в том, превышает ли выигрыш в производительности при использовании bignum вместо 32-разрядных целых чисел преимущество в производительности от умного метода оценки руки, который он использует.
Крис Апчерч

3
На самом деле, барьер между int и long был сломан в 2.5. 3.0 полностью удаляет int, делая long единственным целочисленным типом.
Игнасио Васкес-Абрамс

1
Насколько большой большой номер? Это может быть PHI ^ 4000000?
Майк Карон

9
@Mike Caron - Если структура, указанная в PEP 0237, является точной, longдлины s (в цифрах) сохраняются как 32-разрядные целые числа без знака, до 4 294 967 295 цифр, что означает, что они могут легко содержать φ ** (4 * 10 ** 6 ), что составляет «всего» 832 951 цифр. Однако φ не является целым числом, поэтому вам нужно будет использовать десятичное число (число с плавающей точкой в ​​Python) для вычисления числа. Однако вы можете сохранить результат longпозже.
Бен Бланк

17
@ IgnacioVazquez-Abrams Просто пояснение, longэто единственный целочисленный тип в 3.0, но он назван int. (А старого intуже нет.)
Майкл Миор

70

Python поддерживает произвольно большие целые числа естественным образом:

пример:

>>>10 ** 1000 100000000000000000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

Вы можете даже получить, например, огромное целочисленное значение fib (4000000).

Но все - таки это делает не (на данный момент) поддерживает сколь угодно большой поплавок !!

Если вам нужен один большой, большой, float, то проверьте десятичный модуль. Есть примеры использования этих foruns: OverflowError: (34, 'Результат слишком велик')

Другая ссылка: http://docs.python.org/2/library/decimal.html

Вы даже можете использовать модуль gmpy, если вам нужно ускорение (что, вероятно, вас заинтересует): обработка больших чисел в коде

Другая ссылка: https://code.google.com/p/gmpy/


33

Вы можете сделать это ради удовольствия, но кроме этого это не очень хорошая идея. Это не ускорит ничего, что я могу придумать.

  • Получение карт в руке будет целочисленной факторинговой операцией, которая намного дороже, чем просто доступ к массиву.

  • Добавление карточек будет умножением и удалением деления карточек, как больших числовых чисел, что является более дорогой операцией, чем добавление или удаление элементов из списков.

  • Фактическое числовое значение руки ничего вам не скажет. Вам нужно будет учесть простые числа и следовать правилам покера, чтобы сравнить две руки. h1 <h2 для таких рук ничего не значит.


25

python поддерживает произвольно большие целые числа естественным образом:

In [1]: 59**3*61**4*2*3*5*7*3*5*7
Out[1]: 62702371781194950
In [2]: _ % 61**4
Out[2]: 0

3

Интерпретатор Python справится с этим за вас, вам просто нужно выполнить операции (+, -, *, /), и он будет работать как обычно.

intЗначение не ограничено.

Осторожно при делении, по умолчанию коэффициент превращается в float, но floatне поддерживает такие большие числа. Если вы получите сообщение об ошибке, в котором говорится, floatчто такие большие числа не поддерживаются, то это означает, что частное слишком велико, чтобы его можно было сохранить, floatвам придется использовать floor Division ( //).

Он игнорирует любое десятичное число, которое идет после десятичной запятой, таким образом, результат будет int, так что вы можете получить результат большого числа.

10//3 Выходы 3

10//4 выходы 2


1
Как ваш ответ решает проблему с большими числами в вопросе?
Глупый Волк,

Это означает, что вы можете просто выполнять обычные операции с большими числами, но будьте осторожны с делением
Хеди
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.