/******************************************************************************
 *  Compilation:  javac Karatsuba.java
 *  Execution:    java Karatsuba N
 *
 *  Multiply two positive N-bit BigIntegers using Karatsuba multiplication.
 *
 *
 *  % java Karatsuba N
 * This basic code was obtained from the following website:
 * http://introcs.cs.princeton.edu/java/99crypto/Karatsuba.java.html
 * It was modified for the purpose of CON101.
 ******************************************************************************/

import java.math.BigInteger;
import java.util.Random;
import java.io.*;

class Karatsuba {
    private final static BigInteger ZERO = new BigInteger("0");
    public static final int BASE_CASE = 1;
    
    public static BigInteger karatsuba(BigInteger x, BigInteger y) {
        
        // cutoff to brute force
        int N = Math.max(x.bitLength(), y.bitLength());
        if (N <= BASE_CASE) return x.multiply(y);                // optimize this parameter
        
        // number of bits divided by 2, rounded up
        N = (N / 2) + (N % 2);
        
        // x = a + 2^N b,   y = c + 2^N d
        BigInteger b = x.shiftRight(N);
        BigInteger a = x.subtract(b.shiftLeft(N));
        BigInteger d = y.shiftRight(N);
        BigInteger c = y.subtract(d.shiftLeft(N));
        
        // compute sub-expressions
        BigInteger ac    = karatsuba(a, c);
        BigInteger bd    = karatsuba(b, d);
        BigInteger abcd  = karatsuba(a.add(b), c.add(d));
        
        return ac.add(abcd.subtract(ac).subtract(bd).shiftLeft(N)).add(bd.shiftLeft(2*N));
    }
    
    public static BigInteger longmultiplication(BigInteger x, BigInteger y){
        int n = y.bitLength();
        BigInteger sum = new BigInteger("0");
        for(int i=0; i<n;++i){
            if(y.testBit(i))sum = sum.add(x);
            x = x.shiftLeft(1);
        }
        return(sum);
    }
    
    public static void main(String[] args) {
        long start, stop, elapsed;
        Random random = new Random();
        int N = Integer.parseInt(args[0]);
        
        //This generates random N-bit numbers a and b
        BigInteger a = new BigInteger(N, random);
        BigInteger b = new BigInteger(N, random);
        
        //Print these numbers
        //System.out.println("a = " + a);
        //System.out.println("b = " + b);
        
        start = System.currentTimeMillis();
        BigInteger c = karatsuba(a, b);
        //System.out.println("a*b (by Karatsuba) = " + c);
        stop = System.currentTimeMillis();
        System.out.println("Time for Karatsuba: " + (stop - start));
        
        start = System.currentTimeMillis();
        BigInteger d = longmultiplication(a, b);
        //System.out.println("a*b (by long multiplication) = " + d);
        stop = System.currentTimeMillis();
        System.out.println("Time for Long Multiplication: " + (stop - start));
        
        //The next statement just confirms if the results are the same
        //System.out.println((c.equals(d)));
    }
}