我们从教授那里得到了这个任务。先决条件是:
与我们的第一个直接解决方案相比,我们实现了96倍的改进(几乎快了100倍),但仍然没有达到5秒的限制(目前,我们在i7笔记本电脑上的时间是25秒)。[我们的教授也没有纯Python的解决方案,所以这是一项研究任务。]
完整的代码(包括测试调用)在这里:总的来说,它显示了从最初的2400秒(=40分钟)到25秒的改进。然而,我们需要另一个性能提高系数5。有没有人有想法可以帮忙?你知道吗
# -*- coding: utf-8 -*-
#
# Convert a long random sequence of base-10 digits to integers base 3**k with k=1,2,3,4
#
# Task for phdgroupA: length of sequence is 1.5*(10**6)
# time < 5 sec
# Use Python 3 (standard libraries only, no numpy) !
#
# Testcase with a very small sequence, made purely of the digit 7:
# (see sagemath or www.math.com/tables/general/base_conv.htm)
# numlen = 12 --> 777777777777_base10
# = 2202100120200002212221010_base3
# = 2670520085833_base9
# = 2k9fi2np3_base27 ("digits": 0123456789ab...pq)
# [2, 20, 9, 15, 18, 2, 23, 25, 3]
# = 2[61]5[18]8[53][30]_base81
# [2, 61, 5, 18, 8, 53, 30]
#
# 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 0: Create string of nlen digits
def step0(nlen):
rd = 7 # which digit to repeat
string_val = "".join(str(rd) for i in range(nlen))
return string_val # end of step0()
# Step 1: Convert string to int (the string contains only decimal digits)
def step1(string_val, option_chunk=True):
if option_chunk == True:
string_val_len = len(string_val)
Chunk_len = 90000
Read_len = 0
int_valChunk = 0
int_valLocal = 0
ii = 0
while Read_len < string_val_len:
string_val_ChunkRead = string_val[ii*Chunk_len:(ii+1)*Chunk_len]
Chunk_lenRead = len(string_val_ChunkRead)
int_valChunk = int(string_val_ChunkRead)
ii += 1
int_valLocal = int_valLocal * 10**Chunk_lenRead + int_valChunk
Read_len += Chunk_lenRead
int_val = int_valLocal
else:
int_val = int(string_val)
return int_val # end of step1()
# Step 2: Convert given integer to another base
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) # That's the 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)
return nList # end of step2()
if __name__ == '__main__':
# Calculate the string of digits
numlen = 1500000 # number of digits = length of sequence
string_value = step0(numlen)
# Calculate the integer value of the string_value
int_value = step1(string_value, option_chunk=True)
# Convert int_value to list of numbers of the given bases
convsteps = 3 # value of '3' makes step2() 50-60 times faster than value '1'
b = 3
numList = step2(int_value, b, convsteps)
print('3**1: numList begin:', numList[:10]) # Expect: [2, 0, 1, 0, 0, 1, 1, 0, 2, 1]
想法可能是,第一步中的块可以有另一个大小?或者中间转换的两大基础可以更好地平衡?或者可以更直接地将十进制数字串转换为基数为3的列表?你知道吗
说明:上述Python代码中的算法分3步工作:
这三个变化导致了最大的改善(与最初的直接解决方案相比):
步骤2中使用的helper函数numberToBase(n,b), 将整数n转换为以b为底的整数。结果是一个列表 以b为基数的十进制整数。以序列的形式读取列表 是基数b中的结果数。通过 使用内置函数“divmod”而不是两个命令n%b 在while循环中n//=b。这带来了 因素2。
函数step2(n,b,convsteps)将给定的整数n转换为 基数b的整数(b=3)。最初,我们称之为 助手函数一次。然后,我们介绍了 第二步的中间步骤,所以n没有迁移到最后一步 一步到位,三步到位。中间碱含量较高 比最终的碱基b大。这些中间碱基的转换使步骤 2快得多:60倍。
通过分块读取字符串并分别对每个垃圾进行转换,使函数step1的速度提高了4倍。
任何想法都欢迎。请用time()测试你的想法,并给出一个关于它的优势的定量说明。我们在这里检查的其他答案没有使用这么长的十进制数字序列(在字符串中),或者没有关注基转换的性能。你知道吗
好吧,我想这就是解决办法
然后你可以推断出来
基本上没有数学要做。。。只是O(1)dict查找。。。应该很快
相关问题 更多 >
编程相关推荐