001/* A Fraction.
002
003 Copyright (c) 1998-2014 The Regents of the University of California.
004 All rights reserved.
005 Permission is hereby granted, without written agreement and without
006 license or royalty fees, to use, copy, modify, and distribute this
007 software and its documentation for any purpose, provided that the above
008 copyright notice and the following two paragraphs appear in all copies
009 of this software.
010
011 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
012 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
013 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
014 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
015 SUCH DAMAGE.
016
017 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
018 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
019 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
020 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
021 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
022 ENHANCEMENTS, OR MODIFICATIONS.
023
024 PT_COPYRIGHT_VERSION_2
025 COPYRIGHTENDKEY
026
027 */
028package ptolemy.math;
029
030///////////////////////////////////////////////////////////////////
031//// Fraction
032
033/**
034 A class for representing fractions.  Fractions are immutable and
035 maintained in lowest terms, with a positive denominator.   Thus,
036 1/2 and 2/4 are interpreted as different names for the same number.
037 Any fraction with the value zero is expressed as 0/1 in lowest terms.
038 <p>This class only represents fractions with a determined value,
039 so fractions with a zero in the denominator are not allowed (including 0/0).
040
041 @author Stephen Neuendorffer, Adam Cataldo
042 @version $Id$
043 @since Ptolemy II 0.2
044 @Pt.ProposedRating Green (neuendor)
045 @Pt.AcceptedRating Yellow (cxh)
046 */
047public class Fraction extends Object {
048    /** Create a new fraction with the value zero (0/1).
049     */
050    public Fraction() {
051        _numerator = 0;
052        _denominator = 1;
053        _simplify();
054    }
055
056    /** Create a new fraction with the value i/1.
057     *  @param i The numerator.
058     */
059    public Fraction(int i) {
060        _numerator = i;
061        _denominator = 1;
062        _simplify();
063    }
064
065    /**
066     * Create a new fraction in lowest terms
067     * with the value Numerator/Denominator.
068     * @param numerator The numerator.
069     * @param denominator The denominator.
070     * @exception ArithmeticException If the denominator is specified to be
071     * zero.
072     */
073    public Fraction(int numerator, int denominator) {
074        if (denominator == 0) {
075            throw new ArithmeticException(
076                    "Illegal Fraction: " + "cannot have denominator of zero.");
077        }
078
079        _numerator = numerator;
080        _denominator = denominator;
081        _simplify();
082    }
083
084    /** Create a new fraction with the same value as the given fraction.
085     *  @param f The given Fraction.
086     */
087    public Fraction(Fraction f) {
088        _numerator = f._numerator;
089        _denominator = f._denominator;
090    }
091
092    ///////////////////////////////////////////////////////////////////
093    ////                         public methods                    ////
094
095    /** Add this fraction to the given fraction.
096     *  @param b The given Fraction.
097     *  @return The answer as another fraction in lowest terms.
098     */
099    public Fraction add(Fraction b) {
100        Fraction f = new Fraction(
101                _numerator * b._denominator + _denominator * b._numerator,
102                _denominator * b._denominator);
103        return f;
104    }
105
106    /** Divide this fraction by the given fraction.
107     *  @param b The given Fraction.
108     *  @return The answer as another fraction in lowest terms.
109     *  @exception ArithmeticException If the fraction in the divisor has
110     *  a value of zero.
111     */
112    public Fraction divide(Fraction b) {
113        if (b.equals(ZERO)) {
114            throw new ArithmeticException("Division by zero!");
115        }
116
117        Fraction f = new Fraction(_numerator * b._denominator,
118                _denominator * b._numerator);
119        return f;
120    }
121
122    /** Compare this fraction with the given object.
123     *  @return True if the given object is a fraction
124     *  and equal to this fraction.
125     */
126    @Override
127    public boolean equals(Object b) {
128        // The Fractions are already in lowest terms, so we just compare the
129        // numerator and denominator
130        if (b instanceof Fraction) {
131            return _numerator == ((Fraction) b)._numerator
132                    && _denominator == ((Fraction) b)._denominator;
133        }
134        return false;
135    }
136
137    /** Return the denominator of this fraction.
138     */
139    public int getDenominator() {
140        return _denominator;
141    }
142
143    /** Return the numerator of this fraction.
144     */
145    public int getNumerator() {
146        return _numerator;
147    }
148
149    /** Test if this Fraction is greater than the input.
150     *
151     * @param testInput The input to compare against.
152     * @return True if this Fraction is greater than the input.
153     */
154    public boolean greaterThan(Fraction testInput) {
155        int gcd = ExtendedMath.gcd(testInput.getDenominator(),
156                this.getDenominator());
157        int thisScaled = this.multiply(new Fraction(gcd, 1)).getNumerator();
158        int inputScaled = testInput.multiply(new Fraction(gcd, 1))
159                .getNumerator();
160
161        if (thisScaled > inputScaled) {
162            return true;
163        }
164        return false;
165    }
166
167    /** Return a hash code value for this Fraction. This method returns the
168     *  bitwise and of the hashcode of the denominator and the numerator.
169     *  @return A hash code value for this Coordinate
170     */
171    @Override
172    public int hashCode() {
173        return Integer.valueOf(_denominator).hashCode()
174                & Integer.valueOf(_numerator).hashCode();
175    }
176
177    /** Find the multiplicative inverse of this fraction.
178     *  @return The answer as another fraction in lowest terms
179     *  @exception ArithmeticException If this fraction has a value of zero,
180     *  in which case the multiplicative inverse cannot be represented.
181     */
182    public Fraction inverse() {
183        if (equals(ZERO)) {
184            throw new ArithmeticException("Inverse of zero is undefined!");
185        }
186
187        Fraction f = new Fraction(_denominator, _numerator);
188        return f;
189    }
190
191    /** Finds the least common multiple(LCM) of two integers.
192     *  If one of the numbers is negative, then the LCM is negative.
193     *  If both of the numbers are negative, then the LCM is positive.
194     *  the LCM is least in terms of absolute value.
195     */
196
197    //FIXME: should this go someplace better?
198    public static int lcm(int u, int v) {
199        int gcd = ExtendedMath.gcd(u, v);
200        int result = u * v / gcd;
201        return result;
202    }
203
204    /** Multiply this fraction by the given fraction.
205     *  @return The answer as another fraction in lowest terms.
206     */
207    public Fraction multiply(Fraction b) {
208        Fraction f = new Fraction(_numerator * b._numerator,
209                _denominator * b._denominator);
210        return f;
211    }
212
213    /** Find the additive inverse of this fraction.
214     *  @return The answer as another fraction in lowest terms
215     */
216    public Fraction negate() {
217        Fraction f = new Fraction(-_numerator, _denominator);
218        return f;
219    }
220
221    /** Subtract the given fraction from this fraction.
222     *  @return The answer as another fraction in lowest terms
223     */
224    public Fraction subtract(Fraction b) {
225        Fraction f = new Fraction(
226                _numerator * b._denominator - _denominator * b._numerator,
227                _denominator * b._denominator);
228        return f;
229    }
230
231    /** Convert the fraction to a double.
232     *  @return The double value.
233     */
234    public double toDouble() {
235        double numerator;
236        double denominator;
237        numerator = _numerator;
238        denominator = _denominator;
239        return numerator / denominator;
240    }
241
242    /** Convert the fraction to a float.
243     *  @return The float value.
244     */
245    public float toFloat() {
246        float numerator;
247        float denominator;
248        numerator = _numerator;
249        denominator = _denominator;
250        return numerator / denominator;
251    }
252
253    /** Convert the fraction to a readable string.
254     */
255    @Override
256    public String toString() {
257        _simplify();
258        return _numerator + "/" + _denominator;
259    }
260
261    ///////////////////////////////////////////////////////////////////
262    ////                         public variables                  ////
263
264    /** The value of zero as a Fraction.
265     * It is arguable as to whether or not this is needed.  It may
266     * reduce the number of object creations, and increase speed,
267     * depending how often a zero fraction is needed.  This may become
268     * useful when this class is made into a Token.
269     */
270    public static final Fraction ZERO = new Fraction(0, 1);
271
272    /** Reduce the fraction to lowest terms by dividing the Numerator and
273     *  Denominator by their Greatest Common Divisor.  In addition the
274     *  fraction is put in standard form (denominator greater than zero).
275     */
276    protected void _simplify() {
277        int factor = ExtendedMath.gcd(_numerator, _denominator);
278        _numerator = _numerator / factor;
279        _denominator = _denominator / factor;
280
281        // Standardize the sign
282        if (_denominator < 0) {
283            _denominator = -_denominator;
284            _numerator = -_numerator;
285        }
286    }
287
288    ///////////////////////////////////////////////////////////////////
289    ////                         private variables                 ////
290
291    private int _numerator;
292
293    private int _denominator;
294}