View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.lang3.math;
18  
19  import java.io.IOException;
20  import java.io.InvalidObjectException;
21  import java.io.ObjectInputStream;
22  import java.io.Serializable;
23  import java.math.BigInteger;
24  import java.util.Objects;
25  
26  /**
27   * {@link Fraction} is a {@link Number} implementation that stores fractions accurately.
28   * <p>
29   * This class is immutable, and interoperable with most methods that accept a {@link Number}.
30   * </p>
31   * <p>
32   * Note that this class is intended for common use cases, it is <em>int</em> based and thus suffers from various overflow issues. For a BigInteger based
33   * equivalent, please see the Commons Math BigFraction class.
34   * </p>
35   *
36   * @since 2.0
37   */
38  public final class Fraction extends Number implements Comparable<Fraction> {
39  
40      /**
41       * Required for serialization support. Lang version 2.0.
42       *
43       * @see Serializable
44       */
45      private static final long serialVersionUID = 65382027393090L;
46  
47      /**
48       * {@link Fraction} representation of 0.
49       */
50      public static final Fraction ZERO = new Fraction(0, 1);
51  
52      /**
53       * {@link Fraction} representation of 1.
54       */
55      public static final Fraction ONE = new Fraction(1, 1);
56  
57      /**
58       * {@link Fraction} representation of 1/2.
59       */
60      public static final Fraction ONE_HALF = new Fraction(1, 2);
61  
62      /**
63       * {@link Fraction} representation of 1/3.
64       */
65      public static final Fraction ONE_THIRD = new Fraction(1, 3);
66  
67      /**
68       * {@link Fraction} representation of 2/3.
69       */
70      public static final Fraction TWO_THIRDS = new Fraction(2, 3);
71  
72      /**
73       * {@link Fraction} representation of 1/4.
74       */
75      public static final Fraction ONE_QUARTER = new Fraction(1, 4);
76  
77      /**
78       * {@link Fraction} representation of 2/4.
79       */
80      public static final Fraction TWO_QUARTERS = new Fraction(2, 4);
81  
82      /**
83       * {@link Fraction} representation of 3/4.
84       */
85      public static final Fraction THREE_QUARTERS = new Fraction(3, 4);
86  
87      /**
88       * {@link Fraction} representation of 1/5.
89       */
90      public static final Fraction ONE_FIFTH = new Fraction(1, 5);
91  
92      /**
93       * {@link Fraction} representation of 2/5.
94       */
95      public static final Fraction TWO_FIFTHS = new Fraction(2, 5);
96  
97      /**
98       * {@link Fraction} representation of 3/5.
99       */
100     public static final Fraction THREE_FIFTHS = new Fraction(3, 5);
101 
102     /**
103      * {@link Fraction} representation of 4/5.
104      */
105     public static final Fraction FOUR_FIFTHS = new Fraction(4, 5);
106 
107     /**
108      * Checks that a denominator is not zero.
109      *
110      * @param denominator The denominator to check
111      * @throws ArithmeticException Thrown if the denominator is zero.
112      */
113     private static void checkDenominator(final int denominator) {
114         if (denominator == 0) {
115             throw new ArithmeticException("The denominator must not be zero");
116         }
117     }
118 
119     /**
120      * Gets a {@link Fraction} instance from a {@code double} value.
121      * <p>
122      * This method uses the <a href="https://web.archive.org/web/20210516065058/http%3A//archives.math.utk.edu/articles/atuyl/confrac/"> continued fraction
123      * algorithm</a>, computing a maximum of 25 convergents and bounding the denominator by 10,000.
124      * </p>
125      *
126      * @param value The double value to convert
127      * @return A new fraction instance that is close to the value
128      * @throws ArithmeticException Thrown if {@code |value| &gt; Integer.MAX_VALUE} or {@code value = NaN}.
129      * @throws ArithmeticException Thrown if the calculated denominator is {@code zero}.
130      * @throws ArithmeticException Thrown if the algorithm does not converge.
131      */
132     public static Fraction getFraction(double value) {
133         final int sign = value < 0 ? -1 : 1;
134         value = Math.abs(value);
135         if (value > Integer.MAX_VALUE || Double.isNaN(value)) {
136             throw new ArithmeticException("The value must not be greater than Integer.MAX_VALUE or NaN");
137         }
138         final int wholeNumber = (int) value;
139         value -= wholeNumber;
140         int numer0 = 0; // the pre-previous
141         int denom0 = 1; // the pre-previous
142         int numer1 = 1; // the previous
143         int denom1 = 0; // the previous
144         int numer2; // the current, setup in calculation
145         int denom2; // the current, setup in calculation
146         int a1 = (int) value;
147         int a2;
148         double x1 = 1;
149         double x2;
150         double y1 = value - a1;
151         double y2;
152         double delta1;
153         double delta2 = Double.MAX_VALUE;
154         double fraction;
155         int i = 1;
156         do {
157             delta1 = delta2;
158             a2 = (int) (x1 / y1);
159             x2 = y1;
160             y2 = x1 - a2 * y1;
161             numer2 = a1 * numer1 + numer0;
162             denom2 = a1 * denom1 + denom0;
163             fraction = (double) numer2 / (double) denom2;
164             delta2 = Math.abs(value - fraction);
165             a1 = a2;
166             x1 = x2;
167             y1 = y2;
168             numer0 = numer1;
169             denom0 = denom1;
170             numer1 = numer2;
171             denom1 = denom2;
172             i++;
173         } while (delta1 > delta2 && denom2 <= 10000 && denom2 > 0 && i < 25);
174         if (i == 25) {
175             throw new ArithmeticException("Unable to convert double to fraction");
176         }
177         // wholeNumber can be up to Integer.MAX_VALUE while denom0 > 1 for any non-integer value,
178         // so the int product overflows for values near the limit; check it instead of wrapping silently.
179         final int numerator = Math.addExact(numer0, mulAndCheck(wholeNumber, denom0));
180         return getReducedFraction(numerator * sign, denom0);
181     }
182 
183     /**
184      * Gets a {@link Fraction} instance with the 2 parts of a fraction Y/Z.
185      * <p>
186      * Any negative signs are resolved to be on the numerator.
187      * </p>
188      *
189      * @param numerator   The numerator, for example the three in 'three sevenths'
190      * @param denominator The denominator, for example the seven in 'three sevenths'
191      * @return A new fraction instance
192      * @throws ArithmeticException Thrown if the denominator is {@code zero} or the denominator is {@code negative} and the numerator is
193      *         {@code Integer#MIN_VALUE}.
194      */
195     public static Fraction getFraction(int numerator, int denominator) {
196         checkDenominator(denominator);
197         if (denominator < 0) {
198             if (numerator == Integer.MIN_VALUE || denominator == Integer.MIN_VALUE) {
199                 throw new ArithmeticException("overflow: can't negate");
200             }
201             numerator = -numerator;
202             denominator = -denominator;
203         }
204         return new Fraction(numerator, denominator);
205     }
206 
207     /**
208      * Gets a {@link Fraction} instance with the 3 parts of a fraction X Y/Z.
209      * <p>
210      * The negative sign must be passed in on the whole number part.
211      * </p>
212      *
213      * @param whole       The whole number, for example the one in 'one and three sevenths'
214      * @param numerator   The numerator, for example the three in 'one and three sevenths'
215      * @param denominator The denominator, for example the seven in 'one and three sevenths'
216      * @return A new fraction instance
217      * @throws ArithmeticException Thrown if the denominator is {@code zero}.
218      * @throws ArithmeticException Thrown if the denominator is negative.
219      * @throws ArithmeticException Thrown if the numerator is negative.
220      * @throws ArithmeticException Thrown if the resulting numerator exceeds {@code Integer.MAX_VALUE}.
221      */
222     public static Fraction getFraction(final int whole, final int numerator, final int denominator) {
223         checkDenominator(denominator);
224         if (denominator < 0) {
225             throw new ArithmeticException("The denominator must not be negative");
226         }
227         if (numerator < 0) {
228             throw new ArithmeticException("The numerator must not be negative");
229         }
230         final long numeratorValue;
231         if (whole < 0) {
232             numeratorValue = whole * (long) denominator - numerator;
233         } else {
234             numeratorValue = whole * (long) denominator + numerator;
235         }
236         if (numeratorValue < Integer.MIN_VALUE || numeratorValue > Integer.MAX_VALUE) {
237             throw new ArithmeticException("Numerator too large to represent as an Integer.");
238         }
239         return new Fraction((int) numeratorValue, denominator);
240     }
241 
242     /**
243      * Gets a Fraction from a {@link String}.
244      * <p>
245      * The formats accepted are:
246      * </p>
247      * <ol>
248      * <li>{@code double} String containing a dot</li>
249      * <li>{@code "X Y/Z"}</li>
250      * <li>{@code "Y/Z"}</li>
251      * <li>{@code "X"} (a simple whole number)</li>
252      * </ol>
253      * <p>
254      * and a {@code .}
255      * </p>
256      *
257      * @param str The string to parse, must not be {@code null}
258      * @return The new {@link Fraction} instance
259      * @throws NullPointerException  Thrown if the string is {@code null}
260      * @throws NumberFormatException Thrown if the number format is invalid, or if the string is well-formed but its value cannot be represented as a
261      *                               {@code Fraction}: a zero denominator such as {@code "1/0"}, a value outside the range of an {@code int} such as
262      *                               {@code "9999999999.5"}, or a mixed number whose combined numerator overflows. For those unrepresentable values, the causal
263      *                               {@link ArithmeticException} is preserved as the {@link Throwable#getCause() cause}.
264      */
265     public static Fraction getFraction(final String str) {
266         Objects.requireNonNull(str, "str");
267         // parse double format
268         int pos = str.indexOf('.');
269         if (pos >= 0) {
270             final double value = Double.parseDouble(str);
271             try {
272                 return getFraction(value);
273             } catch (final ArithmeticException e) {
274                 throw toNumberFormatException(str, e);
275             }
276         }
277 
278         // parse X Y/Z format
279         pos = str.indexOf(' ');
280         if (pos > 0) {
281             final int whole = Integer.parseInt(str.substring(0, pos));
282             final String remainder = str.substring(pos + 1);
283             pos = remainder.indexOf('/');
284             if (pos < 0) {
285                 throw new NumberFormatException("The fraction could not be parsed as the format X Y/Z");
286             }
287             final int numer = Integer.parseInt(remainder.substring(0, pos));
288             final int denom = Integer.parseInt(remainder.substring(pos + 1));
289             try {
290                 return getFraction(whole, numer, denom);
291             } catch (final ArithmeticException e) {
292                 throw toNumberFormatException(str, e);
293             }
294         }
295 
296         // parse Y/Z format
297         pos = str.indexOf('/');
298         if (pos < 0) {
299             // simple whole number
300             return getFraction(Integer.parseInt(str), 1);
301         }
302         final int numer = Integer.parseInt(str.substring(0, pos));
303         final int denom = Integer.parseInt(str.substring(pos + 1));
304         try {
305             return getFraction(numer, denom);
306         } catch (final ArithmeticException e) {
307             throw toNumberFormatException(str, e);
308         }
309     }
310 
311     /**
312      * Gets a reduced {@link Fraction} instance with the 2 parts of a fraction Y/Z.
313      * <p>
314      * For example, if the input parameters represent 2/4, then the created fraction will be 1/2.
315      * </p>
316      *
317      * <p>
318      * Any negative signs are resolved to be on the numerator.
319      * </p>
320      *
321      * @param numerator   The numerator, for example the three in 'three sevenths'
322      * @param denominator The denominator, for example the seven in 'three sevenths'
323      * @return A new fraction instance, with the numerator and denominator reduced
324      * @throws ArithmeticException Thrown if the denominator is {@code zero}, or the reduced numerator or positive denominator cannot be represented as an
325      *                             {@code int}.
326      */
327     public static Fraction getReducedFraction(int numerator, int denominator) {
328         checkDenominator(denominator);
329         if (numerator == 0) {
330             return ZERO; // normalize zero.
331         }
332         // Reduce common powers of two before sign normalization to avoid negating Integer.MIN_VALUE.
333         while ((numerator & 1) == 0 && (denominator & 1) == 0) {
334             numerator /= 2;
335             denominator /= 2;
336         }
337         if (denominator < 0) {
338             if (numerator == Integer.MIN_VALUE || denominator == Integer.MIN_VALUE) {
339                 throw new ArithmeticException("overflow: can't negate");
340             }
341             numerator = -numerator;
342             denominator = -denominator;
343         }
344         // simplify fraction.
345         final int gcd = greatestCommonDivisor(numerator, denominator);
346         numerator /= gcd;
347         denominator /= gcd;
348         return new Fraction(numerator, denominator);
349     }
350 
351     /**
352      * Gets the greatest common divisor of the absolute value of
353      * two numbers, using the "binary gcd" method which avoids
354      * division and modulo operations.  See Knuth 4.5.2 algorithm B.
355      * This algorithm is due to Josef Stein (1961).
356      *
357      * @param u  A non-zero number
358      * @param v  A non-zero number
359      * @return The greatest common divisor, never zero
360      */
361     private static int greatestCommonDivisor(int u, int v) {
362         // From Commons Math:
363         if (u == 0 || v == 0) {
364             if (u == Integer.MIN_VALUE || v == Integer.MIN_VALUE) {
365                 throw new ArithmeticException("overflow: gcd is 2^31");
366             }
367             return Math.abs(u) + Math.abs(v);
368         }
369         // if either operand is abs 1, return 1:
370         if (Math.abs(u) == 1 || Math.abs(v) == 1) {
371             return 1;
372         }
373         // keep u and v negative, as negative integers range down to
374         // -2^31, while positive numbers can only be as large as 2^31-1
375         // (i.e. we can't necessarily negate a negative number without
376         // overflow)
377         if (u > 0) {
378             u = -u;
379         } // make u negative
380         if (v > 0) {
381             v = -v;
382         } // make v negative
383         // B1. [Find power of 2]
384         int k = 0;
385         while ((u & 1) == 0 && (v & 1) == 0 && k < 31) { // while u and v are both even...
386             u /= 2;
387             v /= 2;
388             k++; // cast out twos.
389         }
390         if (k == 31) {
391             throw new ArithmeticException("overflow: gcd is 2^31");
392         }
393         // B2. Initialize: u and v have been divided by 2^k and at least
394         // one is odd.
395         int t = (u & 1) == 1 ? v : -(u / 2)/* B3 */;
396         // t negative: u was odd, v may be even (t replaces v)
397         // t positive: u was even, v is odd (t replaces u)
398         do {
399             /* assert u<0 && v<0; */
400             // B4/B3: cast out twos from t.
401             while ((t & 1) == 0) { // while t is even.
402                 t /= 2; // cast out twos
403             }
404             // B5 [reset max(u,v)]
405             if (t > 0) {
406                 u = -t;
407             } else {
408                 v = t;
409             }
410             // B6/B3. at this point both u and v should be odd.
411             t = (v - u) / 2;
412             // |u| larger: t positive (replace u)
413             // |v| larger: t negative (replace v)
414         } while (t != 0);
415         return -u * (1 << k); // gcd is u*2^k
416     }
417 
418     private static int hash(final int value1, final int value2) {
419         return Objects.hash(value1, value2);
420     }
421 
422     /**
423      * Multiplies two integers, checking for overflow.
424      *
425      * @param x A factor
426      * @param y A factor
427      * @return The product {@code x*y}
428      * @throws ArithmeticException Thrown if the result cannot be represented as an int.
429      */
430     private static int mulAndCheck(final int x, final int y) {
431         final long m = (long) x * (long) y;
432         if (m < Integer.MIN_VALUE || m > Integer.MAX_VALUE) {
433             throw new ArithmeticException("overflow: mul");
434         }
435         return (int) m;
436     }
437 
438     /**
439      *  Multiplies two non-negative integers, checking for overflow.
440      *
441      * @param x A non-negative factor
442      * @param y A non-negative factor
443      * @return The product {@code x*y}
444      * @throws ArithmeticException Thrown if the result cannot be represented as an int.
445      */
446     private static int mulPosAndCheck(final int x, final int y) {
447         /* assert x>=0 && y>=0; */
448         final long m = (long) x * (long) y;
449         if (m > Integer.MAX_VALUE) {
450             throw new ArithmeticException("overflow: mulPos");
451         }
452         return (int) m;
453     }
454 
455     /**
456      * Converts an {@link ArithmeticException} raised while parsing a string into the {@link NumberFormatException} that
457      * {@link #getFraction(String)} documents, preserving the original exception as the cause.
458      *
459      * @param str The string being parsed.
460      * @param cause The arithmetic failure: a zero denominator or a value outside the range of an {@code int}.
461      * @return The exception for the caller to throw, never {@code null}.
462      */
463     private static NumberFormatException toNumberFormatException(final String str, final ArithmeticException cause) {
464         final NumberFormatException nfe = new NumberFormatException("The fraction could not be parsed from '" + str + "': " + cause.getMessage());
465         nfe.initCause(cause);
466         return nfe;
467     }
468 
469     /**
470      * The numerator number part of the fraction (the three in three sevenths).
471      */
472     private final int numerator;
473 
474     /**
475      * The denominator number part of the fraction (the seven in three sevenths).
476      */
477     private final int denominator;
478 
479     /**
480      * Cached output hashCode (class is immutable).
481      */
482     private final int hashCode;
483 
484     /**
485      * Cached output toString (class is immutable).
486      */
487     private transient String toString;
488 
489     /**
490      * Cached output toProperString (class is immutable).
491      */
492     private transient String toProperString;
493 
494     /**
495      * Constructs a {@link Fraction} instance with the 2 parts
496      * of a fraction Y/Z.
497      *
498      * @param numerator  The numerator, for example the three in 'three sevenths'
499      * @param denominator  The denominator, for example the seven in 'three sevenths'
500      */
501     private Fraction(final int numerator, final int denominator) {
502         this.numerator = numerator;
503         this.denominator = denominator;
504         this.hashCode = hash(denominator, numerator);
505     }
506 
507     /**
508      * Gets a fraction that is the positive equivalent of this one.
509      * <p>
510      * More precisely: {@code (fraction &gt;= 0 ? this : -fraction)}
511      * </p>
512      * <p>
513      * The returned fraction is not reduced.
514      * </p>
515      *
516      * @return {@code this} if it is positive, or a new positive fraction instance with the opposite signed numerator
517      */
518     public Fraction abs() {
519         if (numerator >= 0) {
520             return this;
521         }
522         return negate();
523     }
524 
525     /**
526      * Adds the value of this fraction to another, returning the result in reduced form.
527      * The algorithm follows Knuth, 4.5.1.
528      *
529      * @param fraction  The fraction to add, must not be {@code null}
530      * @return A {@link Fraction} instance with the resulting values
531      * @throws NullPointerException Thrown if the fraction is {@code null}.
532      * @throws ArithmeticException Thrown if the resulting numerator or denominator exceeds {@code Integer.MAX_VALUE}.
533      */
534     public Fraction add(final Fraction fraction) {
535         return addSub(fraction, true /* add */);
536     }
537 
538     /**
539      * Implements add and subtract using the algorithm described in <a href="https://www-cs-faculty.stanford.edu/~knuth/taocp.html">
540      * The Art of Computer Programming (TAOCP)</a> 4.5.1 by Donald Knuth.
541      *
542      * @param fraction The fraction to subtract, must not be {@code null}
543      * @param isAdd true to add, false to subtract
544      * @return A {@link Fraction} instance with the resulting values
545      * @throws IllegalArgumentException Thrown if the fraction is {@code null}.
546      * @throws ArithmeticException Thrown if the resulting numerator or denominator
547      *   cannot be represented in an {@code int}.
548      */
549     private Fraction addSub(final Fraction fraction, final boolean isAdd) {
550         Objects.requireNonNull(fraction, "fraction");
551         // zero is identity for addition.
552         if (numerator == 0) {
553             return isAdd ? fraction.reduce() : fraction.reduce().negate();
554         }
555         if (fraction.numerator == 0) {
556             return reduce();
557         }
558         // Knuth 4.5.1 assumes operands in lowest terms and this class does not reduce on
559         // construction, so reduce both first, as multiplyBy does.
560         final int thisGcd = greatestCommonDivisor(numerator, denominator);
561         final int thatGcd = greatestCommonDivisor(fraction.numerator, fraction.denominator);
562         final int thisNumerator = numerator / thisGcd;
563         final int thisDenominator = denominator / thisGcd;
564         final int thatNumerator = fraction.numerator / thatGcd;
565         final int thatDenominator = fraction.denominator / thatGcd;
566         // if denominators are randomly distributed, d1 will be 1 about 61%
567         // of the time.
568         final int d1 = greatestCommonDivisor(thisDenominator, thatDenominator);
569         if (d1 == 1) {
570             // result is ((u*v' +/- u'v) / u'v')
571             // the int cross products u*v' and u'*v can overflow even when the reduced result
572             // fits an int, so widen to long and let Math narrow the final numerator back.
573             final long uvp = (long) thisNumerator * thatDenominator;
574             final long upv = (long) thatNumerator * thisDenominator;
575             final long t = isAdd ? Math.addExact(uvp, upv) : Math.subtractExact(uvp, upv);
576             return new Fraction(Math.toIntExact(t), mulPosAndCheck(thisDenominator, thatDenominator));
577         }
578         // the quantity 't' requires 65 bits of precision; see knuth 4.5.1
579         // exercise 7. we're going to use a BigInteger.
580         // t = u(v'/d1) +/- v(u'/d1)
581         final BigInteger uvp = BigInteger.valueOf(thisNumerator).multiply(BigInteger.valueOf(thatDenominator / d1));
582         final BigInteger upv = BigInteger.valueOf(thatNumerator).multiply(BigInteger.valueOf(thisDenominator / d1));
583         final BigInteger t = isAdd ? uvp.add(upv) : uvp.subtract(upv);
584         // but d2 doesn't need extra precision because
585         // d2 = gcd(t,d1) = gcd(t mod d1, d1)
586         final int tmodd1 = t.mod(BigInteger.valueOf(d1)).intValue();
587         final int d2 = tmodd1 == 0 ? d1 : greatestCommonDivisor(tmodd1, d1);
588 
589         // result is (t/d2) / (u'/d1)(v'/d2)
590         final BigInteger w = t.divide(BigInteger.valueOf(d2));
591         if (w.bitLength() > 31) {
592             throw new ArithmeticException("overflow: numerator too large after multiply");
593         }
594         return new Fraction(w.intValue(), mulPosAndCheck(thisDenominator / d1, thatDenominator / d2));
595     }
596 
597     /**
598      * Compares this object to another based on size.
599      * <p>
600      * Note: this class has a natural ordering that is inconsistent with equals, because, for example, equals treats 1/2 and 2/4 as different, whereas compareTo
601      * treats them as equal.
602      * </p>
603      *
604      * @param other The object to compare to
605      * @return -1 if this is less, 0 if equal, +1 if greater
606      * @throws ClassCastException Thrown if the object is not a {@link Fraction}.
607      * @throws NullPointerException Thrown if the object is {@code null}.
608      */
609     @Override
610     public int compareTo(final Fraction other) {
611         if (this == other || numerator == other.numerator && denominator == other.denominator) {
612             return 0;
613         }
614 
615         // otherwise see which is less
616         final long first = (long) numerator * (long) other.denominator;
617         final long second = (long) other.numerator * (long) denominator;
618         return Long.compare(first, second);
619     }
620 
621     /**
622      * Divide the value of this fraction by another.
623      *
624      * @param fraction  The fraction to divide by, must not be {@code null}
625      * @return A {@link Fraction} instance with the resulting values
626      * @throws NullPointerException Thrown if the fraction is {@code null}.
627      * @throws ArithmeticException Thrown if the fraction to divide by is zero.
628      * @throws ArithmeticException Thrown if the resulting numerator or denominator exceeds {@code Integer.MAX_VALUE}.
629      */
630     public Fraction divideBy(final Fraction fraction) {
631         Objects.requireNonNull(fraction, "fraction");
632         if (fraction.numerator == 0) {
633             throw new ArithmeticException("The fraction to divide by must not be zero");
634         }
635         return multiplyBy(fraction.invert());
636     }
637 
638     /**
639      * Gets the fraction as a {@code double}. This calculates the fraction
640      * as the numerator divided by denominator.
641      *
642      * @return The fraction as a {@code double}
643      */
644     @Override
645     public double doubleValue() {
646         return (double) numerator / (double) denominator;
647     }
648 
649     /**
650      * Compares this fraction to another object to test if they are equal.
651      * <p>
652      * To be equal, both values must be equal. Thus 2/4 is not equal to 1/2.
653      * </p>
654      *
655      * @param obj The reference object with which to compare
656      * @return {@code true} if this object is equal
657      */
658     @Override
659     public boolean equals(final Object obj) {
660         if (obj == this) {
661             return true;
662         }
663         if (!(obj instanceof Fraction)) {
664             return false;
665         }
666         final Fraction other = (Fraction) obj;
667         return getNumerator() == other.getNumerator() && getDenominator() == other.getDenominator();
668     }
669 
670     /**
671      * Gets the fraction as a {@code float}. This calculates the fraction
672      * as the numerator divided by denominator.
673      *
674      * @return The fraction as a {@code float}
675      */
676     @Override
677     public float floatValue() {
678         return (float) numerator / (float) denominator;
679     }
680 
681     /**
682      * Gets the denominator part of the fraction.
683      *
684      * @return The denominator fraction part
685      */
686     public int getDenominator() {
687         return denominator;
688     }
689 
690     /**
691      * Gets the numerator part of the fraction.
692      * <p>
693      * This method may return a value greater than the denominator, an improper fraction, such as the seven in 7/4.
694      * </p>
695      *
696      * @return The numerator fraction part
697      */
698     public int getNumerator() {
699         return numerator;
700     }
701 
702     /**
703      * Gets the proper numerator, always positive.
704      * <p>
705      * An improper fraction 7/4 can be resolved into a proper one, 1 3/4. This method returns the 3 from the proper fraction.
706      * </p>
707      *
708      * <p>
709      * If the fraction is negative such as -7/4, it can be resolved into -1 3/4, so this method returns the positive proper numerator, 3.
710      * </p>
711      *
712      * @return The numerator fraction part of a proper fraction, always positive
713      */
714     public int getProperNumerator() {
715         return Math.abs(numerator % denominator);
716     }
717 
718     /**
719      * Gets the proper whole part of the fraction.
720      * <p>
721      * An improper fraction 7/4 can be resolved into a proper one, 1 3/4. This method returns the 1 from the proper fraction.
722      * </p>
723      *
724      * <p>
725      * If the fraction is negative such as -7/4, it can be resolved into -1 3/4, so this method returns the positive whole part -1.
726      * </p>
727      *
728      * @return The whole fraction part of a proper fraction, that includes the sign
729      */
730     public int getProperWhole() {
731         return numerator / denominator;
732     }
733 
734     /**
735      * Gets a hashCode for the fraction.
736      *
737      * @return A hash code value for this object
738      */
739     @Override
740     public int hashCode() {
741         return hashCode;
742     }
743 
744     /**
745      * Gets the fraction as an {@code int}. This returns the whole number
746      * part of the fraction.
747      *
748      * @return The whole number fraction part
749      */
750     @Override
751     public int intValue() {
752         return numerator / denominator;
753     }
754 
755     /**
756      * Gets a fraction that is the inverse (1/fraction) of this one.
757      * <p>
758      * The returned fraction is not reduced.
759      * </p>
760      *
761      * @return A new fraction instance with the numerator and denominator inverted.
762      * @throws ArithmeticException Thrown if the fraction represents zero.
763      */
764     public Fraction invert() {
765         if (numerator == 0) {
766             throw new ArithmeticException("Unable to invert zero.");
767         }
768         if (numerator == Integer.MIN_VALUE) {
769             throw new ArithmeticException("overflow: can't negate numerator");
770         }
771         if (numerator < 0) {
772             return new Fraction(-denominator, -numerator);
773         }
774         return new Fraction(denominator, numerator);
775     }
776 
777     /**
778      * Gets the fraction as a {@code long}. This returns the whole number
779      * part of the fraction.
780      *
781      * @return The whole number fraction part
782      */
783     @Override
784     public long longValue() {
785         return (long) numerator / denominator;
786     }
787 
788     /**
789      * Multiplies the value of this fraction by another, returning the
790      * result in reduced form.
791      *
792      * @param fraction  The fraction to multiply by, must not be {@code null}
793      * @return A {@link Fraction} instance with the resulting values
794      * @throws NullPointerException Thrown if the fraction is {@code null}.
795      * @throws ArithmeticException Thrown if the resulting numerator or denominator exceeds {@code Integer.MAX_VALUE}.
796      */
797     public Fraction multiplyBy(final Fraction fraction) {
798         Objects.requireNonNull(fraction, "fraction");
799         if (numerator == 0 || fraction.numerator == 0) {
800             return ZERO;
801         }
802         // knuth 4.5.1
803         // make sure we don't overflow unless the result *must* overflow.
804         // Reduce both operands first: the cross-gcd below cancels the cross terms only, so a
805         // factor shared inside an unreduced operand survives into the product and can overflow
806         // an int even when the reduced result fits.
807         final int thisGcd = greatestCommonDivisor(numerator, denominator);
808         final int thatGcd = greatestCommonDivisor(fraction.numerator, fraction.denominator);
809         final int thisNumerator = numerator / thisGcd;
810         final int thisDenominator = denominator / thisGcd;
811         final int thatNumerator = fraction.numerator / thatGcd;
812         final int thatDenominator = fraction.denominator / thatGcd;
813         final int d1 = greatestCommonDivisor(thisNumerator, thatDenominator);
814         final int d2 = greatestCommonDivisor(thatNumerator, thisDenominator);
815         return getReducedFraction(mulAndCheck(thisNumerator / d1, thatNumerator / d2), mulPosAndCheck(thisDenominator / d2, thatDenominator / d1));
816     }
817 
818     /**
819      * Gets a fraction that is the negative (-fraction) of this one.
820      * <p>
821      * The returned fraction is not reduced.
822      * </p>
823      *
824      * @return A new fraction instance with the opposite signed numerator
825      */
826     public Fraction negate() {
827         // the positive range is one smaller than the negative range of an int.
828         if (numerator == Integer.MIN_VALUE) {
829             throw new ArithmeticException("overflow: too large to negate");
830         }
831         return new Fraction(-numerator, denominator);
832     }
833 
834     /**
835      * Gets a fraction that is raised to the passed in power.
836      * <p>
837      * The returned fraction is in reduced form.
838      * </p>
839      *
840      * @param power The power to raise the fraction to
841      * @return {@code this} if the power is one, {@link #ONE} if the power is zero (even if the fraction equals ZERO) or a new fraction instance raised to the
842      *         appropriate power
843      * @throws ArithmeticException Thrown if the resulting numerator or denominator exceeds {@code Integer.MAX_VALUE}.
844      */
845     public Fraction pow(final int power) {
846         if (power == 1) {
847             return this;
848         }
849         if (power == 0) {
850             return ONE;
851         }
852         if (power < 0) {
853             if (power == Integer.MIN_VALUE) { // MIN_VALUE can't be negated.
854                 return invert().pow(2).pow(-(power / 2));
855             }
856             return invert().pow(-power);
857         }
858         final Fraction f = multiplyBy(this);
859         if (power % 2 == 0) { // if even...
860             return f.pow(power / 2);
861         }
862         return f.pow(power / 2).multiplyBy(this);
863     }
864 
865     /**
866      * Validates the cached hashCode after deserialization. Throws a {@link InvalidObjectException} when the stored hashCode does not match the canonical hash
867      * of the deserialized numerator/denominator.
868      *
869      * @param in See {@link Serializable}.
870      * @throws IOException Thrown as described in {@link Serializable}.
871      * @throws ClassNotFoundException Thrown as described in {@link Serializable}.
872      * @throws InvalidObjectException Thrown if the hashCode doesn't match the denominator and numerator.
873      */
874     private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
875         in.defaultReadObject();
876         checkDenominator(denominator);
877         if (hashCode != hash(denominator, numerator)) {
878             throw new InvalidObjectException("Fraction hashCode does not match numerator/denominator.");
879         }
880     }
881 
882     /**
883      * Reduce the fraction to the smallest values for the numerator and denominator, returning the result.
884      * <p>
885      * For example, if this fraction represents 2/4, then the result will be 1/2.
886      * </p>
887      *
888      * @return A new reduced fraction instance, or this if no simplification possible
889      */
890     public Fraction reduce() {
891         if (numerator == 0) {
892             return equals(ZERO) ? this : ZERO;
893         }
894         final int gcd = greatestCommonDivisor(Math.abs(numerator), denominator);
895         if (gcd == 1) {
896             return this;
897         }
898         return getFraction(numerator / gcd, denominator / gcd);
899     }
900 
901     /**
902      * Subtracts the value of another fraction from the value of this one,
903      * returning the result in reduced form.
904      *
905      * @param fraction  The fraction to subtract, must not be {@code null}
906      * @return A {@link Fraction} instance with the resulting values
907      * @throws NullPointerException Thrown if the fraction is {@code null}.
908      * @throws ArithmeticException Thrown if the resulting numerator or denominator
909      *   cannot be represented in an {@code int}.
910      */
911     public Fraction subtract(final Fraction fraction) {
912         return addSub(fraction, false /* subtract */);
913     }
914 
915     /**
916      * Gets the fraction as a proper {@link String} in the format X Y/Z.
917      * <p>
918      * The format used in '<em>wholeNumber</em> <em>numerator</em>/<em>denominator</em>'. If the whole number is zero it will be omitted. If the numerator is
919      * zero, only the whole number is returned.
920      * </p>
921      *
922      * @return A {@link String} form of the fraction
923      */
924     public String toProperString() {
925         if (toProperString == null) {
926             if (numerator == 0) {
927                 toProperString = "0";
928             } else if (numerator == denominator) {
929                 toProperString = "1";
930             } else if (numerator == -1 * denominator) {
931                 toProperString = "-1";
932             } else if ((numerator > 0 ? -numerator : numerator) < -denominator) {
933                 // note that we do the magnitude comparison test above with
934                 // NEGATIVE (not positive) numbers, since negative numbers
935                 // have a larger range. otherwise numerator == Integer.MIN_VALUE
936                 // is handled incorrectly.
937                 final int properNumerator = getProperNumerator();
938                 if (properNumerator == 0) {
939                     toProperString = Integer.toString(getProperWhole());
940                 } else {
941                     toProperString = getProperWhole() + " " + properNumerator + "/" + getDenominator();
942                 }
943             } else {
944                 toProperString = getNumerator() + "/" + getDenominator();
945             }
946         }
947         return toProperString;
948     }
949 
950     /**
951      * Gets the fraction as a {@link String}.
952      * <p>
953      * The format used is '<em>numerator</em>/<em>denominator</em>' always.
954      * </p>
955      *
956      * @return A {@link String} form of the fraction
957      */
958     @Override
959     public String toString() {
960         if (toString == null) {
961             toString = getNumerator() + "/" + getDenominator();
962         }
963         return toString;
964     }
965 }