模数和 FizzBu​​zz 的计算复杂度

Computational complexity of modulos and FizzBuzz

所以我不想讨论这是否是 FizzBu​​zz 挑战的最完美代码。

对于那些不熟悉 FizzBu​​zz 的人,打印出 1-100 的 运行ge 有四个规则:

  1. 打印出所有数字;
  2. 如果数字能被3整除,打印"Fizz";
  3. 如果数字能被5整除,打印"Buzz";
  4. 如果号码是 被 3 和 5 整除,打印 "FizzBuzz".)

我运行两种实现方式,比较它们的速度:

# Code A
%%timeit
for i in range(1,10001):
    if i % 15 == 0:
        print('FizzBuzz')
    elif i % 3 == 0:
        print('Fizz')
    elif i % 5 == 0:
        print('Buzz')
    else:
        print(i)
# Code B
%%timeit
for i in range(1,10001):
    if i % 5 == 0 and i % 3 == 0:
        print('FizzBuzz')
    elif i % 3 == 0:
        print('Fizz')
    elif i % 5 == 0:
        print('Buzz')
    else:
        print(i)

尽管对代码 B 进行了额外的 if 评估,但它始终 运行 比代码 A 更快。更大的数字会导致更慢的模数吗?这背后的根本原因是什么?

我能想到的主要原因可能是优化。

版本B多次使用相同的操作,即:

  • 我mod5
  • 我mod3

相当聪明的 compiler/interpreter 可能会发现这一点,并计算出这些中间结果。这样一来,只需 2 mod 次操作即可立即计算出整个 if 块。

简而言之,我认为最终执行的代码可能如下所示:

for i in range(1,10001):
    a = i % 5
    b = i % 3
    if a == 0 and b == 0:
        print('FizzBuzz')
    elif b == 0:
        print('Fizz')
    elif a == 0:
        print('Buzz')
    else:
        print(i)

不过,A块的代码可能太复杂了。也就是说,我的意思是编译器将始终被迫执行 3 mod 操作。除非它能以某种方式发现 15 = 3 * 5,并使用该逻辑重新处理 if 语句。