Инвариант l oop в вашем коде:
a = Fib(n/2^i)
b = Fib(n/2^i + 1)
(здесь ^
- это возведение в степень, а не xor).
Вы можете проверить, что эти инварианты выполнены при изменении i, используя формулы быстрого удвоения:
Fib(2k) = 2Fib(k)*Fib(k+1) - Fib(k)*Fib(k)
Fib(2k+1) = Fib(k+1)*Fib(k+1) + Fib(k)*Fib(k)
И для случая, когда n / 2 ^ i нечетно, оператор if
применяет формулу:
Fib(2k+1), Fib(2k+2) = Fib(2k+1), Fib(2k) + Fib(2k+1)
( это просто обычная формула Фибоначчи).
Может помочь рассмотреть код как нисходящую (а не восходящую) версию этого рекурсивного кода:
def fib2(n):
if n == 0:
return 0, 1
a, b = fib2(n//2)
a, b = a*(b*2 - a), a*a + b*b
if n % 2 != 0:
a, b = b, a+b
return a, b
единственное существенное отличие состоит в том, что, хотя этот код повторяется до тех пор, пока n
не станет равным 0, нисходящий код всегда повторяется 32 раза.