Обработка очень больших чисел в 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
Autoplectic
источник
3

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

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

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

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

10//3 Выходы 3

10//4 выходы 2

Хеди
источник
1
Как ваш ответ решает проблему с большими числами в вопросе?
Глупый Волк,
Это означает, что вы можете просто выполнять обычные операции с большими числами, но будьте осторожны с делением
Хеди