Task: Fibonacci matrix-exponentiation



C#: using System;
using System.IO;
using System.Numerics;
using System.Threading;
using System.Diagnostics;
using System.Globalization;

namespace Fibonacci {
    class Program
    {
        private static readonly BigInteger[,] F = { { BigInteger.One, BigInteger.One }, { BigInteger.One, BigInteger.Zero } };
        private static NumberFormatInfo nfi  = new NumberFormatInfo { NumberGroupSeparator = "_" };
        private static BigInteger[,] Multiply(in BigInteger[,] A, in BigInteger[,] B)
        {
            if (A.GetLength(1) != B.GetLength(0))
            {
                throw new ArgumentException("Illegal matrix dimensions for multiplication.");
            }
            var C = new BigInteger[A.GetLength(0), B.GetLength(1)];
            for (int i = 0; i < A.GetLength(0); ++i)
            {
                for (int j = 0; j < B.GetLength(1); ++j)
                {
                    for (int k = 0; k < A.GetLength(1); ++k)
                    {
                        C[i, j] +=  A[i, k] * B[k, j];
                    }
                }
            }
            return C;
        }
        private static BigInteger[,] Power(in BigInteger[,] A, ulong n)
        {
            if (A.GetLength(1) != A.GetLength(0))
            {
                throw new ArgumentException("Not a square matrix.");
            }
            var C = new BigInteger[A.GetLength(0), A.GetLength(1)];
            for (int i = 0; i < A.GetLength(0); ++i)
            {
                C[i, i] = BigInteger.One;
            }
            if (0 == n) return C;
            var S = new BigInteger[A.GetLength(0), A.GetLength(1)];
            for (int i = 0; i < A.GetLength(0); ++i)
            {
                for (int j = 0; j < A.GetLength(1); ++j)
                {
                    S[i, j] = A[i, j];
                }
            }
            while (0 < n)
            {
                if (1 == n % 2) C = Multiply(C, S);
                S = Multiply(S,S);
                n /= 2;
            }
            return C;
        }
        public static BigInteger Fib(in ulong n)
        {
            var C = Power(F, n);
            return C[0, 1];
        }
        public static void Task(in ulong p)
        {
            var ans = Fib(p).ToString();
            var sp = p.ToString("N0", nfi);
            if (ans.Length <= 40)
            {
                Console.WriteLine("Fibonacci({0}) = {1}", sp, ans);
            }
            else
            {
                Console.WriteLine("Fibonacci({0}) = {1} ... {2}", sp, ans[0..19], ans[^20..]);
            }
        }
        public static void Main()
        {
            Stopwatch stopWatch = new Stopwatch();
            stopWatch.Start();
            for (ulong p = 10; p <= 10_000_000; p *= 10) {
                Task(p);
            }
            stopWatch.Stop();
            TimeSpan ts = stopWatch.Elapsed;
            string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}",
                ts.Hours, ts.Minutes, ts.Seconds,
                ts.Milliseconds / 10);
            Console.WriteLine("Took " + elapsedTime);
        }
    }
}



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);
    }

}