python什么时候开始使用不同的大乘法算法?

python什么时候开始使用不同的大乘法算法?,python,algorithm,multiplication,Python,Algorithm,Multiplication,我目前正在学习一门算法课程,我很想看看两种方法中的哪一种可以让大量的数字相乘,从而提高运行速度。我发现递归乘法的执行速度快了10倍。对于下面的代码,我得到了t_sim=53.05s和t_rec=4.73s。我做了一些其他的测试,它们似乎都在10倍的范围内 此外,您可以将递归乘法中的值放入树中,并重用它们以更快地计算列表子集的乘法 我做了一个理论上的运行时分析,使用标准乘法,两者都是n^2,但当使用karatsuba算法时,该因子下降到n^log_2(3) 简单乘法中的每个乘法都应该有运行时i*1

我目前正在学习一门算法课程,我很想看看两种方法中的哪一种可以让大量的数字相乘,从而提高运行速度。我发现递归乘法的执行速度快了10倍。对于下面的代码,我得到了t_sim=53.05s和t_rec=4.73s。我做了一些其他的测试,它们似乎都在10倍的范围内

此外,您可以将递归乘法中的值放入树中,并重用它们以更快地计算列表子集的乘法

我做了一个理论上的运行时分析,使用标准乘法,两者都是n^2,但当使用karatsuba算法时,该因子下降到n^log_2(3)

简单乘法中的每个乘法都应该有运行时i*1。对i=1…n求和,我们得到一个算术级数,可以使用高斯公式得到n*(n+1)/2=O(n^2)

对于第二个,我们可以看到给定递归级别的乘法时间是(2^d)^2,其中d是深度,但只需要乘以n*2^-d值。这些级别最终形成一个几何系列,其中每个级别的运行时间为n*2^d,最终深度为log_2(n)。几何级数的解是n*(1-2^log_2(n))/(1-2)=n*(n-1)=O(n^2)。如果使用karatsuba算法,您可以通过同样的方法得到O(n^log_2(3))

如果代码使用的是karatsuba算法,那么加速是有意义的,但似乎没有意义的是两个运行时之间的线性关系,这使python看起来像是在使用标准乘法,根据wikipedia的说法,当使用少于500位时,标准乘法会更快。(我在下面的代码中使用了2^23位。每个数字都有一兆字节长)

随机导入
导入时间
def简单_乘法(值):
a=1
对于值中的val:
a*=val
归还
def递归_乘法(值):
如果len(值)==1:
返回值[0]
温度=[]
i=0
而i+1
两种版本的代码具有相同的乘法次数,但在简单版本中,每个乘法的平均长度约为2000位


在第二个版本中,n/2乘法的长度为24位,n/4乘法的长度为48位,n/8乘法的长度为96位,等等。。。平均长度只有48位。

你的假设有些错误。您的假设是,不同等级之间的每次相乘应花费相同的时间,例如
len(24)*len(72)
approx
len(48)*len(48)
。但事实并非如此,从以下片段可以看出:

%%timeit
random.getrandbits(2**14)*random.getrandbits(2**14)*random.getrandbits(2**14)*random.getrandbits(2**14)

>>>1000 loops, best of 3: 1.48 ms per loop

%%timeit
(random.getrandbits(2**14)*random.getrandbits(2**14))*(random.getrandbits(2**14)*random.getrandbits(2**14))

>>>1000 loops, best of 3: 1.23 ms per loop

即使在如此小的范围内,这种差异也是一致的

时间复杂性纯粹是一种理论上的度量——常数因子与任何事情都没有任何关联。只考虑实际代码损坏时的“常数因素”——不要混合这两种度量。你尝试过增加计算范围,看看当前趋势是否保持原样?@使用上面的值,它已经花费了整整一分钟的时间运行,所以看起来是这样的。infeasible@meowgoesthedog是的,我知道,但我认为,由于他们都只做乘法运算(或者至少是主要的乘法运算),他们有着相同的相关因素。这让我觉得python在执行乘法时使用了不同的算法,在这种情况下,您是对的,因子不应该对齐。让它运行一段时间,似乎趋势是,对于简单方法,大小加倍意味着时间增加4倍,而对于递归方法,则是3倍。这意味着方法1是二次的(每个乘法都是线性的),而方法2是log_2(3)的幂,这与karatsuba的算法相同。平均长度不是比较的正确度量,因为乘法的成本与长度不成正比,但它确实让人感觉到了为什么成对乘法更便宜。一次乘法大约需要n^2倍的时间,在每一个级别上,乘法的大小是双倍的,而非乘法的数量是减半的,但是由于乘法需要n^2倍的时间,因此大小的加倍比乘法的数量更重要。我做了更多的研究,并更新了我的问题,以反映这一点。@BenThayer在简单版本中,每次乘法取O(n),因为其中一个操作数是一个小的常量大小。总的来说,产生O(n^2)。在递归版本中,更大的乘法至少使用Karatsuba优化,然后可能使用toom cook,然后可能使用Schönhage–Strassen,因为它们变得更大
%%timeit
random.getrandbits(2**14)*random.getrandbits(2**14)*random.getrandbits(2**14)*random.getrandbits(2**14)

>>>1000 loops, best of 3: 1.48 ms per loop

%%timeit
(random.getrandbits(2**14)*random.getrandbits(2**14))*(random.getrandbits(2**14)*random.getrandbits(2**14))

>>>1000 loops, best of 3: 1.23 ms per loop