Fraction.java

  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.  * This is not the original file distributed by the Apache Software Foundation
  19.  * It has been modified by the Hipparchus project
  20.  */
  21. package org.hipparchus.fraction;

  22. import java.io.Serializable;
  23. import java.math.BigInteger;
  24. import java.util.function.Function;
  25. import java.util.function.Predicate;
  26. import java.util.stream.Stream;

  27. import org.hipparchus.FieldElement;
  28. import org.hipparchus.exception.LocalizedCoreFormats;
  29. import org.hipparchus.exception.MathIllegalStateException;
  30. import org.hipparchus.exception.MathRuntimeException;
  31. import org.hipparchus.fraction.ConvergentsIterator.ConvergenceStep;
  32. import org.hipparchus.util.ArithmeticUtils;
  33. import org.hipparchus.util.FastMath;
  34. import org.hipparchus.util.MathUtils;
  35. import org.hipparchus.util.Pair;
  36. import org.hipparchus.util.Precision;

  37. /**
  38.  * Representation of a rational number.
  39.  */
  40. public class Fraction
  41.     extends Number
  42.     implements FieldElement<Fraction>, Comparable<Fraction>, Serializable {

  43.     /** A fraction representing "2 / 1". */
  44.     public static final Fraction TWO = new Fraction(2, 1);

  45.     /** A fraction representing "1". */
  46.     public static final Fraction ONE = new Fraction(1, 1);

  47.     /** A fraction representing "0". */
  48.     public static final Fraction ZERO = new Fraction(0, 1);

  49.     /** A fraction representing "4/5". */
  50.     public static final Fraction FOUR_FIFTHS = new Fraction(4, 5);

  51.     /** A fraction representing "1/5". */
  52.     public static final Fraction ONE_FIFTH = new Fraction(1, 5);

  53.     /** A fraction representing "1/2". */
  54.     public static final Fraction ONE_HALF = new Fraction(1, 2);

  55.     /** A fraction representing "1/4". */
  56.     public static final Fraction ONE_QUARTER = new Fraction(1, 4);

  57.     /** A fraction representing "1/3". */
  58.     public static final Fraction ONE_THIRD = new Fraction(1, 3);

  59.     /** A fraction representing "3/5". */
  60.     public static final Fraction THREE_FIFTHS = new Fraction(3, 5);

  61.     /** A fraction representing "3/4". */
  62.     public static final Fraction THREE_QUARTERS = new Fraction(3, 4);

  63.     /** A fraction representing "2/5". */
  64.     public static final Fraction TWO_FIFTHS = new Fraction(2, 5);

  65.     /** A fraction representing "2/4". */
  66.     public static final Fraction TWO_QUARTERS = new Fraction(2, 4);

  67.     /** A fraction representing "2/3". */
  68.     public static final Fraction TWO_THIRDS = new Fraction(2, 3);

  69.     /** A fraction representing "-1 / 1". */
  70.     public static final Fraction MINUS_ONE = new Fraction(-1, 1);

  71.     /** Serializable version identifier */
  72.     private static final long serialVersionUID = 3698073679419233275L;

  73.     /** The default epsilon used for convergence. */
  74.     private static final double DEFAULT_EPSILON = 1e-5;

  75.     /** Convert a convergence step to the corresponding double fraction. */
  76.     private static final Function<ConvergenceStep, Fraction> STEP_TO_FRACTION = //
  77.                     s -> new Fraction((int) s.getNumerator(), (int) s.getDenominator());

  78.     /** The denominator. */
  79.     private final int denominator;

  80.     /** The numerator. */
  81.     private final int numerator;

  82.     /**
  83.      * Create a fraction given the double value.
  84.      * @param value the double value to convert to a fraction.
  85.      * @throws MathIllegalStateException if the continued fraction failed to
  86.      *         converge.
  87.      */
  88.     public Fraction(double value) throws MathIllegalStateException {
  89.         this(value, DEFAULT_EPSILON, 100);
  90.     }

  91.     /**
  92.      * Create a fraction given the double value and maximum error allowed.
  93.      * <p>
  94.      * References:
  95.      * <ul>
  96.      * <li><a href="http://mathworld.wolfram.com/ContinuedFraction.html">
  97.      * Continued Fraction</a> equations (11) and (22)-(26)</li>
  98.      * </ul>
  99.      *
  100.      * @param value the double value to convert to a fraction.
  101.      * @param epsilon maximum error allowed.  The resulting fraction is within
  102.      *        {@code epsilon} of {@code value}, in absolute terms.
  103.      * @param maxIterations maximum number of convergents
  104.      * @throws MathIllegalStateException if the continued fraction failed to
  105.      *         converge.
  106.      */
  107.     public Fraction(double value, double epsilon, int maxIterations)
  108.         throws MathIllegalStateException {
  109.         ConvergenceStep converged = convergent(value, maxIterations, s -> {
  110.             double quotient = s.getFractionValue();
  111.             return Precision.equals(quotient, value, 1) || FastMath.abs(quotient - value) < epsilon;
  112.         }).getKey();
  113.         if (FastMath.abs(converged.getFractionValue() - value) < epsilon) {
  114.             this.numerator   = (int) converged.getNumerator();
  115.             this.denominator = (int) converged.getDenominator();
  116.         } else {
  117.             throw new MathIllegalStateException(LocalizedCoreFormats.FAILED_FRACTION_CONVERSION,
  118.                                                 value, maxIterations);
  119.         }
  120.     }

  121.     /**
  122.      * Create a fraction given the double value and maximum denominator.
  123.      * <p>
  124.      * References:
  125.      * <ul>
  126.      * <li><a href="http://mathworld.wolfram.com/ContinuedFraction.html">
  127.      * Continued Fraction</a> equations (11) and (22)-(26)</li>
  128.      * </ul>
  129.      *
  130.      * @param value the double value to convert to a fraction.
  131.      * @param maxDenominator The maximum allowed value for denominator
  132.      * @throws MathIllegalStateException if the continued fraction failed to
  133.      *         converge
  134.      */
  135.     public Fraction(double value, int maxDenominator)
  136.         throws MathIllegalStateException {
  137.         final int maxIterations = 100;
  138.         ConvergenceStep[] lastValid = new ConvergenceStep[1];
  139.         try {
  140.             convergent(value, maxIterations, s -> {
  141.                 if (s.getDenominator() < maxDenominator) {
  142.                     lastValid[0] = s;
  143.                 }
  144.                 return Precision.equals(s.getFractionValue(), value, 1);
  145.             });
  146.         } catch (MathIllegalStateException e) { // NOPMD - ignore overflows and just take the last valid result
  147.         }
  148.         if (lastValid[0] != null) {
  149.             this.numerator   = (int) lastValid[0].getNumerator();
  150.             this.denominator = (int) lastValid[0].getDenominator();
  151.         } else {
  152.             throw new MathIllegalStateException(LocalizedCoreFormats.FAILED_FRACTION_CONVERSION,
  153.                                                 value, maxIterations);
  154.         }
  155.     }

  156.     /**
  157.      * Create a fraction from an int.
  158.      * The fraction is num / 1.
  159.      * @param num the numerator.
  160.      */
  161.     public Fraction(int num) {
  162.         this(num, 1);
  163.     }

  164.     /**
  165.      * Create a fraction given the numerator and denominator.  The fraction is
  166.      * reduced to lowest terms.
  167.      * @param num the numerator.
  168.      * @param den the denominator.
  169.      * @throws MathRuntimeException if the denominator is {@code zero}
  170.      */
  171.     public Fraction(int num, int den) {
  172.         if (den == 0) {
  173.             throw new MathRuntimeException(LocalizedCoreFormats.ZERO_DENOMINATOR_IN_FRACTION,
  174.                                            num, den);
  175.         }
  176.         if (den < 0) {
  177.             if (num == Integer.MIN_VALUE ||
  178.                 den == Integer.MIN_VALUE) {
  179.                 throw new MathRuntimeException(LocalizedCoreFormats.OVERFLOW_IN_FRACTION,
  180.                                                num, den);
  181.             }
  182.             num = -num;
  183.             den = -den;
  184.         }
  185.         // reduce numerator and denominator by greatest common denominator.
  186.         final int d = ArithmeticUtils.gcd(num, den);
  187.         if (d > 1) {
  188.             num /= d;
  189.             den /= d;
  190.         }

  191.         // move sign to numerator.
  192.         if (den < 0) {
  193.             num = -num;
  194.             den = -den;
  195.         }
  196.         this.numerator   = num;
  197.         this.denominator = den;
  198.     }

  199.     /**
  200.      * A test to determine if a series of fractions has converged.
  201.      */
  202.     @FunctionalInterface
  203.     public interface ConvergenceTest {
  204.         /**
  205.          * Evaluates if the fraction formed by {@code numerator/denominator} satisfies
  206.          * this convergence test.
  207.          *
  208.          * @param numerator   the numerator
  209.          * @param denominator the denominator
  210.          * @return if this convergence test is satisfied
  211.          */
  212.         boolean test(int numerator, int denominator); // NOPMD - this is not a Junit test, PMD false positive here
  213.     }

  214.     /** Generate a {@link Stream stream} of convergents from a real number.
  215.      * @param value value to approximate
  216.      * @param maxConvergents maximum number of convergents.
  217.      * @return stream of {@link Fraction} convergents approximating  {@code value}
  218.      * @since 2.1
  219.      */
  220.     public static Stream<Fraction> convergents(final double value, final int maxConvergents) {
  221.         if (FastMath.abs(value) > Integer.MAX_VALUE) {
  222.             throw new MathIllegalStateException(LocalizedCoreFormats.FRACTION_CONVERSION_OVERFLOW, value, value, 1l);
  223.         }
  224.         return ConvergentsIterator.convergents(value, maxConvergents).map(STEP_TO_FRACTION);
  225.     }

  226.     /**
  227.      * Returns the last element of the series of convergent-steps to approximate the
  228.      * given value.
  229.      * <p>
  230.      * The series terminates either at the first step that satisfies the given
  231.      * {@code convergenceTest} or after at most {@code maxConvergents} elements. The
  232.      * returned Pair consists of that terminal {@link Fraction} and a
  233.      * {@link Boolean} that indicates if it satisfies the given convergence tests.
  234.      * If the returned pair's value is {@code false} the element at position
  235.      * {@code maxConvergents} was examined but failed to satisfy the
  236.      * {@code convergenceTest}. A caller can then decide to accept the result
  237.      * nevertheless or to discard it. This method is usually faster than
  238.      * {@link #convergents(double, int)} if only the terminal element is of
  239.      * interest.
  240.      *
  241.      * @param value           value to approximate
  242.      * @param maxConvergents  maximum number of convergents to examine
  243.      * @param convergenceTest the test if the series has converged at a step
  244.      * @return the pair of last element of the series of convergents and a boolean
  245.      *         indicating if that element satisfies the specified convergent test
  246.      */
  247.     public static Pair<Fraction, Boolean> convergent(double value, int maxConvergents, ConvergenceTest convergenceTest) {
  248.         Pair<ConvergenceStep, Boolean> converged = convergent(value, maxConvergents, s -> {
  249.             customAssertNoIntegerOverflow(s, value);
  250.             return convergenceTest.test((int) s.getNumerator(), (int) s.getDenominator());
  251.         });
  252.         return Pair.create(STEP_TO_FRACTION.apply(converged.getKey()), converged.getValue());
  253.     }

  254.     /** Create a convergent-steps to approximate the given value.
  255.      * @param value           value to approximate
  256.      * @param maxConvergents  maximum number of convergents to examine
  257.      * @param convergenceTests the test if the series has converged at a step
  258.      * @return the pair of last element of the series of convergents and a boolean
  259.      *         indicating if that element satisfies the specified convergent test
  260.      */
  261.     private static Pair<ConvergenceStep, Boolean> convergent(double value, int maxConvergents,
  262.                                                              Predicate<ConvergenceStep> convergenceTests) {
  263.         if (FastMath.abs(value) > Integer.MAX_VALUE) {
  264.             throw new MathIllegalStateException(LocalizedCoreFormats.FRACTION_CONVERSION_OVERFLOW, value, value, 1l);
  265.         }
  266.         return ConvergentsIterator.convergent(value, maxConvergents, s -> {
  267.             customAssertNoIntegerOverflow(s, value);
  268.             return convergenceTests.test(s);
  269.         });
  270.     }

  271.     /** Check no overflow occurred.
  272.      * @param s convergent
  273.      * @param value corresponding value
  274.      */
  275.     private static void customAssertNoIntegerOverflow(ConvergenceStep s, double value) {
  276.         if (s.getNumerator() > Integer.MAX_VALUE || s.getDenominator() > Integer.MAX_VALUE) {
  277.             throw new MathIllegalStateException(LocalizedCoreFormats.FRACTION_CONVERSION_OVERFLOW, value,
  278.                     s.getNumerator(), s.getDenominator());
  279.         }
  280.     }

  281.     /** {@inheritDoc} */
  282.     @Override
  283.     public double getReal() {
  284.         return doubleValue();
  285.     }

  286.     /** Check if a fraction is an integer.
  287.      * @return true of fraction is an integer
  288.      */
  289.     public boolean isInteger() {
  290.         return denominator == 1;
  291.     }

  292.     /** Returns the signum function of this fraction.
  293.      * <p>
  294.      * The return value is -1 if the specified value is negative;
  295.      * 0 if the specified value is zero; and 1 if the specified value is positive.
  296.      * </p>
  297.      * @return the signum function of this fraction
  298.      * @since 1.7
  299.      */
  300.     public int signum() {
  301.         return Integer.signum(numerator);
  302.     }

  303.     /**
  304.      * Returns the absolute value of this fraction.
  305.      * @return the absolute value.
  306.      */
  307.     public Fraction abs() {
  308.         Fraction ret;
  309.         if (numerator >= 0) {
  310.             ret = this;
  311.         } else {
  312.             ret = negate();
  313.         }
  314.         return ret;
  315.     }

  316.     /**
  317.      * Compares this object to another based on size.
  318.      * @param object the object to compare to
  319.      * @return -1 if this is less than {@code object}, +1 if this is greater
  320.      *         than {@code object}, 0 if they are equal.
  321.      */
  322.     @Override
  323.     public int compareTo(Fraction object) {
  324.         long nOd = ((long) numerator) * object.denominator;
  325.         long dOn = ((long) denominator) * object.numerator;
  326.         return Long.compare(nOd, dOn);
  327.     }

  328.     /**
  329.      * Gets the fraction as a {@code double}. This calculates the fraction as
  330.      * the numerator divided by denominator.
  331.      * @return the fraction as a {@code double}
  332.      */
  333.     @Override
  334.     public double doubleValue() {
  335.         return ((double) numerator) / denominator;
  336.     }

  337.     /**
  338.      * Test for the equality of two fractions.  If the lowest term
  339.      * numerator and denominators are the same for both fractions, the two
  340.      * fractions are considered to be equal.
  341.      * @param other fraction to test for equality to this fraction
  342.      * @return true if two fractions are equal, false if object is
  343.      *         {@code null}, not an instance of {@link Fraction}, or not equal
  344.      *         to this fraction instance.
  345.      */
  346.     @Override
  347.     public boolean equals(Object other) {
  348.         if (this == other) {
  349.             return true;
  350.         }
  351.         if (other instanceof Fraction) {
  352.             // since fractions are always in lowest terms, numerators and
  353.             // denominators can be compared directly for equality.
  354.             Fraction rhs = (Fraction)other;
  355.             return (numerator == rhs.numerator) &&
  356.                 (denominator == rhs.denominator);
  357.         }
  358.         return false;
  359.     }

  360.     /**
  361.      * Gets the fraction as a {@code float}. This calculates the fraction as
  362.      * the numerator divided by denominator.
  363.      * @return the fraction as a {@code float}
  364.      */
  365.     @Override
  366.     public float floatValue() {
  367.         return (float)doubleValue();
  368.     }

  369.     /**
  370.      * Rational number greatest common divisor.
  371.      *
  372.      * @param s fraction.
  373.      * @return gcd(this, s).
  374.      * @since 3.1
  375.      */
  376.     public Fraction gcd(Fraction s) {
  377.       if (s.isZero()) {
  378.         return this;
  379.       }
  380.       if (this.isZero()) {
  381.         return s;
  382.       }
  383.       int p = ArithmeticUtils.gcd(numerator, s.numerator);
  384.       int q = ArithmeticUtils.lcm(denominator, s.denominator);
  385.       return new Fraction(p, q);
  386.     }

  387.     /**
  388.      * Rational number least common multiple.
  389.      *
  390.      * @param s fraction.
  391.      * @return lcm(this, s).
  392.      * @since 3.1
  393.      */
  394.     public Fraction lcm(Fraction s) {
  395.       if (s.isZero()) {
  396.         return ZERO;
  397.       }
  398.       if (this.isZero()) {
  399.         return ZERO;
  400.       }
  401.       return new Fraction(ArithmeticUtils.lcm(numerator, s.numerator),
  402.                           ArithmeticUtils.gcd(denominator, s.denominator));
  403.     }

  404.     /**
  405.      * Access the denominator.
  406.      * @return the denominator.
  407.      */
  408.     public int getDenominator() {
  409.         return denominator;
  410.     }

  411.     /**
  412.      * Access the numerator.
  413.      * @return the numerator.
  414.      */
  415.     public int getNumerator() {
  416.         return numerator;
  417.     }

  418.     /**
  419.      * Gets a hashCode for the fraction.
  420.      * @return a hash code value for this object
  421.      */
  422.     @Override
  423.     public int hashCode() {
  424.         return 37 * (37 * 17 + numerator) + denominator;
  425.     }

  426.     /**
  427.      * Gets the fraction as an {@code int}. This returns the whole number part
  428.      * of the fraction.
  429.      * @return the whole number fraction part
  430.      */
  431.     @Override
  432.     public int intValue() {
  433.         return (int)doubleValue();
  434.     }

  435.     /**
  436.      * Gets the fraction as a {@code long}. This returns the whole number part
  437.      * of the fraction.
  438.      * @return the whole number fraction part
  439.      */
  440.     @Override
  441.     public long longValue() {
  442.         return (long)doubleValue();
  443.     }

  444.     /**
  445.      * Return the additive inverse of this fraction.
  446.      * @return the negation of this fraction.
  447.      */
  448.     @Override
  449.     public Fraction negate() {
  450.         if (numerator==Integer.MIN_VALUE) {
  451.             throw new MathRuntimeException(LocalizedCoreFormats.OVERFLOW_IN_FRACTION, numerator, denominator);
  452.         }
  453.         return new Fraction(-numerator, denominator);
  454.     }

  455.     /**
  456.      * Return the multiplicative inverse of this fraction.
  457.      * @return the reciprocal fraction
  458.      */
  459.     @Override
  460.     public Fraction reciprocal() {
  461.         return new Fraction(denominator, numerator);
  462.     }

  463.     /**
  464.      * Adds the value of this fraction to another, returning the result in reduced form.
  465.      * The algorithm follows Knuth, 4.5.1.
  466.      *
  467.      * @param fraction  the fraction to add, must not be {@code null}
  468.      * @return a {@code Fraction} instance with the resulting values
  469.      * @throws org.hipparchus.exception.NullArgumentException if the fraction is {@code null}
  470.      * @throws MathRuntimeException if the resulting numerator or denominator exceeds
  471.      *  {@code Integer.MAX_VALUE}
  472.      */
  473.     @Override
  474.     public Fraction add(Fraction fraction) {
  475.         return addSub(fraction, true /* add */);
  476.     }

  477.     /**
  478.      * Add an integer to the fraction.
  479.      * @param i the {@code integer} to add.
  480.      * @return this + i
  481.      */
  482.     public Fraction add(final int i) {
  483.         return new Fraction(numerator + i * denominator, denominator);
  484.     }

  485.     /**
  486.      * Subtracts the value of another fraction from the value of this one,
  487.      * returning the result in reduced form.
  488.      *
  489.      * @param fraction  the fraction to subtract, must not be {@code null}
  490.      * @return a {@code Fraction} instance with the resulting values
  491.      * @throws org.hipparchus.exception.NullArgumentException if the fraction is {@code null}
  492.      * @throws MathRuntimeException if the resulting numerator or denominator
  493.      *   cannot be represented in an {@code int}.
  494.      */
  495.     @Override
  496.     public Fraction subtract(Fraction fraction) {
  497.         return addSub(fraction, false /* subtract */);
  498.     }

  499.     /**
  500.      * Subtract an integer from the fraction.
  501.      * @param i the {@code integer} to subtract.
  502.      * @return this - i
  503.      */
  504.     public Fraction subtract(final int i) {
  505.         return new Fraction(numerator - i * denominator, denominator);
  506.     }

  507.     /**
  508.      * Implement add and subtract using algorithm described in Knuth 4.5.1.
  509.      *
  510.      * @param fraction the fraction to subtract, must not be {@code null}
  511.      * @param isAdd true to add, false to subtract
  512.      * @return a {@code Fraction} instance with the resulting values
  513.      * @throws org.hipparchus.exception.NullArgumentException if the fraction is {@code null}
  514.      * @throws MathRuntimeException if the resulting numerator or denominator
  515.      *   cannot be represented in an {@code int}.
  516.      */
  517.     private Fraction addSub(Fraction fraction, boolean isAdd) {
  518.         MathUtils.checkNotNull(fraction, LocalizedCoreFormats.FRACTION);

  519.         // zero is identity for addition.
  520.         if (numerator == 0) {
  521.             return isAdd ? fraction : fraction.negate();
  522.         }
  523.         if (fraction.numerator == 0) {
  524.             return this;
  525.         }
  526.         // if denominators are randomly distributed, d1 will be 1 about 61%
  527.         // of the time.
  528.         int d1 = ArithmeticUtils.gcd(denominator, fraction.denominator);
  529.         if (d1==1) {
  530.             // result is ( (u*v' +/- u'v) / u'v')
  531.             int uvp = ArithmeticUtils.mulAndCheck(numerator, fraction.denominator);
  532.             int upv = ArithmeticUtils.mulAndCheck(fraction.numerator, denominator);
  533.             return new Fraction
  534.                 (isAdd ? ArithmeticUtils.addAndCheck(uvp, upv) :
  535.                  ArithmeticUtils.subAndCheck(uvp, upv),
  536.                  ArithmeticUtils.mulAndCheck(denominator, fraction.denominator));
  537.         }
  538.         // the quantity 't' requires 65 bits of precision; see knuth 4.5.1
  539.         // exercise 7.  we're going to use a BigInteger.
  540.         // t = u(v'/d1) +/- v(u'/d1)
  541.         BigInteger uvp = BigInteger.valueOf(numerator)
  542.                                    .multiply(BigInteger.valueOf(fraction.denominator / d1));
  543.         BigInteger upv = BigInteger.valueOf(fraction.numerator)
  544.                                    .multiply(BigInteger.valueOf(denominator / d1));
  545.         BigInteger t = isAdd ? uvp.add(upv) : uvp.subtract(upv);
  546.         // but d2 doesn't need extra precision because
  547.         // d2 = gcd(t,d1) = gcd(t mod d1, d1)
  548.         int tmodd1 = t.mod(BigInteger.valueOf(d1)).intValue();
  549.         int d2 = (tmodd1==0)?d1:ArithmeticUtils.gcd(tmodd1, d1);

  550.         // result is (t/d2) / (u'/d1)(v'/d2)
  551.         BigInteger w = t.divide(BigInteger.valueOf(d2));
  552.         if (w.bitLength() > 31) {
  553.             throw new MathRuntimeException(LocalizedCoreFormats.NUMERATOR_OVERFLOW_AFTER_MULTIPLY,
  554.                                            w);
  555.         }
  556.         return new Fraction (w.intValue(),
  557.                 ArithmeticUtils.mulAndCheck(denominator/d1,
  558.                                             fraction.denominator/d2));
  559.     }

  560.     /**
  561.      * Multiplies the value of this fraction by another, returning the
  562.      * result in reduced form.
  563.      *
  564.      * @param fraction  the fraction to multiply by, must not be {@code null}
  565.      * @return a {@code Fraction} instance with the resulting values
  566.      * @throws org.hipparchus.exception.NullArgumentException if the fraction is {@code null}
  567.      * @throws MathRuntimeException if the resulting numerator or denominator exceeds
  568.      *  {@code Integer.MAX_VALUE}
  569.      */
  570.     @Override
  571.     public Fraction multiply(Fraction fraction) {
  572.         MathUtils.checkNotNull(fraction, LocalizedCoreFormats.FRACTION);
  573.         if (numerator == 0 || fraction.numerator == 0) {
  574.             return ZERO;
  575.         }
  576.         // knuth 4.5.1
  577.         // make sure we don't overflow unless the result *must* overflow.
  578.         int d1 = ArithmeticUtils.gcd(numerator, fraction.denominator);
  579.         int d2 = ArithmeticUtils.gcd(fraction.numerator, denominator);
  580.         return getReducedFraction
  581.                 (ArithmeticUtils.mulAndCheck(numerator/d1, fraction.numerator/d2),
  582.                  ArithmeticUtils.mulAndCheck(denominator/d2, fraction.denominator/d1));
  583.     }

  584.     /**
  585.      * Multiply the fraction by an integer.
  586.      * @param i the {@code integer} to multiply by.
  587.      * @return this * i
  588.      */
  589.     @Override
  590.     public Fraction multiply(final int i) {
  591.         return multiply(new Fraction(i));
  592.     }

  593.     /**
  594.      * Divide the value of this fraction by another.
  595.      *
  596.      * @param fraction  the fraction to divide by, must not be {@code null}
  597.      * @return a {@code Fraction} instance with the resulting values
  598.      * @throws IllegalArgumentException if the fraction is {@code null}
  599.      * @throws MathRuntimeException if the fraction to divide by is zero
  600.      * @throws MathRuntimeException if the resulting numerator or denominator exceeds
  601.      *  {@code Integer.MAX_VALUE}
  602.      */
  603.     @Override
  604.     public Fraction divide(Fraction fraction) {
  605.         MathUtils.checkNotNull(fraction, LocalizedCoreFormats.FRACTION);
  606.         if (fraction.numerator == 0) {
  607.             throw new MathRuntimeException(LocalizedCoreFormats.ZERO_FRACTION_TO_DIVIDE_BY,
  608.                                            fraction.numerator, fraction.denominator);
  609.         }
  610.         return multiply(fraction.reciprocal());
  611.     }

  612.     /**
  613.      * Divide the fraction by an integer.
  614.      * @param i the {@code integer} to divide by.
  615.      * @return this * i
  616.      */
  617.     public Fraction divide(final int i) {
  618.         return divide(new Fraction(i));
  619.     }

  620.     /**
  621.      * Gets the fraction percentage as a {@code double}. This calculates the
  622.      * fraction as the numerator divided by denominator multiplied by 100.
  623.      *
  624.      * @return the fraction percentage as a {@code double}.
  625.      */
  626.     public double percentageValue() {
  627.         return 100 * doubleValue();
  628.     }

  629.     /**
  630.      * Creates a {@code Fraction} instance with the 2 parts
  631.      * of a fraction Y/Z.
  632.      * <p>
  633.      * Any negative signs are resolved to be on the numerator.
  634.      *
  635.      * @param numerator  the numerator, for example the three in 'three sevenths'
  636.      * @param denominator  the denominator, for example the seven in 'three sevenths'
  637.      * @return a new fraction instance, with the numerator and denominator reduced
  638.      * @throws MathRuntimeException if the denominator is {@code zero}
  639.      */
  640.     public static Fraction getReducedFraction(int numerator, int denominator) {
  641.         if (denominator == 0) {
  642.             throw new MathRuntimeException(LocalizedCoreFormats.ZERO_DENOMINATOR_IN_FRACTION,
  643.                                            numerator, denominator);
  644.         }
  645.         if (numerator==0) {
  646.             return ZERO; // normalize zero.
  647.         }
  648.         // allow 2^k/-2^31 as a valid fraction (where k>0)
  649.         if (denominator==Integer.MIN_VALUE && (numerator&1)==0) {
  650.             numerator/=2; denominator/=2;
  651.         }
  652.         if (denominator < 0) {
  653.             if (numerator==Integer.MIN_VALUE ||
  654.                 denominator==Integer.MIN_VALUE) {
  655.                 throw new MathRuntimeException(LocalizedCoreFormats.OVERFLOW_IN_FRACTION,
  656.                                                numerator, denominator);
  657.             }
  658.             numerator = -numerator;
  659.             denominator = -denominator;
  660.         }
  661.         // simplify fraction.
  662.         int gcd = ArithmeticUtils.gcd(numerator, denominator);
  663.         numerator /= gcd;
  664.         denominator /= gcd;
  665.         return new Fraction(numerator, denominator);
  666.     }

  667.     /**
  668.      * Returns the {@code String} representing this fraction, ie
  669.      * "num / dem" or just "num" if the denominator is one.
  670.      *
  671.      * @return a string representation of the fraction.
  672.      * @see java.lang.Object#toString()
  673.      */
  674.     @Override
  675.     public String toString() {
  676.         if (denominator == 1) {
  677.             return Integer.toString(numerator);
  678.         } else if (numerator == 0) {
  679.             return "0";
  680.         } else {
  681.             return numerator + " / " + denominator;
  682.         }
  683.     }

  684.     /** {@inheritDoc} */
  685.     @Override
  686.     public FractionField getField() {
  687.         return FractionField.getInstance();
  688.     }

  689. }