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  
18  /*
19   * This is not the original file distributed by the Apache Software Foundation
20   * It has been modified by the Hipparchus project
21   */
22  package org.hipparchus.fraction;
23  
24  import java.io.Serializable;
25  import java.math.BigInteger;
26  import java.util.function.Function;
27  import java.util.function.Predicate;
28  import java.util.stream.Stream;
29  
30  import org.hipparchus.FieldElement;
31  import org.hipparchus.exception.LocalizedCoreFormats;
32  import org.hipparchus.exception.MathIllegalStateException;
33  import org.hipparchus.exception.MathRuntimeException;
34  import org.hipparchus.fraction.ConvergentsIterator.ConvergenceStep;
35  import org.hipparchus.util.ArithmeticUtils;
36  import org.hipparchus.util.FastMath;
37  import org.hipparchus.util.MathUtils;
38  import org.hipparchus.util.Pair;
39  import org.hipparchus.util.Precision;
40  
41  /**
42   * Representation of a rational number.
43   */
44  public class Fraction
45      extends Number
46      implements FieldElement<Fraction>, Comparable<Fraction>, Serializable {
47  
48      /** A fraction representing "2 / 1". */
49      public static final Fraction TWO = new Fraction(2, 1);
50  
51      /** A fraction representing "1". */
52      public static final Fraction ONE = new Fraction(1, 1);
53  
54      /** A fraction representing "0". */
55      public static final Fraction ZERO = new Fraction(0, 1);
56  
57      /** A fraction representing "4/5". */
58      public static final Fraction FOUR_FIFTHS = new Fraction(4, 5);
59  
60      /** A fraction representing "1/5". */
61      public static final Fraction ONE_FIFTH = new Fraction(1, 5);
62  
63      /** A fraction representing "1/2". */
64      public static final Fraction ONE_HALF = new Fraction(1, 2);
65  
66      /** A fraction representing "1/4". */
67      public static final Fraction ONE_QUARTER = new Fraction(1, 4);
68  
69      /** A fraction representing "1/3". */
70      public static final Fraction ONE_THIRD = new Fraction(1, 3);
71  
72      /** A fraction representing "3/5". */
73      public static final Fraction THREE_FIFTHS = new Fraction(3, 5);
74  
75      /** A fraction representing "3/4". */
76      public static final Fraction THREE_QUARTERS = new Fraction(3, 4);
77  
78      /** A fraction representing "2/5". */
79      public static final Fraction TWO_FIFTHS = new Fraction(2, 5);
80  
81      /** A fraction representing "2/4". */
82      public static final Fraction TWO_QUARTERS = new Fraction(2, 4);
83  
84      /** A fraction representing "2/3". */
85      public static final Fraction TWO_THIRDS = new Fraction(2, 3);
86  
87      /** A fraction representing "-1 / 1". */
88      public static final Fraction MINUS_ONE = new Fraction(-1, 1);
89  
90      /** Serializable version identifier */
91      private static final long serialVersionUID = 3698073679419233275L;
92  
93      /** The default epsilon used for convergence. */
94      private static final double DEFAULT_EPSILON = 1e-5;
95  
96      /** Convert a convergence step to the corresponding double fraction. */
97      private static final Function<ConvergenceStep, Fraction> STEP_TO_FRACTION = //
98                      s -> new Fraction((int) s.getNumerator(), (int) s.getDenominator());
99  
100     /** The denominator. */
101     private final int denominator;
102 
103     /** The numerator. */
104     private final int numerator;
105 
106     /**
107      * Create a fraction given the double value.
108      * @param value the double value to convert to a fraction.
109      * @throws MathIllegalStateException if the continued fraction failed to
110      *         converge.
111      */
112     public Fraction(double value) throws MathIllegalStateException {
113         this(value, DEFAULT_EPSILON, 100);
114     }
115 
116     /**
117      * Create a fraction given the double value and maximum error allowed.
118      * <p>
119      * References:
120      * <ul>
121      * <li><a href="http://mathworld.wolfram.com/ContinuedFraction.html">
122      * Continued Fraction</a> equations (11) and (22)-(26)</li>
123      * </ul>
124      *
125      * @param value the double value to convert to a fraction.
126      * @param epsilon maximum error allowed.  The resulting fraction is within
127      *        {@code epsilon} of {@code value}, in absolute terms.
128      * @param maxIterations maximum number of convergents
129      * @throws MathIllegalStateException if the continued fraction failed to
130      *         converge.
131      */
132     public Fraction(double value, double epsilon, int maxIterations)
133         throws MathIllegalStateException {
134         ConvergenceStep converged = convergent(value, maxIterations, s -> {
135             double quotient = s.getFractionValue();
136             return Precision.equals(quotient, value, 1) || FastMath.abs(quotient - value) < epsilon;
137         }).getKey();
138         if (FastMath.abs(converged.getFractionValue() - value) < epsilon) {
139             this.numerator   = (int) converged.getNumerator();
140             this.denominator = (int) converged.getDenominator();
141         } else {
142             throw new MathIllegalStateException(LocalizedCoreFormats.FAILED_FRACTION_CONVERSION,
143                                                 value, maxIterations);
144         }
145     }
146 
147     /**
148      * Create a fraction given the double value and maximum denominator.
149      * <p>
150      * References:
151      * <ul>
152      * <li><a href="http://mathworld.wolfram.com/ContinuedFraction.html">
153      * Continued Fraction</a> equations (11) and (22)-(26)</li>
154      * </ul>
155      *
156      * @param value the double value to convert to a fraction.
157      * @param maxDenominator The maximum allowed value for denominator
158      * @throws MathIllegalStateException if the continued fraction failed to
159      *         converge
160      */
161     public Fraction(double value, int maxDenominator)
162         throws MathIllegalStateException {
163         final int maxIterations = 100;
164         ConvergenceStep[] lastValid = new ConvergenceStep[1];
165         try {
166             convergent(value, maxIterations, s -> {
167                 if (s.getDenominator() < maxDenominator) {
168                     lastValid[0] = s;
169                 }
170                 return Precision.equals(s.getFractionValue(), value, 1);
171             });
172         } catch (MathIllegalStateException e) { // NOPMD - ignore overflows and just take the last valid result
173         }
174         if (lastValid[0] != null) {
175             this.numerator   = (int) lastValid[0].getNumerator();
176             this.denominator = (int) lastValid[0].getDenominator();
177         } else {
178             throw new MathIllegalStateException(LocalizedCoreFormats.FAILED_FRACTION_CONVERSION,
179                                                 value, maxIterations);
180         }
181     }
182 
183     /**
184      * Create a fraction from an int.
185      * The fraction is num / 1.
186      * @param num the numerator.
187      */
188     public Fraction(int num) {
189         this(num, 1);
190     }
191 
192     /**
193      * Create a fraction given the numerator and denominator.  The fraction is
194      * reduced to lowest terms.
195      * @param num the numerator.
196      * @param den the denominator.
197      * @throws MathRuntimeException if the denominator is {@code zero}
198      */
199     public Fraction(int num, int den) {
200         if (den == 0) {
201             throw new MathRuntimeException(LocalizedCoreFormats.ZERO_DENOMINATOR_IN_FRACTION,
202                                            num, den);
203         }
204         if (den < 0) {
205             if (num == Integer.MIN_VALUE ||
206                 den == Integer.MIN_VALUE) {
207                 throw new MathRuntimeException(LocalizedCoreFormats.OVERFLOW_IN_FRACTION,
208                                                num, den);
209             }
210             num = -num;
211             den = -den;
212         }
213         // reduce numerator and denominator by greatest common denominator.
214         final int d = ArithmeticUtils.gcd(num, den);
215         if (d > 1) {
216             num /= d;
217             den /= d;
218         }
219 
220         // move sign to numerator.
221         if (den < 0) {
222             num = -num;
223             den = -den;
224         }
225         this.numerator   = num;
226         this.denominator = den;
227     }
228 
229     /**
230      * A test to determine if a series of fractions has converged.
231      */
232     @FunctionalInterface
233     public interface ConvergenceTest {
234         /**
235          * Evaluates if the fraction formed by {@code numerator/denominator} satisfies
236          * this convergence test.
237          *
238          * @param numerator   the numerator
239          * @param denominator the denominator
240          * @return if this convergence test is satisfied
241          */
242         boolean test(int numerator, int denominator); // NOPMD - this is not a Junit test, PMD false positive here
243     }
244 
245     /** Generate a {@link Stream stream} of convergents from a real number.
246      * @param value value to approximate
247      * @param maxConvergents maximum number of convergents.
248      * @return stream of {@link Fraction} convergents approximating  {@code value}
249      * @since 2.1
250      */
251     public static Stream<Fraction> convergents(final double value, final int maxConvergents) {
252         if (FastMath.abs(value) > Integer.MAX_VALUE) {
253             throw new MathIllegalStateException(LocalizedCoreFormats.FRACTION_CONVERSION_OVERFLOW, value, value, 1l);
254         }
255         return ConvergentsIterator.convergents(value, maxConvergents).map(STEP_TO_FRACTION);
256     }
257 
258     /**
259      * Returns the last element of the series of convergent-steps to approximate the
260      * given value.
261      * <p>
262      * The series terminates either at the first step that satisfies the given
263      * {@code convergenceTest} or after at most {@code maxConvergents} elements. The
264      * returned Pair consists of that terminal {@link Fraction} and a
265      * {@link Boolean} that indicates if it satisfies the given convergence tests.
266      * If the returned pair's value is {@code false} the element at position
267      * {@code maxConvergents} was examined but failed to satisfy the
268      * {@code convergenceTest}. A caller can then decide to accept the result
269      * nevertheless or to discard it. This method is usually faster than
270      * {@link #convergents(double, int)} if only the terminal element is of
271      * interest.
272      *
273      * @param value           value to approximate
274      * @param maxConvergents  maximum number of convergents to examine
275      * @param convergenceTest the test if the series has converged at a step
276      * @return the pair of last element of the series of convergents and a boolean
277      *         indicating if that element satisfies the specified convergent test
278      */
279     public static Pair<Fraction, Boolean> convergent(double value, int maxConvergents, ConvergenceTest convergenceTest) {
280         Pair<ConvergenceStep, Boolean> converged = convergent(value, maxConvergents, s -> {
281             assertNoIntegerOverflow(s, value);
282             return convergenceTest.test((int) s.getNumerator(), (int) s.getDenominator());
283         });
284         return Pair.create(STEP_TO_FRACTION.apply(converged.getKey()), converged.getValue());
285     }
286 
287     /** Create a convergent-steps to approximate the given value.
288      * @param value           value to approximate
289      * @param maxConvergents  maximum number of convergents to examine
290      * @param convergenceTests the test if the series has converged at a step
291      * @return the pair of last element of the series of convergents and a boolean
292      *         indicating if that element satisfies the specified convergent test
293      */
294     private static Pair<ConvergenceStep, Boolean> convergent(double value, int maxConvergents,
295                                                              Predicate<ConvergenceStep> convergenceTests) {
296         if (FastMath.abs(value) > Integer.MAX_VALUE) {
297             throw new MathIllegalStateException(LocalizedCoreFormats.FRACTION_CONVERSION_OVERFLOW, value, value, 1l);
298         }
299         return ConvergentsIterator.convergent(value, maxConvergents, s -> {
300             assertNoIntegerOverflow(s, value);
301             return convergenceTests.test(s);
302         });
303     }
304 
305     /** Check no overflow occurred.
306      * @param s convergent
307      * @param value corresponding value
308      */
309     private static void assertNoIntegerOverflow(ConvergenceStep s, double value) {
310         if (s.getNumerator() > Integer.MAX_VALUE || s.getDenominator() > Integer.MAX_VALUE) {
311             throw new MathIllegalStateException(LocalizedCoreFormats.FRACTION_CONVERSION_OVERFLOW, value,
312                     s.getNumerator(), s.getDenominator());
313         }
314     }
315 
316     /** {@inheritDoc} */
317     @Override
318     public double getReal() {
319         return doubleValue();
320     }
321 
322     /** Check if a fraction is an integer.
323      * @return true of fraction is an integer
324      */
325     public boolean isInteger() {
326         return denominator == 1;
327     }
328 
329     /** Returns the signum function of this fraction.
330      * <p>
331      * The return value is -1 if the specified value is negative;
332      * 0 if the specified value is zero; and 1 if the specified value is positive.
333      * </p>
334      * @return the signum function of this fraction
335      * @since 1.7
336      */
337     public int signum() {
338         return Integer.signum(numerator);
339     }
340 
341     /**
342      * Returns the absolute value of this fraction.
343      * @return the absolute value.
344      */
345     public Fraction abs() {
346         Fraction ret;
347         if (numerator >= 0) {
348             ret = this;
349         } else {
350             ret = negate();
351         }
352         return ret;
353     }
354 
355     /**
356      * Compares this object to another based on size.
357      * @param object the object to compare to
358      * @return -1 if this is less than {@code object}, +1 if this is greater
359      *         than {@code object}, 0 if they are equal.
360      */
361     @Override
362     public int compareTo(Fraction object) {
363         long nOd = ((long) numerator) * object.denominator;
364         long dOn = ((long) denominator) * object.numerator;
365         return Long.compare(nOd, dOn);
366     }
367 
368     /**
369      * Gets the fraction as a {@code double}. This calculates the fraction as
370      * the numerator divided by denominator.
371      * @return the fraction as a {@code double}
372      */
373     @Override
374     public double doubleValue() {
375         return (double)numerator / (double)denominator;
376     }
377 
378     /**
379      * Test for the equality of two fractions.  If the lowest term
380      * numerator and denominators are the same for both fractions, the two
381      * fractions are considered to be equal.
382      * @param other fraction to test for equality to this fraction
383      * @return true if two fractions are equal, false if object is
384      *         {@code null}, not an instance of {@link Fraction}, or not equal
385      *         to this fraction instance.
386      */
387     @Override
388     public boolean equals(Object other) {
389         if (this == other) {
390             return true;
391         }
392         if (other instanceof Fraction) {
393             // since fractions are always in lowest terms, numerators and
394             // denominators can be compared directly for equality.
395             Fraction rhs = (Fraction)other;
396             return (numerator == rhs.numerator) &&
397                 (denominator == rhs.denominator);
398         }
399         return false;
400     }
401 
402     /**
403      * Gets the fraction as a {@code float}. This calculates the fraction as
404      * the numerator divided by denominator.
405      * @return the fraction as a {@code float}
406      */
407     @Override
408     public float floatValue() {
409         return (float)doubleValue();
410     }
411 
412     /**
413      * Rational number greatest common divisor.
414      *
415      * @param s fraction.
416      * @return gcd(this, s).
417      * @since 3.1
418      */
419     public Fraction gcd(Fraction s) {
420       if (s.isZero()) {
421         return this;
422       }
423       if (this.isZero()) {
424         return s;
425       }
426       int p = ArithmeticUtils.gcd(numerator, s.numerator);
427       int q = ArithmeticUtils.lcm(denominator, s.denominator);
428       return new Fraction(p, q);
429     }
430 
431     /**
432      * Rational number least common multiple.
433      *
434      * @param s fraction.
435      * @return lcm(this, s).
436      * @since 3.1
437      */
438     public Fraction lcm(Fraction s) {
439       if (s.isZero()) {
440         return ZERO;
441       }
442       if (this.isZero()) {
443         return ZERO;
444       }
445       return new Fraction(ArithmeticUtils.lcm(numerator, s.numerator),
446                           ArithmeticUtils.gcd(denominator, s.denominator));
447     }
448 
449     /**
450      * Access the denominator.
451      * @return the denominator.
452      */
453     public int getDenominator() {
454         return denominator;
455     }
456 
457     /**
458      * Access the numerator.
459      * @return the numerator.
460      */
461     public int getNumerator() {
462         return numerator;
463     }
464 
465     /**
466      * Gets a hashCode for the fraction.
467      * @return a hash code value for this object
468      */
469     @Override
470     public int hashCode() {
471         return 37 * (37 * 17 + numerator) + denominator;
472     }
473 
474     /**
475      * Gets the fraction as an {@code int}. This returns the whole number part
476      * of the fraction.
477      * @return the whole number fraction part
478      */
479     @Override
480     public int intValue() {
481         return (int)doubleValue();
482     }
483 
484     /**
485      * Gets the fraction as a {@code long}. This returns the whole number part
486      * of the fraction.
487      * @return the whole number fraction part
488      */
489     @Override
490     public long longValue() {
491         return (long)doubleValue();
492     }
493 
494     /**
495      * Return the additive inverse of this fraction.
496      * @return the negation of this fraction.
497      */
498     @Override
499     public Fraction negate() {
500         if (numerator==Integer.MIN_VALUE) {
501             throw new MathRuntimeException(LocalizedCoreFormats.OVERFLOW_IN_FRACTION, numerator, denominator);
502         }
503         return new Fraction(-numerator, denominator);
504     }
505 
506     /**
507      * Return the multiplicative inverse of this fraction.
508      * @return the reciprocal fraction
509      */
510     @Override
511     public Fraction reciprocal() {
512         return new Fraction(denominator, numerator);
513     }
514 
515     /**
516      * Adds the value of this fraction to another, returning the result in reduced form.
517      * The algorithm follows Knuth, 4.5.1.
518      *
519      * @param fraction  the fraction to add, must not be {@code null}
520      * @return a {@code Fraction} instance with the resulting values
521      * @throws org.hipparchus.exception.NullArgumentException if the fraction is {@code null}
522      * @throws MathRuntimeException if the resulting numerator or denominator exceeds
523      *  {@code Integer.MAX_VALUE}
524      */
525     @Override
526     public Fraction add(Fraction fraction) {
527         return addSub(fraction, true /* add */);
528     }
529 
530     /**
531      * Add an integer to the fraction.
532      * @param i the {@code integer} to add.
533      * @return this + i
534      */
535     public Fraction add(final int i) {
536         return new Fraction(numerator + i * denominator, denominator);
537     }
538 
539     /**
540      * Subtracts the value of another fraction from the value of this one,
541      * returning the result in reduced form.
542      *
543      * @param fraction  the fraction to subtract, must not be {@code null}
544      * @return a {@code Fraction} instance with the resulting values
545      * @throws org.hipparchus.exception.NullArgumentException if the fraction is {@code null}
546      * @throws MathRuntimeException if the resulting numerator or denominator
547      *   cannot be represented in an {@code int}.
548      */
549     @Override
550     public Fraction subtract(Fraction fraction) {
551         return addSub(fraction, false /* subtract */);
552     }
553 
554     /**
555      * Subtract an integer from the fraction.
556      * @param i the {@code integer} to subtract.
557      * @return this - i
558      */
559     public Fraction subtract(final int i) {
560         return new Fraction(numerator - i * denominator, denominator);
561     }
562 
563     /**
564      * Implement add and subtract using algorithm described in Knuth 4.5.1.
565      *
566      * @param fraction the fraction to subtract, must not be {@code null}
567      * @param isAdd true to add, false to subtract
568      * @return a {@code Fraction} instance with the resulting values
569      * @throws org.hipparchus.exception.NullArgumentException if the fraction is {@code null}
570      * @throws MathRuntimeException if the resulting numerator or denominator
571      *   cannot be represented in an {@code int}.
572      */
573     private Fraction addSub(Fraction fraction, boolean isAdd) {
574         MathUtils.checkNotNull(fraction, LocalizedCoreFormats.FRACTION);
575 
576         // zero is identity for addition.
577         if (numerator == 0) {
578             return isAdd ? fraction : fraction.negate();
579         }
580         if (fraction.numerator == 0) {
581             return this;
582         }
583         // if denominators are randomly distributed, d1 will be 1 about 61%
584         // of the time.
585         int d1 = ArithmeticUtils.gcd(denominator, fraction.denominator);
586         if (d1==1) {
587             // result is ( (u*v' +/- u'v) / u'v')
588             int uvp = ArithmeticUtils.mulAndCheck(numerator, fraction.denominator);
589             int upv = ArithmeticUtils.mulAndCheck(fraction.numerator, denominator);
590             return new Fraction
591                 (isAdd ? ArithmeticUtils.addAndCheck(uvp, upv) :
592                  ArithmeticUtils.subAndCheck(uvp, upv),
593                  ArithmeticUtils.mulAndCheck(denominator, fraction.denominator));
594         }
595         // the quantity 't' requires 65 bits of precision; see knuth 4.5.1
596         // exercise 7.  we're going to use a BigInteger.
597         // t = u(v'/d1) +/- v(u'/d1)
598         BigInteger uvp = BigInteger.valueOf(numerator)
599                                    .multiply(BigInteger.valueOf(fraction.denominator / d1));
600         BigInteger upv = BigInteger.valueOf(fraction.numerator)
601                                    .multiply(BigInteger.valueOf(denominator / d1));
602         BigInteger t = isAdd ? uvp.add(upv) : uvp.subtract(upv);
603         // but d2 doesn't need extra precision because
604         // d2 = gcd(t,d1) = gcd(t mod d1, d1)
605         int tmodd1 = t.mod(BigInteger.valueOf(d1)).intValue();
606         int d2 = (tmodd1==0)?d1:ArithmeticUtils.gcd(tmodd1, d1);
607 
608         // result is (t/d2) / (u'/d1)(v'/d2)
609         BigInteger w = t.divide(BigInteger.valueOf(d2));
610         if (w.bitLength() > 31) {
611             throw new MathRuntimeException(LocalizedCoreFormats.NUMERATOR_OVERFLOW_AFTER_MULTIPLY,
612                                            w);
613         }
614         return new Fraction (w.intValue(),
615                 ArithmeticUtils.mulAndCheck(denominator/d1,
616                                             fraction.denominator/d2));
617     }
618 
619     /**
620      * Multiplies the value of this fraction by another, returning the
621      * result in reduced form.
622      *
623      * @param fraction  the fraction to multiply by, must not be {@code null}
624      * @return a {@code Fraction} instance with the resulting values
625      * @throws org.hipparchus.exception.NullArgumentException if the fraction is {@code null}
626      * @throws MathRuntimeException if the resulting numerator or denominator exceeds
627      *  {@code Integer.MAX_VALUE}
628      */
629     @Override
630     public Fraction multiply(Fraction fraction) {
631         MathUtils.checkNotNull(fraction, LocalizedCoreFormats.FRACTION);
632         if (numerator == 0 || fraction.numerator == 0) {
633             return ZERO;
634         }
635         // knuth 4.5.1
636         // make sure we don't overflow unless the result *must* overflow.
637         int d1 = ArithmeticUtils.gcd(numerator, fraction.denominator);
638         int d2 = ArithmeticUtils.gcd(fraction.numerator, denominator);
639         return getReducedFraction
640                 (ArithmeticUtils.mulAndCheck(numerator/d1, fraction.numerator/d2),
641                  ArithmeticUtils.mulAndCheck(denominator/d2, fraction.denominator/d1));
642     }
643 
644     /**
645      * Multiply the fraction by an integer.
646      * @param i the {@code integer} to multiply by.
647      * @return this * i
648      */
649     @Override
650     public Fraction multiply(final int i) {
651         return multiply(new Fraction(i));
652     }
653 
654     /**
655      * Divide the value of this fraction by another.
656      *
657      * @param fraction  the fraction to divide by, must not be {@code null}
658      * @return a {@code Fraction} instance with the resulting values
659      * @throws IllegalArgumentException if the fraction is {@code null}
660      * @throws MathRuntimeException if the fraction to divide by is zero
661      * @throws MathRuntimeException if the resulting numerator or denominator exceeds
662      *  {@code Integer.MAX_VALUE}
663      */
664     @Override
665     public Fraction divide(Fraction fraction) {
666         MathUtils.checkNotNull(fraction, LocalizedCoreFormats.FRACTION);
667         if (fraction.numerator == 0) {
668             throw new MathRuntimeException(LocalizedCoreFormats.ZERO_FRACTION_TO_DIVIDE_BY,
669                                            fraction.numerator, fraction.denominator);
670         }
671         return multiply(fraction.reciprocal());
672     }
673 
674     /**
675      * Divide the fraction by an integer.
676      * @param i the {@code integer} to divide by.
677      * @return this * i
678      */
679     public Fraction divide(final int i) {
680         return divide(new Fraction(i));
681     }
682 
683     /**
684      * Gets the fraction percentage as a {@code double}. This calculates the
685      * fraction as the numerator divided by denominator multiplied by 100.
686      *
687      * @return the fraction percentage as a {@code double}.
688      */
689     public double percentageValue() {
690         return 100 * doubleValue();
691     }
692 
693     /**
694      * Creates a {@code Fraction} instance with the 2 parts
695      * of a fraction Y/Z.
696      * <p>
697      * Any negative signs are resolved to be on the numerator.
698      *
699      * @param numerator  the numerator, for example the three in 'three sevenths'
700      * @param denominator  the denominator, for example the seven in 'three sevenths'
701      * @return a new fraction instance, with the numerator and denominator reduced
702      * @throws MathRuntimeException if the denominator is {@code zero}
703      */
704     public static Fraction getReducedFraction(int numerator, int denominator) {
705         if (denominator == 0) {
706             throw new MathRuntimeException(LocalizedCoreFormats.ZERO_DENOMINATOR_IN_FRACTION,
707                                            numerator, denominator);
708         }
709         if (numerator==0) {
710             return ZERO; // normalize zero.
711         }
712         // allow 2^k/-2^31 as a valid fraction (where k>0)
713         if (denominator==Integer.MIN_VALUE && (numerator&1)==0) {
714             numerator/=2; denominator/=2;
715         }
716         if (denominator < 0) {
717             if (numerator==Integer.MIN_VALUE ||
718                 denominator==Integer.MIN_VALUE) {
719                 throw new MathRuntimeException(LocalizedCoreFormats.OVERFLOW_IN_FRACTION,
720                                                numerator, denominator);
721             }
722             numerator = -numerator;
723             denominator = -denominator;
724         }
725         // simplify fraction.
726         int gcd = ArithmeticUtils.gcd(numerator, denominator);
727         numerator /= gcd;
728         denominator /= gcd;
729         return new Fraction(numerator, denominator);
730     }
731 
732     /**
733      * Returns the {@code String} representing this fraction, ie
734      * "num / dem" or just "num" if the denominator is one.
735      *
736      * @return a string representation of the fraction.
737      * @see java.lang.Object#toString()
738      */
739     @Override
740     public String toString() {
741         if (denominator == 1) {
742             return Integer.toString(numerator);
743         } else if (numerator == 0) {
744             return "0";
745         } else {
746             return numerator + " / " + denominator;
747         }
748     }
749 
750     /** {@inheritDoc} */
751     @Override
752     public FractionField getField() {
753         return FractionField.getInstance();
754     }
755 
756 }