两个运算的性能得到前n个自然数的和



我正在研究Project Euler问题12,并提出了以下解决方案:

import math
def main():
    num = 0
    j = 0
    numFactors = 0
    while numFactors <= 500:
        j += 1

        num = num + j #num = sum of numbers from 1 to j
        #num = (j *(j+1))//2

        numFactors = 0
        for n in range(1,int(math.sqrt(num))):
            if num % n == 0:
                numFactors += 2
    print(num)
if __name__ == '__main__':
    from timeit import Timer
    t = Timer(lambda: main())
    print(t.timeit(number=1))

我的问题是关于线num = num + jnum = (j *(j+1))//2

当只使用单个加法时,程序总是比我取消注释下一行并进行乘法、加法和除法慢。

有人能解释为什么单次操作比做3次慢吗?

我实际上没有看到我的机器性能有任何差异。如果乘法真的比加法快,我也会有点惊讶。

我们可以使用dis模块来从这两个变体中反汇编字节码。在两个变体中,大部分都是相同的,因此任何一个函数的性能都应该相同。这是两个不同的部分(第11行是num = num + j,第12行是num = (j *(j+1))//2):

 11          43 LOAD_FAST                0 (num)
             46 LOAD_FAST                1 (j)
             49 BINARY_ADD          
             50 STORE_FAST               0 (num)
 12          43 LOAD_FAST                1 (j)
             46 LOAD_FAST                1 (j)
             49 LOAD_CONST               3 (1)
             52 BINARY_ADD          
             53 BINARY_MULTIPLY     
             54 LOAD_CONST               4 (2)
             57 BINARY_FLOOR_DIVIDE 
             58 STORE_FAST               0 (num)

两次拆解都有三次操作。它又来了,只显示了每个变体特有的行:

 11          43 LOAD_FAST                0 (num)
 12          43 LOAD_FAST                1 (j)
             49 LOAD_CONST               3 (1)
             53 BINARY_MULTIPLY     
             54 LOAD_CONST               4 (2)
             57 BINARY_FLOOR_DIVIDE

如果乘法真的比加法快,那么我希望精通字节码的人能够解释为什么numLOAD_FAST比第12行的五次运算快。但在我的外行看来,我预计带有更多字节码操作的变体需要更长的时间。

最新更新