package Supporting;

/**
 * Class that contains a selection of numerical routines.
 * @author Mark Allen Weiss
 */
public final class Numerical
{
    /**
     * Return x^n (mod p)
     * Assumes x, n >= 0, p > 0, x < p, 0^0 = 1
     * Overflow may occur if p > 31 bits.
     */
    public static long power( long x, long n, long p )
    {
        if( n == 0 )
            return 1;

        long tmp = power( ( x * x ) % p, n / 2, p );

        if( n % 2 != 0 )
            tmp = ( tmp * x ) % p;

        return tmp;
    }

    /**
     * Private method that implements the basic primality test.
     * If witness does not return 1, n is definitely composite.
     * Do this by computing a^i (mod n) and looking for
     * non-trivial square roots of 1 along the way.
     */
    private static long witness( long a, long i, long n )
    {
        if( i == 0 )
            return 1;

        long x = witness( a, i / 2, n );
        if( x == 0 )    // If n is recursively composite, stop
            return 0;

        // n is not prime if we find a non-trivial square root of 1
        long y = ( x * x ) % n;
        if( y == 1 && x != 1 && x != n - 1 )
            return 0;

        if( i % 2 != 0 )
            y = ( a * y ) % n;

        return y;
    }

    /**
     * The number of witnesses queried in randomized primality test.
     */
    public static final int TRIALS = 5;

    /**
     * Randomized primality test.
     * Adjust TRIALS to increase confidence level.
     * @param n the number to test.
     * @return if false, n is definitely not prime.
     *     If true, n is probably prime.
     */
    public static boolean isPrime( long n )
    {
        Random r = new Random( );

        for( int counter = 0; counter < TRIALS; counter++ )
            if( witness( r.randomInt( 2, (int) n - 2 ), n - 1, n ) != 1 )
                return false;

        return true;
    }

    /**
     * Return the greatest common divisor.
     */
    public static long gcd( long a, long b )
    {
        if( b == 0 )
            return a;
        else
            return gcd( b, a % b );
    }

        // Internal variables for fullGcd
    private static long x;
    private static long y;

    /**
     * Works back through Euclid's algorithm to find
     * x and y such that if gcd(a,b) = 1,
     * ax + by = 1.
     */
    private static void fullGcd( long a, long b )
    {
        long x1, y1;

        if( b == 0 )
        {
            x = 1;
            y = 0;
        }
        else
        {
            fullGcd( b, a % b );
            x1 = x; y1 = y;
            x = y1;
            y = x1 - ( a / b ) * y1;
        }
    }

    /**
     * Solve ax == 1 (mod n), assuming gcd( a, n ) = 1.
     * @return x.
     */
    public static long inverse( long a, long n )
    {
        fullGcd( a, n );
        return x > 0 ? x : x + n;
    }
}
