【发布时间】:2018-12-05 23:52:16
【问题描述】:
我们有一个像 (10**1500000)+1 这样的大数,并且想将它转换为以 3 为底的数。 下面是使用普通 Python 以最快的方式运行代码(不使用 numpy 或 CAS 库)。
如何加快基数转换(到基数 3)的性能?
我们想知道如何通过以下两种方式做到这一点:
- 仅使用 Python 3 的内置函数(无 numpy)?
- 在普通 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 + 1、n = 10**80000 + 1和其他较大的值,我从numberToBase(n, 3)和step2(n, 3, 3)得到不同的结果;答案有不同的长度。我认为在convsteps == 3代码中组装结果的方式存在错误,因为对结果开头和结尾的数字进行目视检查表明它们是一致的。 -
我会尝试像
gmpy2这样的 bignum 库包装器之一;像gmpy2.digits(your_num, 3)这样的东西应该比设计良好的纯 Python 替代品好几个数量级。
标签: python performance math