Source code for Rational.java

What follows is the highlighted source code with comments. You can also download this file directly: Rational.java.

/*
 * This work by W. Patrick Hooper is free of known copyright restrictions.
 * The work is in the public domain.
 * 
 * Author's website: <a href="http://wphooper.com">http://wphooper.com</a>. 
 */

package number;

// Allow us to use Java's built in BigInteger class
import java.math.BigInteger;

/** 
 * An instance of this class stores a rational number. The rational is 
 * normalized so that the denominator is always positive, and the 
 * numerator and denominator are relatively prime.
 * 
 * @author W. Patrick Hooper (wphooper@gmail.com)
 */
public class Rational {
    
    /** The numerator and denominator. 
     * I've marked these things private, because I don't want anyone accessing them directly.
     * I've marked them final, because I don't want them to change once I've set them.
     */
    private final BigInteger n, d;

    /** Return the numerator of this rational. */
    public BigInteger numerator() {
        return n;
    }

    /** Return the denominator of this rational. */ 
    public BigInteger denominator() {
        return d;
    }
    
    /** Construct a rational with an integral value. */
    public Rational(BigInteger numerator) {
        n = numerator;
        d = BigInteger.valueOf(1);
    }
    
    /** Construct a rational with an integral value. */
    public Rational(long numerator) {
        this(BigInteger.valueOf(numerator));
    }

    /** Construct the rational p/q. */
    public Rational(BigInteger p, BigInteger q) {
        // the signnum function returns 1 if q>0, 0 if q=0, and -1 if q<0.
        int s = q.signum();
        
        // So, this says "if d<0"...
        if (s <= 0) {
            // if s is 0, then we have a zero in the denominator!
            if (s == 0) {
                // this throws an exception to indicate that we divided by zero
                // So, this rational is going to be invalid.
                throw new ArithmeticException("Division by zero in fraction");
            }
            
            // Now we will negate both the numerator and denominator. 
            // This guarantees that we are storing the same rational, but 
            // now the denominator is positive.
            p = p.negate();
            q = q.negate();
        }
        // Set x to be the GCD of n and d.
        BigInteger x = p.gcd(q);
        
        // store the numerator divided by the GCD
        n = p.divide(x);
        // store the denominator divided by the GCD
        d = q.divide(x);        
    }

    /** Construct the rational p/q. */
    public Rational(long p, long q) {
        this(BigInteger.valueOf(p), BigInteger.valueOf(q));
    }

    
    
    
    
    /** Return the sign of this rational. It returns 1 if the rational is positive,
     * 0 if the rational is zero, and -1 if the rational is negative.
     */
    public int signum() {
        return numerator().signum();
    }
    
    
    
    
    
    
    
    
    
    /** Convert this rational to a string. */
    @Override
    public String toString() {
        if (this.denominator().equals(BigInteger.ONE)) {
            // We have an integer, return just the numerator.
            return this.numerator().toString();
        } else {
            // We have a non-trivial denominator, we'll return the ratio.
            // Following a string by a "+" and an object converts the object to 
            // a string and concatenates the two strings.
            return "" + this.numerator() + "/" + this.denominator();
        }
    }

    /** 
     * Return true if the object is a rational which is numerically equal to
     * this rational. 
     * @param obj The object to compare to.
     */
    @Override
    public boolean equals(Object obj) {
        // Return false if the object is null
        if (obj == null) return false;
        // Return true if passed the exact same object
        if (obj == this) return true;
        // Return false if the object is not a rational
        if (!(obj instanceof Rational)) return false;
        
        // now the object must be a rational, so we can convert it to a rational
        Rational other = (Rational) obj;
        
        // if the numerators are not equal return false
        if (! this.n.equals(other.n)) {
            return false;
        }
        // if the denominators are not equal return false
        if (! this.d.equals(other.d)) {
            return false;
        }
        // The numerator and denominator are equal: return true
        return true;
    }
    
    // Remark: In Java, we should really override the hashcode function
    // whenever we override the equals function. But, I don't want to 
    // get into this for a light introduction to programming in java.   

}
HOOPER >>>>> JAVA TUTORIAL
Last modified on August 25, 2021.
[check html] [check css]