Block B


import java.math.BigInteger;
/**
 * This is a class of immutible object that support extended-precision
 * rational arithmetic.  All of the usual arithmetic operations are
 * supported.
 */
public class BigFraction
{
    /**
     * This is the BigFraction 0/1
     */
    public final static BigFraction ZERO;
    /**
     * This is the BigFraction 0/1
     */
    public final static BigFraction ONE;
    /**
     * This is the BigFraction 1/2
     */
    public final static BigFraction HALF;
    //static block.
    static 
    {
        ZERO = new BigFraction();
        ONE = BigFraction.valueOf(1,1);
        HALF = BigFraction.valueOf(1,2);
    }

    private final BigInteger num;
    private final BigInteger denom;
    /**
     * This creates a BigFraction with the specified numerator and 
     * denominator
     * @param num this is the numerator we are specifying
     * @param denom this is the denominator we are specifying
     */
    public BigFraction(BigInteger num, BigInteger denom)
    {
        if(denom.equals(BigInteger.ZERO))
        {
            throw new IllegalArgumentException();
        }
        BigInteger d = denom.gcd(num);
        num = num.divide(d);
        denom = denom.divide(d);
        if(denom.compareTo(BigInteger.ZERO) < 0)
        {
            num = num.negate();
            denom = denom.negate();
        }
        this.num = num;
        this.denom = denom;
    }
    /**
     * This creates the BigFraction 0/1, which is the same as BigFraction.ZERO.
     */
    public BigFraction()
    {
        this(BigInteger.ZERO, BigInteger.ONE);
    }
    /**
     * This gives a string represention of the form numerator/denominator.
     * @return a string representation of the form numerator/denominator.
     */
    @Override
    public String toString()
    {
        return String.format("%s/%s", num, denom);
    }
    /**
     * This checks if this BigFraction has the same numerical value as
     * the object o.
     * @param o the object we are comparing this BigFraction to.
     * @return true if o is a BigFraction and if it is numerically
     * equal to this BigFraction
     */
    @Override
    public boolean equals(Object o)
    {
        if(o == this)
        {
            return true;
        }
        //species test
        if( !(o instanceof BigFraction))
        {
            return false;
        }
        BigFraction that = (BigFraction) o;
        return num.equals(that.num) && denom.equals(that.denom);
    }
    /**
     * This computes this + that.
     * @param that the BigFraction we are adding this BigFraction to.
     * @return this + that
     */
    public BigFraction add(BigFraction that)
    {
        BigInteger top = num.multiply(that.denom).add(denom.multiply(that.num));
        BigInteger bottom = denom.multiply(that.denom);
        return new BigFraction(top, bottom);
    }
    /**
     * This computes this - that.
     * @param that the BigFraction we are subtracting this BigFraction from.
     * @return this - that
     */
    public BigFraction subtract(BigFraction that)
    {
        BigInteger top = num.multiply(that.denom).subtract(denom.multiply(that.num));
        BigInteger bottom = denom.multiply(that.denom);
        return new BigFraction(top, bottom);
    }
    /**
     * This computes this*that.
     * @param that the BigFraction we are multiplying this BigFraction by.
     * @return this*that
     */
    public BigFraction multiply(BigFraction that)
    {
        BigInteger top = num.multiply(that.num);
        BigInteger bottom = denom.multiply(that.num);
        return new BigFraction(top, bottom);
    }
    /**
     * This computes this/that.
     * @param that the BigFraction we are dividing this BigFraction by.
     * @return this/that
     */
    public BigFraction divide(BigFraction that)
    {
        BigInteger top = num.multiply(that.denom);
        BigInteger bottom = denom.multiply(that.num);
        return new BigFraction(top, bottom);
    }
    /**
     * This is a static factory method that allows a BigFraction to 
     * specified by longs in the numerator and the denominator.
     * @param num the numerator we are specifying
     * @param denom the denominator we are specifying
     * @return the BigFraction num/denom.
     */
    public static BigFraction valueOf(long num, long denom)
    {
        return new BigFraction(BigInteger.valueOf(num), BigInteger.valueOf(denom));
    }
    /*
     * This is where test code is dumped.
     */
    public static void main(String[] args)
    {
        BigFraction boo = BigFraction.valueOf(3,4);
        System.out.println(boo);
        boo = BigFraction.valueOf(-3, -4);
        System.out.println(boo);
        boo = BigFraction.valueOf(6,8);
        System.out.println(boo);
        boo = BigFraction.valueOf(1048576, 7776);
        System.out.println(boo);
        BigFraction total = new BigFraction();
        for(long k = 1; k <= 1000; k++)
        {
            total = total.add(BigFraction.valueOf(1, k));
        }
        System.out.println(total);
    }
}