Note: older compilers may be missing <inttypes.h> or <stdint.h>. If <inttypes.h> is not present (Visual Studio 2010), use compiler specific format string for uint64_t. If <stdint.h> is not present (Visual Studio 2005), use typedef ... uint64_t (usually unsigned long long) and the appropriate format string.
During the calculation of a and b, let cm = current cumulative sum of bits of n:
b = F(cm)
a = F(c+1m+1)
a' = F(c+1+pm+1+p) = F(c+2m+2) F(p) + F(c+1m+1) F(p-1)
= (F(c+1m+1)+F(cm)) F(p) + F(c+1m+1) F(p-1)
= F(c+1m+1) F(p) + F(cm) F(p) + F(cm) F(p-1)
= a d + b d + b c
b' = F(c+pm+p) = F(c+1m+1) F(p) + F(cm) F(p-1)
= a d + b c
Note that if b' is the max value for uint64_t, a' will overflow, but it's not an issue. However, the algorithm can be modified so that when completed, a = fib(n-1):
a = fib(-1) = 1
b = fib(0) = 0
a = fib(m-1)
b = fib(m)
b' = fib(m+p)
= fib(m+1)fib(p) + fib(m)fib(p-1)
= (fib(m) + fib(m-1))fib(p) + fib(m)fib(p-1)
= fib(m)fib(p) + fib(m-1)fib(p) + fib(m)fib(p-1)
= bd + ad + bc
a' = fib(m-1+p)
= fib(m)fib(p) + fib(m-1)fib(p-1)
= bd + ac
uint64_t fib(uint64_t n)
{
uint64_t a, b, c, d;
a = d = 1;
b = c = 0;
while (1) {
if (n & 1) {
uint64_t bd = b*d;
b = bd + a*d + b*c;
a = bd + a*c;
}
n >>= 1;
if (n == 0)
break;
{
uint64_t dd = d*d;
d = dd + 2*d*c;
c = dd + c*c;
}
}
return b;
}