【问题标题】:Speedily calculate base 3 value of real huge integer number with Python 3使用 Python 3 快速计算实大整数的基数 3 值
【发布时间】:2018-12-05 23:52:16
【问题描述】:

我们有一个像 (10**1500000)+1 这样的大数,并且想将它转换为以 3 为底的数。 下面是使用普通 Python 以最快的方式运行代码(不使用 numpy 或 CAS 库)。

如何加快基数转换(到基数 3)的性能?

我们想知道如何通过以下两种方式做到这一点:

  1. 仅使用 Python 3 的内置函数(无 numpy)?
  2. 在普通 Python 3 程序中使用 numpy(或其他 CAS 库)?

非常欢迎任何帮助。这是我们当前的代码:

#### --- Convert a huge integer to base 3 --- ####

# Convert decimal number n to a sequence of list elements
# with integer values in the range 0 to base-1.
# With divmod, it's ca. 1/3 faster than using n%b and then n//=b.
def numberToBase(n, b):
    digits = []
    while n:
        n, rem = divmod(n, b)
        digits.append(rem)
    return digits[::-1]

# Step 2: Convert given integer to another base
# With convsteps == 3, it's about 50-100 times faster than
# with with convsteps == 1, where numberToBase() is called only once.
def step2(n, b, convsteps):
    nList = []
    if convsteps == 3:  # Here the conversion is done in 3 steps
        expos = 10000, 300
        base_a = b ** expos[0]
        base_b = b ** expos[1]
        nList1 = numberToBase(n, base_a)  # time killer in this part
        nList2 = [numberToBase(ll, base_b) for ll in nList1]
        nList3 = [numberToBase(mm, b) for ll in nList2 for mm in ll]
        nList = [mm for ll in nList3 for mm in ll]
    else: # Do conversion in one bulk
        nList = numberToBase(n, b)  # that's the time killer in this part
    return nList


if __name__ == '__main__':

    int_value = (10**1500000)+1  # sample huge numbers
                          # expected begin: [2, 2, 0, 1, 1, 1, 1, 0, 2, 0]
                          # expected time: 4 min with convsteps=3
    base = 3

    # Convert int_value to list of numbers of given base
    # -- two variants of step2() using different convsteps params
    numList = step2(int_value, base, convsteps=1)
    print('   3-1: numList begin:', numList[:10])

    # A value of '3' for the parameter "convsteps" makes
    # step2() much faster than a value of '1'
    numList = step2(int_value, base, convsteps=3)
    print('   3-3: numList begin:', numList[:10])

How to calculate as quick as possible the base 3 value of an integer which is given as a huge sequence of decimal digits (more than one million)? 是一个类似的问题,在基本转换之前还有更多步骤。在这个问题中,我们专注于那部分,到目前为止,大部分时间都消耗了,我们还没有得到答案。

同样在Convert a base 10 number to a base 3 number 中,未处理大量数字的性能方面。

【问题讨论】:

  • 我想知道yield 会不会比list.append 快?您也可以尝试反转字符串而不是列表。
  • @Mark Ransom:谢谢。关于反转:我猜你的意思是函数 numberToBase(n, b) 中的语句“return digits[::-1]”。没有字符串:参数“n”是一个整数。还是有别的意思?
  • 抱歉,起初我没有意识到您想要的输出是一个列表而不是一串数字。当我意识到我的错误时,编辑评论已经太晚了。
  • 对于n = 10**30000 + 1n = 10**80000 + 1 和其他较大的值,我从numberToBase(n, 3)step2(n, 3, 3) 得到不同的结果;答案有不同的长度。我认为在convsteps == 3 代码中组装结果的方式存在错误,因为对结果开头和结尾的数字进行目视检查表明它们是一致的。
  • 我会尝试像 gmpy2 这样的 bignum 库包装器之一;像 gmpy2.digits(your_num, 3) 这样的东西应该比设计良好的纯 Python 替代品好几个数量级。

标签: python performance math


【解决方案1】:

这是一种扩展您的 convsteps 解决方案的方法,方法是在每次调用时使用基方进行递归。删除前导零需要一些额外的工作。

def number_to_base(n, b):
    if n < b:
        return [n]
    else:
        digits = [d for x in number_to_base(n, b*b) for d in divmod(x, b)]
        return digits if digits[0] else digits[1:]

我的快速计时测试表明,它与您的step2 相同,在误差范围内。但它更简单,可能有更少的错误。

【讨论】:

  • 嘿,马克,我想看看这与我正在破解的递归版本相比如何,但未定义 base_recurse。 ☹️ 看起来应该只是number_to_base,对吗?
  • 解决了这个问题,让我知道你的代码比我的快 3 到 4 倍。 ?
  • @WarrenWeckesser 对此感到抱歉,我正在尝试一些变体,一些旧代码与新代码混合在一起。一分钟后,我可能会有一个更简单(更快?)的版本。
  • 不错。我改进了我的,但它仍然较慢,我怀疑进一步的改进只会收敛到你的代码之类的东西。
  • 只是想补充一下,我做了一些基准测试并以 10 为基数,在 ~n=10**1000000 之后,这个函数开始优于 str(n),最终归结为使用 TAOCP 的 long_to_decimal_string_internal(),高德纳 - 卷。 2 节。 4.4 方法 1b。这包括"".join(map(str, ... )) 的时间。对于n=10**10000000,它是内置转换的 2 倍。在 Windows 10 上的 Python 3.6.4 上测试。
猜你喜欢
  • 2023-01-10
  • 2017-02-24
  • 1970-01-01
  • 2017-09-20
  • 2017-03-19
  • 2013-08-30
  • 2014-04-17
  • 1970-01-01
  • 2012-07-07
相关资源
最近更新 更多