package net.cynthia; /** * An immutable class containing a fraction. Operations in this class return a * new Fraction containing their result; they do not modify any * original Fraction. *

* Operations supported by objects of this class are: *

* * @author Cynthia G. */ public class Fraction implements java.io.Serializable, Comparable { private static final long serialVersionUID = 1L; /** * The numerator of this Fraction. */ private final long numerator; /** * The denominator of this Fraction. */ private final long denominator; /** * Constructs a Fraction representing the value 0. The * denominator does not matter, but this constructor sets it to 1. */ public Fraction() { this(0L); } /** * Constructs a Fraction having the given numerator * and a denominator of 1. * * @param numerator * The numerator of the newly created Fraction. */ public Fraction(final long numerator) { this.numerator = numerator; denominator = 1L; } /** * Constructs a Fraction having the given numerator * and denominator. * * @param numerator * The numerator of the newly created Fraction. * @param denominator * The denominator of the newly created Fraction. */ 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 Fractions 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 Fraction whose numerator is the given * number and whose denominator is 1. Calling this method may * be more efficient than creating Fractions on demand, since * frequently-used values may be cached. * * @param number * The number to use as the returned Fraction's * numerator. * @return a Fraction whose numerator is the given * number 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 Fraction. The numerator is the * integer above the division bar in a fraction when written out. * * @return the numerator of this Fraction */ public long getNumerator() { return numerator; } /** * Returns the denominator of this Fraction. 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 Fraction */ public long getDenominator() { return denominator; } /** * Adds this Fraction and the other one together, * then returns the result of that addition. * * @param other * The Fraction to add to this one. * @return the result of the addition of this Fraction and the * other 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 Fraction and the given number * together, then returns the result of that addition. * * @param number * The number to add to this Fraction. * @return the result of the addition of this Fraction and the * given number */ public Fraction add(final long number) { return add(valueOf(number)); } /** * Subtracts the other Fraction from this one, * then returns the result of that subtraction. * * @param other * The Fraction to subtract from this one. * @return the result of the subtraction of the * other Fraction from this one */ public Fraction subtract(final Fraction other) { return add(other.negate()); } /** * Subtracts the given number from this Fraction, * then returns the result of that subtraction. * * @param number * The number to subtract from this Fraction. * @return the result of the subtraction of the given number * from this Fraction */ public Fraction subtract(final long number) { return subtract(valueOf(number)); } /** * Multiplies this Fraction by the other one, then * returns the result of that multiplication. * * @param other * The Fraction to multiply this one by. * @return the result of the multiplication of this Fraction by * the other one */ public Fraction multiply(final Fraction other) { return new Fraction(numerator * other.numerator, denominator * other.denominator); } /** * Multiplies this Fraction by the given number, * then returns the result of that multiplication. * * @param number * The number to multiply this Fraction by. * @return the result of the multiplication of this Fraction by * the given number */ public Fraction multiply(final long number) { return multiply(valueOf(number)); } /** * Divides this Fraction by the other one, then * returns the result of that division. * * @param other * The Fraction to divide this one by. * @return the result of the division of this Fraction by the * other one */ public Fraction divide(final Fraction other) { return multiply(other.inverse()); } /** * Divides this Fraction by the given number, * then returns the result of that division. * * @param number * The number to divide this Fraction by. * @return the result of the division of this Fraction by the * given number */ public Fraction divide(final long number) { return divide(valueOf(number)); } /** * Returns the inverse (1/x) of this Fraction. More formally, * returns a Fraction whose numerator is this one's denominator * and whose denominator is this one's numerator. If the resulting * Fraction's denominator would be negative, it is made positive * and the numerator is negated so that getDenominator's * contract is satisfied. * * @return the inverse (1/x) of this Fraction */ public Fraction inverse() { return new Fraction(denominator, numerator); } /** * Returns the negation (-x) of this Fraction. More formally, * returns a Fraction whose numerator is minus this one's * numerator and whose denominator is equal to this one's denominator. * * @return the negation (-x) of this Fraction */ public Fraction negate() { return new Fraction(-numerator, denominator); } /** * Returns the value held by this Fraction, as a * double value. * * @return the value held by this Fraction, as a * double value */ public double doubleValue() { return (double) numerator / denominator; } /** * Returns the value held by this Fraction, as a * float value. * * @return the value held by this Fraction, as a * float value */ public float floatValue() { return (float) doubleValue(); } /** * Returns the value held by this Fraction, as if by *
* Long.toString(getNumerator()) + "/" + Long.toString(getDenominator()) *
*/ @Override public String toString() { return Long.toString(numerator) + "/" + Long.toString(denominator); } /** * Reduces this Fraction and returns its reduced representation. * * @return the result of the reduction of this Fraction */ 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 Fraction and the given Object * are equal; that is, that they * */ @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 Fraction with the specified Fraction * for order. Returns a negative integer, zero, or a positive integer as * this Fraction is less than, equal to, or greater than the * specified Fraction. Exceptions to this rule are as follows: * * * @param o * The Fraction to be compared with this one. * @return a negative integer, zero, or a positive integer as this * Fraction is less than, equal to, or greater than the * given Fraction */ 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()); } }