Алгоритм быстрого возведения в степень, два подхода, в чем разница?

Не совсем понимаю в чём существенная разница в реализации этих двух алгоритмов?

def pow(a, n):
    if n==0:
        return 1
    elif n%2 == 0:
        return pow(a, n//2)**2
    else:
        return pow(a, n-1)*a

def pow2(a, n):
    if n == 0:
        return 1
    elif n%2 == 1:
        return pow2(a,n-1)*a
    else:
        return pow2(a**2, n//2)

Ответы (1 шт):

Автор решения: Stanislav Volodarskiy

Единственное существенное различие - разный порядок операций: pow(a, n//2)**2 и pow2(a**2, n//2). Это приводит к различиям в производительности. Пример:

import time


def elapsed(f):
    start = time.perf_counter()
    r = f()
    finish = time.perf_counter()
    return finish - start, r


def pow(a, n):
    if n==0:
        return 1
    elif n%2 == 0:
        return pow(a, n//2)**2
    else:
        return pow(a, n-1)*a


def pow2(a, n):
    if n == 0:
        return 1
    elif n%2 == 1:
        return pow2(a,n-1)*a
    else:
        return pow2(a**2, n//2)



def test(a, n):
    t1, r1 = elapsed(lambda: pow(a, n))
    t2, r2 = elapsed(lambda: pow2(a, n))
    assert r1 == r2
    print(f'{a} ** {n}', f'{t1:5.2f}', f'{t2:5.2f}')


def main():
    for p in range(20, 30):
        n = 2 ** p - 1
        a = 3
        test(a, n)


main()
$ python difference.py
3 ** 1048575  0.09  0.22
3 ** 2097151  0.26  0.66
3 ** 4194303  0.77  2.01
3 ** 8388607  2.32  6.12
3 ** 16777215  7.01 18.53
3 ** 33554431 21.18 56.44

Вторая реализация на этих примерах примерно в два с половиной раза медленнее первой.

→ Ссылка