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. }