【问题标题】:Handling very large numbers in Python在 Python 中处理非常大的数字
【发布时间】:2010-10-07 00:23:38
【问题描述】:

我一直在考虑用 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 平分;任何有四张 K 的牌都将除以 59^4 等。

问题在于,像 AcAdAhAsKdKhKs 这样的七张牌手牌的哈希值约为 62.7 万亿,这需要远远超过 32 位来表示内部。有没有办法在 Python 中存储如此大的数字,让我可以对其执行算术运算?

【问题讨论】:

  • 您确定,一旦您开始以这种方式表示您的数据,您仍然会看到任何显着的速度提升吗?我意识到这并不能回答你的问题,但仍然......
  • 我有一个建议:我建议不要对卡片值和表示使用单独的变量,而是使用字典。 (所以 faces = {'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}。)
  • 依赖整数乘法和因式分解听起来会是速度上的巨大损失,而不是增益。这也可能是记忆力下降。如果您真的想优化手牌存储,您可以考虑使用每等级 3 位的位域(因为每个等级可以有 0 到 4 张牌)和每套 4 位。但我不确定 python 是否是此类优化的最佳语言。也许使用collections.Counter 会更简单。

标签: python optimization largenumber


【解决方案1】:

我知道这个问题很古老,但只是为了未来的人...... 为什么你会想要这样做吗?如果您坚持将手存储为单个编码值而不是 dict 或列表,请使用位串而不是素数的乘积。乘法和素数分解是。将每张卡片编码为 2 的幂(1、2、4、8、16 等)。您可以添加一张手牌|=手牌。 if hand & card > 0,你可以检查卡片。

【讨论】:

    【解决方案2】:

    python自然支持任意整数

    示例:

    >>> 10**1000
    10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
    

    你甚至可以得到一个巨大的整数值,例如 fib(4000000)。

    但它仍然(目前)支持任意大的 float !!

    如果您需要一个很大的浮点数,请检查十进制模块。这些论坛上有使用示例:OverflowError: (34, 'Result too large')

    另一个参考:http://docs.python.org/2/library/decimal.html

    如果您需要加速(您可能感兴趣),您甚至可以使用 gmpy 模块:Handling big numbers in code

    另一个参考:https://code.google.com/p/gmpy/

    【讨论】:

      【解决方案3】:

      python 解释器会为您处理,您只需执行操作(+、-、*、/),它就会正常工作。

      int 的值是无限的。

      除法时要小心,默认情况下商会变成float,但float不支持这么大的数字。如果您收到一条错误消息,指出 float 不支持如此大的数字,则意味着商太大而无法存储在 float 中,您必须使用地板除法 (//)。

      它忽略小数点后的任何小数,这样,结果将是int,所以你可以得到一个大数字结果。

      >>>10//3
      3
      
      >>>10//4
      2
      

      【讨论】:

      • 你的回答如何解决问题中的大数问题?
      • 这意味着你可以对大数进行正常操作,但要小心除法
      • @Hedy 如果出现分裂,我可以/应该做什么?我试图将 (10^18 - 1) 除以 2,这是不正确的。给我一轮 5 * 10^17 而不是 49999...99.5。我能对此做些什么吗?我正在使用“/”除法
      【解决方案4】:

      Python 支持“bignum”整数类型,它可以处理任意大的数字。在 Python 2.5+ 中,这种类型称为 long 并与 int 类型分开,但解释器会自动使用更合适的类型。在 Python 3.0+ 中,int 类型已完全删除。

      不过,这只是一个实现细节——只要您拥有 2.5 或更高版本,只需执行标准数学运算,任何超出 32 位数学边界的数字都将自动(并且透明地)转换为 bignum。

      你可以在PEP 0237找到所有血淋淋的细节。

      【讨论】:

      • 问题是,使用 bignum 而不是 32 位整数对性能的影响是否超过了他使用的巧妙的手动评估方法带来的性能优势。
      • 实际上,int 和 long 之间的界限在 2.5 中被打破了。 3.0 完全删除了 int,使 long 成为唯一的整数类型。
      • 大数字有多大?可以是 PHI ^ 4000000 吗?
      • @Mike Caron — 如果 PEP 0237 中列出的结构是准确的,longs 的长度(以数字为单位)存储为无符号 32 位整数,最多 4,294,967,295 位,这意味着它们可以轻松持有 φ**(4*10**6),即“仅”832,951 位。但是,φ 不是整数,因此您需要使用 Decimal(Python 的浮点 bignum)来计算数字。不过,之后您可以将结果存储在 long 中。
      • @IgnacioVazquez-Abrams 澄清一点,long 是 3.0 中唯一的整数类型,但它被命名为 int。 (而且旧的int 已经不复存在了。)
      【解决方案5】:

      您可以这样做是为了好玩,但除此之外,这不是一个好主意。它不会加快我能想到的任何事情。

      • 拿到手中的牌将是一个整数因式分解运算,比仅仅访问一个数组要昂贵得多。

      • 添加卡片将是乘法,删除卡片除法,两者都是大的多字数字,这比在列表中添加或删除元素更昂贵。

      • 一手牌的实际数值不会告诉您任何信息。您需要考虑素数并遵循扑克规则来比较两只手。 h1

      【讨论】:

        【解决方案6】:

        python 自然地支持任意大的整数:

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-08-05
          • 1970-01-01
          • 1970-01-01
          • 2012-08-17
          • 2017-03-26
          • 2016-11-09
          相关资源
          最近更新 更多