package net.cynthia;/** * An immutable class containing a fraction. Operations in this class return a * new <tt>Fraction</tt> containing their result; they do not modify any * original <tt>Fraction</tt>. * <p> * Operations supported by objects of this class are: * <ul> * <li>addition to a fraction or a number; * <li>subtraction of a fraction or a number; * <li>multiplication by a fraction or a number; * <li>division by a fraction or a number. * </ul> * * @author Cynthia G. */public class Fraction implements java.io.Serializable, Comparable<Fraction> { private static final long serialVersionUID = 1L; /** * The numerator of this <tt>Fraction</tt>. */ private final long numerator; /** * The denominator of this <tt>Fraction</tt>. */ private final long denominator; /** * Constructs a <tt>Fraction</tt> representing the value 0. The * denominator does not matter, but this constructor sets it to 1. */ public Fraction() { this(0L); } /** * Constructs a <tt>Fraction</tt> having the given <code>numerator</code> * and a <code>denominator</code> of 1. * * @param numerator * The numerator of the newly created <tt>Fraction</tt>. */ public Fraction(final long numerator) { this.numerator = numerator; denominator = 1L; } /** * Constructs a <tt>Fraction</tt> having the given <code>numerator</code> * and <code>denominator</code>. * * @param numerator * The numerator of the newly created <tt>Fraction</tt>. * @param denominator * The denominator of the newly created <tt>Fraction</tt>. */ public Fraction(final long numerator, final long denominator) { if (denominator >= 0) { this.numerator = numerator; this.denominator = denominator; } else { this.numerator = -numerator; this.denominator = -denominator; } } /** * Size of the cache of <tt>Fraction</tt>s maintained by this class, of * either sign. */ private static final int CACHE_SIZE = 100; private static final Fraction[] CACHE = new Fraction[CACHE_SIZE * 2]; static { for (int i = -CACHE_SIZE; i < CACHE_SIZE; i++) CACHE[i + CACHE_SIZE] = new Fraction(i); } /** * Returns a <tt>Fraction</tt> whose numerator is the given * <code>number</code> and whose denominator is 1. Calling this method may * be more efficient than creating <tt>Fraction</tt>s on demand, since * frequently-used values may be cached. * * @param number * The number to use as the returned <tt>Fraction</tt>'s * numerator. * @return a <tt>Fraction</tt> whose numerator is the given * <code>number</code> and whose denominator is 1 */ public static Fraction valueOf(final long number) { if (number >= -CACHE_SIZE && number < CACHE_SIZE) return CACHE[(int) (number + CACHE_SIZE)]; return new Fraction(number); } /** * Returns the numerator of this <tt>Fraction</tt>. The numerator is the * integer above the division bar in a fraction when written out. * * @return the numerator of this <tt>Fraction</tt> */ public long getNumerator() { return numerator; } /** * Returns the denominator of this <tt>Fraction</tt>. The denominator is * the integer below the division bar in a fraction when written out. It is * never negative, but may be 0. * * @return the denominator of this <tt>Fraction</tt> */ public long getDenominator() { return denominator; } /** * Adds this <tt>Fraction</tt> and the <code>other</code> one together, * then returns the result of that addition. * * @param other * The <tt>Fraction</tt> to add to this one. * @return the result of the addition of this <tt>Fraction</tt> and the * <code>other</code> one */ public Fraction add(final Fraction other) { // If the denominator of either fraction is 0, return ?/0. if (denominator == 0 || other.denominator == 0) return new Fraction(0, 0); final long denominator; // If the denominators are already the same, if (this.denominator == other.denominator) // use it as the denominator of the resulting fraction. denominator = this.denominator; // If the denominator of one divides that of the other evenly, // use the greater one. else if (this.denominator % other.denominator == 0) denominator = this.denominator; else if (other.denominator % this.denominator == 0) denominator = other.denominator; // Otherwise, just multiply both. else denominator = this.denominator * other.denominator; final long numerator = this.numerator * (denominator / this.denominator) + other.numerator * (denominator / other.denominator); return new Fraction(numerator, denominator); } /** * Adds this <tt>Fraction</tt> and the given <code>number</code> * together, then returns the result of that addition. * * @param number * The number to add to this <tt>Fraction</tt>. * @return the result of the addition of this <tt>Fraction</tt> and the * given <code>number</code> */ public Fraction add(final long number) { return add(valueOf(number)); } /** * Subtracts the <code>other</code> <tt>Fraction</tt> from this one, * then returns the result of that subtraction. * * @param other * The <tt>Fraction</tt> to subtract from this one. * @return the result of the subtraction of the * <code>other</code> <tt>Fraction</tt> from this one */ public Fraction subtract(final Fraction other) { return add(other.negate()); } /** * Subtracts the given <code>number</code> from this <tt>Fraction</tt>, * then returns the result of that subtraction. * * @param number * The number to subtract from this <tt>Fraction</tt>. * @return the result of the subtraction of the given <code>number</code> * from this <tt>Fraction</tt> */ public Fraction subtract(final long number) { return subtract(valueOf(number)); } /** * Multiplies this <tt>Fraction</tt> by the <code>other</code> one, then * returns the result of that multiplication. * * @param other * The <tt>Fraction</tt> to multiply this one by. * @return the result of the multiplication of this <tt>Fraction</tt> by * the <code>other</code> one */ public Fraction multiply(final Fraction other) { return new Fraction(numerator * other.numerator, denominator * other.denominator); } /** * Multiplies this <tt>Fraction</tt> by the given <code>number</code>, * then returns the result of that multiplication. * * @param number * The number to multiply this <tt>Fraction</tt> by. * @return the result of the multiplication of this <tt>Fraction</tt> by * the given <code>number</code> */ public Fraction multiply(final long number) { return multiply(valueOf(number)); } /** * Divides this <tt>Fraction</tt> by the <code>other</code> one, then * returns the result of that division. * * @param other * The <tt>Fraction</tt> to divide this one by. * @return the result of the division of this <tt>Fraction</tt> by the * <code>other</code> one */ public Fraction divide(final Fraction other) { return multiply(other.inverse()); } /** * Divides this <tt>Fraction</tt> by the given <code>number</code>, * then returns the result of that division. * * @param number * The number to divide this <tt>Fraction</tt> by. * @return the result of the division of this <tt>Fraction</tt> by the * given <code>number</code> */ public Fraction divide(final long number) { return divide(valueOf(number)); } /** * Returns the inverse (1/x) of this <tt>Fraction</tt>. More formally, * returns a <tt>Fraction</tt> whose numerator is this one's denominator * and whose denominator is this one's numerator. If the resulting * <tt>Fraction</tt>'s denominator would be negative, it is made positive * and the numerator is negated so that <code>getDenominator</code>'s * contract is satisfied. * * @return the inverse (1/x) of this <tt>Fraction</tt> */ public Fraction inverse() { return new Fraction(denominator, numerator); } /** * Returns the negation (-x) of this <tt>Fraction</tt>. More formally, * returns a <tt>Fraction</tt> whose numerator is minus this one's * numerator and whose denominator is equal to this one's denominator. * * @return the negation (-x) of this <tt>Fraction</tt> */ public Fraction negate() { return new Fraction(-numerator, denominator); } /** * Returns the value held by this <tt>Fraction</tt>, as a * <code>double</code> value. * * @return the value held by this <tt>Fraction</tt>, as a * <code>double</code> value */ public double doubleValue() { return (double) numerator / denominator; } /** * Returns the value held by this <tt>Fraction</tt>, as a * <code>float</code> value. * * @return the value held by this <tt>Fraction</tt>, as a * <code>float</code> value */ public float floatValue() { return (float) doubleValue(); } /** * Returns the value held by this <tt>Fraction</tt>, as if by * <blockquote><code> * Long.toString(getNumerator()) + "/" + Long.toString(getDenominator()) * </code></blockquote> */ @Override public String toString() { return Long.toString(numerator) + "/" + Long.toString(denominator); } /** * Reduces this <tt>Fraction</tt> and returns its reduced representation. * * @return the result of the reduction of this <tt>Fraction</tt> */ public Fraction reduce() { // Edge case: Denominator == 0? If so, return this // Shortcut: Denominator == 1? If so, return this if (denominator <= 1) return this; // Otherwise, find what divides both the numerator and the denominator final long divisor = greatestCommonDivisor(numerator, denominator); return new Fraction(numerator / divisor, denominator / divisor); } @Override public int hashCode() { final int PRIME = 31; int result = 1; final Fraction reduced = reduce(); result = PRIME * result + (int) (reduced.denominator ^ (reduced.denominator >>> 32)); result = PRIME * result + (int) (reduced.numerator ^ (reduced.numerator >>> 32)); return result; } /** * Determines whether this <tt>Fraction</tt> and the given <tt>Object</tt> * are equal; that is, that they * <ul> * <li>represent the same <tt>Object</tt>, or * <li>represent fractions with equal numerators and denominators, or * <li>represent fractions which, when reduced, represent fractions with * equal numerators and denominators. * </ul> */ @Override public boolean equals(final Object obj) { if (this == obj) return true; if (obj == null) return false; if (!(obj instanceof Fraction)) return false; final Fraction other = (Fraction) obj; if (numerator == other.numerator && denominator == other.denominator) return true; final Fraction reducedThis = reduce(), reducedOther = other.reduce(); if (reducedThis.numerator == reducedOther.numerator && reducedThis.denominator == reducedOther.denominator) return true; return false; } /** * Compares this <tt>Fraction</tt> with the specified <tt>Fraction</tt> * for order. Returns a negative integer, zero, or a positive integer as * this <tt>Fraction</tt> is less than, equal to, or greater than the * specified <tt>Fraction</tt>. Exceptions to this rule are as follows: * <ul> * <li>any <tt>Fraction</tt> that has 0 as its denominator will be * ordered before any other <tt>Fraction</tt> except another * <tt>Fraction</tt> that has 0 as its denominator; * <li> two <tt>Fraction</tt>s that have 0 as their denominators will be * ordered according to their numerators. * </ul> * * @param o * The <tt>Fraction</tt> to be compared with this one. * @return a negative integer, zero, or a positive integer as this * <tt>Fraction</tt> is less than, equal to, or greater than the * given <tt>Fraction</tt> */ public int compareTo(final Fraction o) { if (denominator == 0) { if (o.denominator == 0) return (int) Math.signum(numerator - o.numerator); else return -1; } else if (o.denominator == 0) return 1; else return (int) Math.signum(doubleValue() - o.doubleValue()); } /** * Calculates the greatest common divisor of the two given numbers using * Euclid's algorithm. * * @param a * The first number. * @param b * The second number. * @return the greatest common divisor of the two given numbers */ private static long greatestCommonDivisor(final long a, final long b) { if (b == 0L) return a; else return greatestCommonDivisor(b, a % b); } public static void main(final String[] args) { Fraction c, d, x; // Fraction Objects c = new Fraction(5, 8); d = new Fraction(4, 10); x = new Fraction(); // create a fraction for the number 0 System.out.println(c); System.out.println(d); System.out.println(x); x = x.add(c).add(d); System.out.println(x); System.out.println(x.doubleValue()); x = new Fraction(1); // create a fraction for the number 1 x = x.multiply(c).multiply(d); System.out.println(x); System.out.println(x.doubleValue()); x = new Fraction(6, 0); System.out.println(x.doubleValue()); }}