Task: Fibonacci matrix-exponentiation





Java: import java.math.BigInteger;
import java.util.Arrays;

public class FibonacciMatrixExponentiation {

    public static void main(String[] args) {
        BigInteger mod = BigInteger.TEN.pow(20);
        for ( int exp : Arrays.asList(32, 64) ) {
            System.out.printf("Last 20 digits of fib(2^%d) = %s%n", exp, fibMod(BigInteger.valueOf(2).pow(exp), mod));
        }
        
        for ( int i = 1 ; i <= 7 ; i++ ) {
            BigInteger n = BigInteger.TEN.pow(i);
            System.out.printf("fib(%,d) = %s%n", n, displayFib(fib(n)));
        }
    }
    
    private static String displayFib(BigInteger fib) {
        String s = fib.toString();
        if ( s.length() <= 40 ) {
            return s;
        }
        return s.substring(0, 20) + " ... " + s.subSequence(s.length()-20, s.length());
    }

    
    private static BigInteger fib(BigInteger k) {
        BigInteger aRes = BigInteger.ZERO;
        BigInteger bRes = BigInteger.ONE;
        BigInteger cRes = BigInteger.ONE;
        BigInteger aBase = BigInteger.ZERO;
        BigInteger bBase = BigInteger.ONE;
        BigInteger cBase = BigInteger.ONE;
        while ( k.compareTo(BigInteger.ZERO) > 0 ) {
            if ( k.mod(BigInteger.valueOf(2)).compareTo(BigInteger.ONE) == 0 ) {
                BigInteger temp1 = aRes.multiply(aBase).add(bRes.multiply(bBase));
                BigInteger temp2 = aBase.multiply(bRes).add(bBase.multiply(cRes));
                BigInteger temp3 = bBase.multiply(bRes).add(cBase.multiply(cRes));
                aRes = temp1;
                bRes = temp2;
                cRes = temp3;
            }
            k = k.shiftRight(1);
            BigInteger temp1 = aBase.multiply(aBase).add(bBase.multiply(bBase));
            BigInteger temp2 = aBase.multiply(bBase).add(bBase.multiply(cBase));
            BigInteger temp3 = bBase.multiply(bBase).add(cBase.multiply(cBase));
            aBase = temp1;
            bBase = temp2;
            cBase = temp3;
        }
        return aRes;
    }

    
    private static BigInteger fibMod(BigInteger k, BigInteger mod) {
        BigInteger aRes = BigInteger.ZERO;
        BigInteger bRes = BigInteger.ONE;
        BigInteger cRes = BigInteger.ONE;
        BigInteger aBase = BigInteger.ZERO;
        BigInteger bBase = BigInteger.ONE;
        BigInteger cBase = BigInteger.ONE;
        while ( k.compareTo(BigInteger.ZERO) > 0 ) {
            if ( k.mod(BigInteger.valueOf(2)).compareTo(BigInteger.ONE) == 0 ) {
                BigInteger temp1 = aRes.multiply(aBase).add(bRes.multiply(bBase)).mod(mod);
                BigInteger temp2 = aBase.multiply(bRes).add(bBase.multiply(cRes)).mod(mod);
                BigInteger temp3 = bBase.multiply(bRes).add(cBase.multiply(cRes)).mod(mod);
                aRes = temp1;
                bRes = temp2;
                cRes = temp3;
            }
            k = k.shiftRight(1);
            BigInteger temp1 = aBase.multiply(aBase).add(bBase.multiply(bBase)).mod(mod);
            BigInteger temp2 = aBase.multiply(bBase).add(bBase.multiply(cBase)).mod(mod);
            BigInteger temp3 = bBase.multiply(bBase).add(cBase.multiply(cBase)).mod(mod);
            aBase = temp1;
            bBase = temp2;
            cBase = temp3;
        }
        return aRes.mod(mod);
    }

}



Python: class Head():
    def __init__(self, lo, hi=None, shift=0):
        if hi is None: hi = lo

        d = hi - lo
        ds, ls, hs = str(d), str(lo), str(hi)

        if d and len(ls) > len(ds):
            assert(len(ls) - len(ds) + 1 > 21)
            lo = int(str(lo)[:len(ls) - len(ds) + 1])
            hi = int(str(hi)[:len(hs) - len(ds) + 1]) + 1
            shift += len(ds) - 1
        elif len(ls) > 100:
            lo = int(str(ls)[:100])
            hi = lo + 1
            shift = len(ls) - 100

        self.lo, self.hi, self.shift = lo, hi, shift

    def __mul__(self, other):
        lo = self.lo*other.lo
        hi = self.hi*other.hi
        shift = self.shift + other.shift

        return Head(lo, hi, shift)

    def __add__(self, other):
        if self.shift < other.shift:
            return other + self

        sh = self.shift - other.shift
        if sh >= len(str(other.hi)):
            return Head(self.lo, self.hi, self.shift)

        ls = str(other.lo)
        hs = str(other.hi)

        lo = self.lo + int(ls[:len(ls)-sh])
        hi = self.hi + int(hs[:len(hs)-sh])

        return Head(lo, hi, self.shift)

    def __repr__(self):
        return str(self.hi)[:20]

class Tail():
    def __init__(self, v):
        self.v = int(f'{v:020d}'[-20:])

    def __add__(self, other):
        return Tail(self.v + other.v)

    def __mul__(self, other):
        return Tail(self.v*other.v)

    def __repr__(self):
        return f'{self.v:020d}'[-20:]
        
def mul(a, b):
    return a[0]*b[0] + a[1]*b[1], a[0]*b[1] + a[1]*b[2], a[1]*b[1] + a[2]*b[2]

def fibo(n, cls):
    n -= 1
    zero, one = cls(0), cls(1)
    m = (one, one, zero)
    e = (one, zero, one)

    while n:
        if n&1: e = mul(m, e)
        m = mul(m, m)
        n >>= 1

    return f'{e[0]}'

for i in range(2, 10):
    n = 10**i
    print(f'10^{i} :', fibo(n, Head), '...', fibo(n, Tail))

for i in range(3, 8):
    n = 2**i
    s = f'2^{n}'
    print(f'{s:5s}:', fibo(2**n, Head), '...', fibo(2**n, Tail))