diff options
Diffstat (limited to 'src/main/java/org/apache/commons/math/fraction/BigFraction.java')
-rw-r--r-- | src/main/java/org/apache/commons/math/fraction/BigFraction.java | 1129 |
1 files changed, 1129 insertions, 0 deletions
diff --git a/src/main/java/org/apache/commons/math/fraction/BigFraction.java b/src/main/java/org/apache/commons/math/fraction/BigFraction.java new file mode 100644 index 0000000..98fa676 --- /dev/null +++ b/src/main/java/org/apache/commons/math/fraction/BigFraction.java @@ -0,0 +1,1129 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.math.fraction; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.math.BigInteger; + +import org.apache.commons.math.FieldElement; +import org.apache.commons.math.MathRuntimeException; +import org.apache.commons.math.exception.util.LocalizedFormats; +import org.apache.commons.math.util.MathUtils; +import org.apache.commons.math.util.FastMath; + +/** + * Representation of a rational number without any overflow. This class is + * immutable. + * + * @version $Revision: 1073687 $ $Date: 2011-02-23 11:39:25 +0100 (mer. 23 févr. 2011) $ + * @since 2.0 + */ +public class BigFraction + extends Number + implements FieldElement<BigFraction>, Comparable<BigFraction>, Serializable { + + /** A fraction representing "2 / 1". */ + public static final BigFraction TWO = new BigFraction(2); + + /** A fraction representing "1". */ + public static final BigFraction ONE = new BigFraction(1); + + /** A fraction representing "0". */ + public static final BigFraction ZERO = new BigFraction(0); + + /** A fraction representing "-1 / 1". */ + public static final BigFraction MINUS_ONE = new BigFraction(-1); + + /** A fraction representing "4/5". */ + public static final BigFraction FOUR_FIFTHS = new BigFraction(4, 5); + + /** A fraction representing "1/5". */ + public static final BigFraction ONE_FIFTH = new BigFraction(1, 5); + + /** A fraction representing "1/2". */ + public static final BigFraction ONE_HALF = new BigFraction(1, 2); + + /** A fraction representing "1/4". */ + public static final BigFraction ONE_QUARTER = new BigFraction(1, 4); + + /** A fraction representing "1/3". */ + public static final BigFraction ONE_THIRD = new BigFraction(1, 3); + + /** A fraction representing "3/5". */ + public static final BigFraction THREE_FIFTHS = new BigFraction(3, 5); + + /** A fraction representing "3/4". */ + public static final BigFraction THREE_QUARTERS = new BigFraction(3, 4); + + /** A fraction representing "2/5". */ + public static final BigFraction TWO_FIFTHS = new BigFraction(2, 5); + + /** A fraction representing "2/4". */ + public static final BigFraction TWO_QUARTERS = new BigFraction(2, 4); + + /** A fraction representing "2/3". */ + public static final BigFraction TWO_THIRDS = new BigFraction(2, 3); + + /** Serializable version identifier. */ + private static final long serialVersionUID = -5630213147331578515L; + + /** <code>BigInteger</code> representation of 100. */ + private static final BigInteger ONE_HUNDRED_DOUBLE = BigInteger.valueOf(100); + + /** The numerator. */ + private final BigInteger numerator; + + /** The denominator. */ + private final BigInteger denominator; + + /** + * <p> + * Create a {@link BigFraction} equivalent to the passed <tt>BigInteger</tt>, ie + * "num / 1". + * </p> + * + * @param num + * the numerator. + */ + public BigFraction(final BigInteger num) { + this(num, BigInteger.ONE); + } + + /** + * Create a {@link BigFraction} given the numerator and denominator as + * {@code BigInteger}. The {@link BigFraction} is reduced to lowest terms. + * + * @param num the numerator, must not be {@code null}. + * @param den the denominator, must not be {@code null}.. + * @throws ArithmeticException if the denominator is zero. + */ + public BigFraction(BigInteger num, BigInteger den) { + if (num == null) { + throw new NullPointerException(LocalizedFormats.NUMERATOR.getSourceString()); + } + if (den == null) { + throw new NullPointerException(LocalizedFormats.DENOMINATOR.getSourceString()); + } + if (BigInteger.ZERO.equals(den)) { + throw MathRuntimeException.createArithmeticException(LocalizedFormats.ZERO_DENOMINATOR); + } + if (BigInteger.ZERO.equals(num)) { + numerator = BigInteger.ZERO; + denominator = BigInteger.ONE; + } else { + + // reduce numerator and denominator by greatest common denominator + final BigInteger gcd = num.gcd(den); + if (BigInteger.ONE.compareTo(gcd) < 0) { + num = num.divide(gcd); + den = den.divide(gcd); + } + + // move sign to numerator + if (BigInteger.ZERO.compareTo(den) > 0) { + num = num.negate(); + den = den.negate(); + } + + // store the values in the final fields + numerator = num; + denominator = den; + + } + } + + /** + * Create a fraction given the double value. + * <p> + * This constructor behaves <em>differently</em> from + * {@link #BigFraction(double, double, int)}. It converts the + * double value exactly, considering its internal bits representation. + * This does work for all values except NaN and infinities and does + * not requires any loop or convergence threshold. + * </p> + * <p> + * Since this conversion is exact and since double numbers are sometimes + * approximated, the fraction created may seem strange in some cases. For example + * calling <code>new BigFraction(1.0 / 3.0)</code> does <em>not</em> create + * the fraction 1/3 but the fraction 6004799503160661 / 18014398509481984 + * because the double number passed to the constructor is not exactly 1/3 + * (this number cannot be stored exactly in IEEE754). + * </p> + * @see #BigFraction(double, double, int) + * @param value the double value to convert to a fraction. + * @exception IllegalArgumentException if value is NaN or infinite + */ + public BigFraction(final double value) throws IllegalArgumentException { + if (Double.isNaN(value)) { + throw MathRuntimeException.createIllegalArgumentException(LocalizedFormats.NAN_VALUE_CONVERSION); + } + if (Double.isInfinite(value)) { + throw MathRuntimeException.createIllegalArgumentException(LocalizedFormats.INFINITE_VALUE_CONVERSION); + } + + // compute m and k such that value = m * 2^k + final long bits = Double.doubleToLongBits(value); + final long sign = bits & 0x8000000000000000L; + final long exponent = bits & 0x7ff0000000000000L; + long m = bits & 0x000fffffffffffffL; + if (exponent != 0) { + // this was a normalized number, add the implicit most significant bit + m |= 0x0010000000000000L; + } + if (sign != 0) { + m = -m; + } + int k = ((int) (exponent >> 52)) - 1075; + while (((m & 0x001ffffffffffffeL) != 0) && ((m & 0x1) == 0)) { + m = m >> 1; + ++k; + } + + if (k < 0) { + numerator = BigInteger.valueOf(m); + denominator = BigInteger.ZERO.flipBit(-k); + } else { + numerator = BigInteger.valueOf(m).multiply(BigInteger.ZERO.flipBit(k)); + denominator = BigInteger.ONE; + } + + } + + /** + * Create a fraction given the double value and maximum error allowed. + * <p> + * References: + * <ul> + * <li><a href="http://mathworld.wolfram.com/ContinuedFraction.html"> + * Continued Fraction</a> equations (11) and (22)-(26)</li> + * </ul> + * </p> + * + * @param value + * the double value to convert to a fraction. + * @param epsilon + * maximum error allowed. The resulting fraction is within + * <code>epsilon</code> of <code>value</code>, in absolute terms. + * @param maxIterations + * maximum number of convergents. + * @throws FractionConversionException + * if the continued fraction failed to converge. + * @see #BigFraction(double) + */ + public BigFraction(final double value, final double epsilon, + final int maxIterations) + throws FractionConversionException { + this(value, epsilon, Integer.MAX_VALUE, maxIterations); + } + + /** + * Create a fraction given the double value and either the maximum error + * allowed or the maximum number of denominator digits. + * <p> + * + * NOTE: This constructor is called with EITHER - a valid epsilon value and + * the maxDenominator set to Integer.MAX_VALUE (that way the maxDenominator + * has no effect). OR - a valid maxDenominator value and the epsilon value + * set to zero (that way epsilon only has effect if there is an exact match + * before the maxDenominator value is reached). + * </p> + * <p> + * + * It has been done this way so that the same code can be (re)used for both + * scenarios. However this could be confusing to users if it were part of + * the public API and this constructor should therefore remain PRIVATE. + * </p> + * + * See JIRA issue ticket MATH-181 for more details: + * + * https://issues.apache.org/jira/browse/MATH-181 + * + * @param value + * the double value to convert to a fraction. + * @param epsilon + * maximum error allowed. The resulting fraction is within + * <code>epsilon</code> of <code>value</code>, in absolute terms. + * @param maxDenominator + * maximum denominator value allowed. + * @param maxIterations + * maximum number of convergents. + * @throws FractionConversionException + * if the continued fraction failed to converge. + */ + private BigFraction(final double value, final double epsilon, + final int maxDenominator, int maxIterations) + throws FractionConversionException { + long overflow = Integer.MAX_VALUE; + double r0 = value; + long a0 = (long) FastMath.floor(r0); + if (a0 > overflow) { + throw new FractionConversionException(value, a0, 1l); + } + + // check for (almost) integer arguments, which should not go + // to iterations. + if (FastMath.abs(a0 - value) < epsilon) { + numerator = BigInteger.valueOf(a0); + denominator = BigInteger.ONE; + return; + } + + long p0 = 1; + long q0 = 0; + long p1 = a0; + long q1 = 1; + + long p2 = 0; + long q2 = 1; + + int n = 0; + boolean stop = false; + do { + ++n; + final double r1 = 1.0 / (r0 - a0); + final long a1 = (long) FastMath.floor(r1); + p2 = (a1 * p1) + p0; + q2 = (a1 * q1) + q0; + if ((p2 > overflow) || (q2 > overflow)) { + throw new FractionConversionException(value, p2, q2); + } + + final double convergent = (double) p2 / (double) q2; + if ((n < maxIterations) && + (FastMath.abs(convergent - value) > epsilon) && + (q2 < maxDenominator)) { + p0 = p1; + p1 = p2; + q0 = q1; + q1 = q2; + a0 = a1; + r0 = r1; + } else { + stop = true; + } + } while (!stop); + + if (n >= maxIterations) { + throw new FractionConversionException(value, maxIterations); + } + + if (q2 < maxDenominator) { + numerator = BigInteger.valueOf(p2); + denominator = BigInteger.valueOf(q2); + } else { + numerator = BigInteger.valueOf(p1); + denominator = BigInteger.valueOf(q1); + } + } + + /** + * Create a fraction given the double value and maximum denominator. + * <p> + * References: + * <ul> + * <li><a href="http://mathworld.wolfram.com/ContinuedFraction.html"> + * Continued Fraction</a> equations (11) and (22)-(26)</li> + * </ul> + * </p> + * + * @param value + * the double value to convert to a fraction. + * @param maxDenominator + * The maximum allowed value for denominator. + * @throws FractionConversionException + * if the continued fraction failed to converge. + */ + public BigFraction(final double value, final int maxDenominator) + throws FractionConversionException { + this(value, 0, maxDenominator, 100); + } + + /** + * <p> + * Create a {@link BigFraction} equivalent to the passed <tt>int</tt>, ie + * "num / 1". + * </p> + * + * @param num + * the numerator. + */ + public BigFraction(final int num) { + this(BigInteger.valueOf(num), BigInteger.ONE); + } + + /** + * <p> + * Create a {@link BigFraction} given the numerator and denominator as simple + * <tt>int</tt>. The {@link BigFraction} is reduced to lowest terms. + * </p> + * + * @param num + * the numerator. + * @param den + * the denominator. + */ + public BigFraction(final int num, final int den) { + this(BigInteger.valueOf(num), BigInteger.valueOf(den)); + } + + /** + * <p> + * Create a {@link BigFraction} equivalent to the passed long, ie "num / 1". + * </p> + * + * @param num + * the numerator. + */ + public BigFraction(final long num) { + this(BigInteger.valueOf(num), BigInteger.ONE); + } + + /** + * <p> + * Create a {@link BigFraction} given the numerator and denominator as simple + * <tt>long</tt>. The {@link BigFraction} is reduced to lowest terms. + * </p> + * + * @param num + * the numerator. + * @param den + * the denominator. + */ + public BigFraction(final long num, final long den) { + this(BigInteger.valueOf(num), BigInteger.valueOf(den)); + } + + /** + * <p> + * Creates a <code>BigFraction</code> instance with the 2 parts of a fraction + * Y/Z. + * </p> + * + * <p> + * Any negative signs are resolved to be on the numerator. + * </p> + * + * @param numerator + * the numerator, for example the three in 'three sevenths'. + * @param denominator + * the denominator, for example the seven in 'three sevenths'. + * @return a new fraction instance, with the numerator and denominator + * reduced. + * @throws ArithmeticException + * if the denominator is <code>zero</code>. + */ + public static BigFraction getReducedFraction(final int numerator, + final int denominator) { + if (numerator == 0) { + return ZERO; // normalize zero. + } + + return new BigFraction(numerator, denominator); + } + + /** + * <p> + * Returns the absolute value of this {@link BigFraction}. + * </p> + * + * @return the absolute value as a {@link BigFraction}. + */ + public BigFraction abs() { + return (BigInteger.ZERO.compareTo(numerator) <= 0) ? this : negate(); + } + + /** + * <p> + * Adds the value of this fraction to the passed {@link BigInteger}, + * returning the result in reduced form. + * </p> + * + * @param bg + * the {@link BigInteger} to add, must'nt be <code>null</code>. + * @return a <code>BigFraction</code> instance with the resulting values. + * @throws NullPointerException + * if the {@link BigInteger} is <code>null</code>. + */ + public BigFraction add(final BigInteger bg) { + return new BigFraction(numerator.add(denominator.multiply(bg)), denominator); + } + + /** + * <p> + * Adds the value of this fraction to the passed <tt>integer</tt>, returning + * the result in reduced form. + * </p> + * + * @param i + * the <tt>integer</tt> to add. + * @return a <code>BigFraction</code> instance with the resulting values. + */ + public BigFraction add(final int i) { + return add(BigInteger.valueOf(i)); + } + + /** + * <p> + * Adds the value of this fraction to the passed <tt>long</tt>, returning + * the result in reduced form. + * </p> + * + * @param l + * the <tt>long</tt> to add. + * @return a <code>BigFraction</code> instance with the resulting values. + */ + public BigFraction add(final long l) { + return add(BigInteger.valueOf(l)); + } + + /** + * <p> + * Adds the value of this fraction to another, returning the result in + * reduced form. + * </p> + * + * @param fraction + * the {@link BigFraction} to add, must not be <code>null</code>. + * @return a {@link BigFraction} instance with the resulting values. + * @throws NullPointerException if the {@link BigFraction} is {@code null}. + */ + public BigFraction add(final BigFraction fraction) { + if (fraction == null) { + throw new NullPointerException(LocalizedFormats.FRACTION.getSourceString()); + } + if (ZERO.equals(fraction)) { + return this; + } + + BigInteger num = null; + BigInteger den = null; + + if (denominator.equals(fraction.denominator)) { + num = numerator.add(fraction.numerator); + den = denominator; + } else { + num = (numerator.multiply(fraction.denominator)).add((fraction.numerator).multiply(denominator)); + den = denominator.multiply(fraction.denominator); + } + return new BigFraction(num, den); + + } + + /** + * <p> + * Gets the fraction as a <code>BigDecimal</code>. This calculates the + * fraction as the numerator divided by denominator. + * </p> + * + * @return the fraction as a <code>BigDecimal</code>. + * @throws ArithmeticException + * if the exact quotient does not have a terminating decimal + * expansion. + * @see BigDecimal + */ + public BigDecimal bigDecimalValue() { + return new BigDecimal(numerator).divide(new BigDecimal(denominator)); + } + + /** + * <p> + * Gets the fraction as a <code>BigDecimal</code> following the passed + * rounding mode. This calculates the fraction as the numerator divided by + * denominator. + * </p> + * + * @param roundingMode + * rounding mode to apply. see {@link BigDecimal} constants. + * @return the fraction as a <code>BigDecimal</code>. + * @throws IllegalArgumentException + * if <tt>roundingMode</tt> does not represent a valid rounding + * mode. + * @see BigDecimal + */ + public BigDecimal bigDecimalValue(final int roundingMode) { + return new BigDecimal(numerator).divide(new BigDecimal(denominator), roundingMode); + } + + /** + * <p> + * Gets the fraction as a <code>BigDecimal</code> following the passed scale + * and rounding mode. This calculates the fraction as the numerator divided + * by denominator. + * </p> + * + * @param scale + * scale of the <code>BigDecimal</code> quotient to be returned. + * see {@link BigDecimal} for more information. + * @param roundingMode + * rounding mode to apply. see {@link BigDecimal} constants. + * @return the fraction as a <code>BigDecimal</code>. + * @see BigDecimal + */ + public BigDecimal bigDecimalValue(final int scale, final int roundingMode) { + return new BigDecimal(numerator).divide(new BigDecimal(denominator), scale, roundingMode); + } + + /** + * <p> + * Compares this object to another based on size. + * </p> + * + * @param object + * the object to compare to, must not be <code>null</code>. + * @return -1 if this is less than <tt>object</tt>, +1 if this is greater + * than <tt>object</tt>, 0 if they are equal. + * @see java.lang.Comparable#compareTo(java.lang.Object) + */ + public int compareTo(final BigFraction object) { + BigInteger nOd = numerator.multiply(object.denominator); + BigInteger dOn = denominator.multiply(object.numerator); + return nOd.compareTo(dOn); + } + + /** + * <p> + * Divide the value of this fraction by the passed <code>BigInteger</code>, + * ie "this * 1 / bg", returning the result in reduced form. + * </p> + * + * @param bg + * the <code>BigInteger</code> to divide by, must not be + * <code>null</code>. + * @return a {@link BigFraction} instance with the resulting values. + * @throws NullPointerException if the {@code BigInteger} is {@code null}. + * @throws ArithmeticException + * if the fraction to divide by is zero. + */ + public BigFraction divide(final BigInteger bg) { + if (BigInteger.ZERO.equals(bg)) { + throw MathRuntimeException.createArithmeticException(LocalizedFormats.ZERO_DENOMINATOR); + } + return new BigFraction(numerator, denominator.multiply(bg)); + } + + /** + * <p> + * Divide the value of this fraction by the passed <tt>int</tt>, ie + * "this * 1 / i", returning the result in reduced form. + * </p> + * + * @param i + * the <tt>int</tt> to divide by. + * @return a {@link BigFraction} instance with the resulting values. + * @throws ArithmeticException + * if the fraction to divide by is zero. + */ + public BigFraction divide(final int i) { + return divide(BigInteger.valueOf(i)); + } + + /** + * <p> + * Divide the value of this fraction by the passed <tt>long</tt>, ie + * "this * 1 / l", returning the result in reduced form. + * </p> + * + * @param l + * the <tt>long</tt> to divide by. + * @return a {@link BigFraction} instance with the resulting values. + * @throws ArithmeticException + * if the fraction to divide by is zero. + */ + public BigFraction divide(final long l) { + return divide(BigInteger.valueOf(l)); + } + + /** + * <p> + * Divide the value of this fraction by another, returning the result in + * reduced form. + * </p> + * + * @param fraction Fraction to divide by, must not be {@code null}. + * @return a {@link BigFraction} instance with the resulting values. + * @throws NullPointerException if the {@code fraction} is {@code null}. + * @throws ArithmeticException if the fraction to divide by is zero. + */ + public BigFraction divide(final BigFraction fraction) { + if (fraction == null) { + throw new NullPointerException(LocalizedFormats.FRACTION.getSourceString()); + } + if (BigInteger.ZERO.equals(fraction.numerator)) { + throw MathRuntimeException.createArithmeticException(LocalizedFormats.ZERO_DENOMINATOR); + } + + return multiply(fraction.reciprocal()); + } + + /** + * <p> + * Gets the fraction as a <tt>double</tt>. This calculates the fraction as + * the numerator divided by denominator. + * </p> + * + * @return the fraction as a <tt>double</tt> + * @see java.lang.Number#doubleValue() + */ + @Override + public double doubleValue() { + return numerator.doubleValue() / denominator.doubleValue(); + } + + /** + * <p> + * Test for the equality of two fractions. If the lowest term numerator and + * denominators are the same for both fractions, the two fractions are + * considered to be equal. + * </p> + * + * @param other + * fraction to test for equality to this fraction, can be + * <code>null</code>. + * @return true if two fractions are equal, false if object is + * <code>null</code>, not an instance of {@link BigFraction}, or not + * equal to this fraction instance. + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(final Object other) { + boolean ret = false; + + if (this == other) { + ret = true; + } else if (other instanceof BigFraction) { + BigFraction rhs = ((BigFraction) other).reduce(); + BigFraction thisOne = this.reduce(); + ret = thisOne.numerator.equals(rhs.numerator) && thisOne.denominator.equals(rhs.denominator); + } + + return ret; + } + + /** + * <p> + * Gets the fraction as a <tt>float</tt>. This calculates the fraction as + * the numerator divided by denominator. + * </p> + * + * @return the fraction as a <tt>float</tt>. + * @see java.lang.Number#floatValue() + */ + @Override + public float floatValue() { + return numerator.floatValue() / denominator.floatValue(); + } + + /** + * <p> + * Access the denominator as a <code>BigInteger</code>. + * </p> + * + * @return the denominator as a <code>BigInteger</code>. + */ + public BigInteger getDenominator() { + return denominator; + } + + /** + * <p> + * Access the denominator as a <tt>int</tt>. + * </p> + * + * @return the denominator as a <tt>int</tt>. + */ + public int getDenominatorAsInt() { + return denominator.intValue(); + } + + /** + * <p> + * Access the denominator as a <tt>long</tt>. + * </p> + * + * @return the denominator as a <tt>long</tt>. + */ + public long getDenominatorAsLong() { + return denominator.longValue(); + } + + /** + * <p> + * Access the numerator as a <code>BigInteger</code>. + * </p> + * + * @return the numerator as a <code>BigInteger</code>. + */ + public BigInteger getNumerator() { + return numerator; + } + + /** + * <p> + * Access the numerator as a <tt>int</tt>. + * </p> + * + * @return the numerator as a <tt>int</tt>. + */ + public int getNumeratorAsInt() { + return numerator.intValue(); + } + + /** + * <p> + * Access the numerator as a <tt>long</tt>. + * </p> + * + * @return the numerator as a <tt>long</tt>. + */ + public long getNumeratorAsLong() { + return numerator.longValue(); + } + + /** + * <p> + * Gets a hashCode for the fraction. + * </p> + * + * @return a hash code value for this object. + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + return 37 * (37 * 17 + numerator.hashCode()) + denominator.hashCode(); + } + + /** + * <p> + * Gets the fraction as an <tt>int</tt>. This returns the whole number part + * of the fraction. + * </p> + * + * @return the whole number fraction part. + * @see java.lang.Number#intValue() + */ + @Override + public int intValue() { + return numerator.divide(denominator).intValue(); + } + + /** + * <p> + * Gets the fraction as a <tt>long</tt>. This returns the whole number part + * of the fraction. + * </p> + * + * @return the whole number fraction part. + * @see java.lang.Number#longValue() + */ + @Override + public long longValue() { + return numerator.divide(denominator).longValue(); + } + + /** + * <p> + * Multiplies the value of this fraction by the passed + * <code>BigInteger</code>, returning the result in reduced form. + * </p> + * + * @param bg the {@code BigInteger} to multiply by. + * @return a {@code BigFraction} instance with the resulting values. + * @throws NullPointerException if {@code bg} is {@code null}. + */ + public BigFraction multiply(final BigInteger bg) { + if (bg == null) { + throw new NullPointerException(); + } + return new BigFraction(bg.multiply(numerator), denominator); + } + + /** + * <p> + * Multiply the value of this fraction by the passed <tt>int</tt>, returning + * the result in reduced form. + * </p> + * + * @param i + * the <tt>int</tt> to multiply by. + * @return a {@link BigFraction} instance with the resulting values. + */ + public BigFraction multiply(final int i) { + return multiply(BigInteger.valueOf(i)); + } + + /** + * <p> + * Multiply the value of this fraction by the passed <tt>long</tt>, + * returning the result in reduced form. + * </p> + * + * @param l + * the <tt>long</tt> to multiply by. + * @return a {@link BigFraction} instance with the resulting values. + */ + public BigFraction multiply(final long l) { + return multiply(BigInteger.valueOf(l)); + } + + /** + * <p> + * Multiplies the value of this fraction by another, returning the result in + * reduced form. + * </p> + * + * @param fraction Fraction to multiply by, must not be {@code null}. + * @return a {@link BigFraction} instance with the resulting values. + * @throws NullPointerException if {@code fraction} is {@code null}. + */ + public BigFraction multiply(final BigFraction fraction) { + if (fraction == null) { + throw new NullPointerException(LocalizedFormats.FRACTION.getSourceString()); + } + if (numerator.equals(BigInteger.ZERO) || + fraction.numerator.equals(BigInteger.ZERO)) { + return ZERO; + } + return new BigFraction(numerator.multiply(fraction.numerator), + denominator.multiply(fraction.denominator)); + } + + /** + * <p> + * Return the additive inverse of this fraction, returning the result in + * reduced form. + * </p> + * + * @return the negation of this fraction. + */ + public BigFraction negate() { + return new BigFraction(numerator.negate(), denominator); + } + + /** + * <p> + * Gets the fraction percentage as a <tt>double</tt>. This calculates the + * fraction as the numerator divided by denominator multiplied by 100. + * </p> + * + * @return the fraction percentage as a <tt>double</tt>. + */ + public double percentageValue() { + return (numerator.divide(denominator)).multiply(ONE_HUNDRED_DOUBLE).doubleValue(); + } + + /** + * <p> + * Returns a <tt>integer</tt> whose value is + * <tt>(this<sup>exponent</sup>)</tt>, returning the result in reduced form. + * </p> + * + * @param exponent + * exponent to which this <code>BigInteger</code> is to be + * raised. + * @return <tt>this<sup>exponent</sup></tt>. + */ + public BigFraction pow(final int exponent) { + if (exponent < 0) { + return new BigFraction(denominator.pow(-exponent), numerator.pow(-exponent)); + } + return new BigFraction(numerator.pow(exponent), denominator.pow(exponent)); + } + + /** + * <p> + * Returns a <code>BigFraction</code> whose value is + * <tt>(this<sup>exponent</sup>)</tt>, returning the result in reduced form. + * </p> + * + * @param exponent + * exponent to which this <code>BigFraction</code> is to be raised. + * @return <tt>this<sup>exponent</sup></tt> as a <code>BigFraction</code>. + */ + public BigFraction pow(final long exponent) { + if (exponent < 0) { + return new BigFraction(MathUtils.pow(denominator, -exponent), + MathUtils.pow(numerator, -exponent)); + } + return new BigFraction(MathUtils.pow(numerator, exponent), + MathUtils.pow(denominator, exponent)); + } + + /** + * <p> + * Returns a <code>BigFraction</code> whose value is + * <tt>(this<sup>exponent</sup>)</tt>, returning the result in reduced form. + * </p> + * + * @param exponent + * exponent to which this <code>BigFraction</code> is to be raised. + * @return <tt>this<sup>exponent</sup></tt> as a <code>BigFraction</code>. + */ + public BigFraction pow(final BigInteger exponent) { + if (exponent.compareTo(BigInteger.ZERO) < 0) { + final BigInteger eNeg = exponent.negate(); + return new BigFraction(MathUtils.pow(denominator, eNeg), + MathUtils.pow(numerator, eNeg)); + } + return new BigFraction(MathUtils.pow(numerator, exponent), + MathUtils.pow(denominator, exponent)); + } + + /** + * <p> + * Returns a <code>double</code> whose value is + * <tt>(this<sup>exponent</sup>)</tt>, returning the result in reduced form. + * </p> + * + * @param exponent + * exponent to which this <code>BigFraction</code> is to be raised. + * @return <tt>this<sup>exponent</sup></tt>. + */ + public double pow(final double exponent) { + return FastMath.pow(numerator.doubleValue(), exponent) / + FastMath.pow(denominator.doubleValue(), exponent); + } + + /** + * <p> + * Return the multiplicative inverse of this fraction. + * </p> + * + * @return the reciprocal fraction. + */ + public BigFraction reciprocal() { + return new BigFraction(denominator, numerator); + } + + /** + * <p> + * Reduce this <code>BigFraction</code> to its lowest terms. + * </p> + * + * @return the reduced <code>BigFraction</code>. It doesn't change anything if + * the fraction can be reduced. + */ + public BigFraction reduce() { + final BigInteger gcd = numerator.gcd(denominator); + return new BigFraction(numerator.divide(gcd), denominator.divide(gcd)); + } + + /** + * <p> + * Subtracts the value of an {@link BigInteger} from the value of this one, + * returning the result in reduced form. + * </p> + * + * @param bg the {@link BigInteger} to subtract, cannot be {@code null}. + * @return a {@code BigFraction} instance with the resulting values. + * @throws NullPointerException if the {@link BigInteger} is {@code null}. + */ + public BigFraction subtract(final BigInteger bg) { + if (bg == null) { + throw new NullPointerException(); + } + return new BigFraction(numerator.subtract(denominator.multiply(bg)), denominator); + } + + /** + * <p> + * Subtracts the value of an <tt>integer</tt> from the value of this one, + * returning the result in reduced form. + * </p> + * + * @param i + * the <tt>integer</tt> to subtract. + * @return a <code>BigFraction</code> instance with the resulting values. + */ + public BigFraction subtract(final int i) { + return subtract(BigInteger.valueOf(i)); + } + + /** + * <p> + * Subtracts the value of an <tt>integer</tt> from the value of this one, + * returning the result in reduced form. + * </p> + * + * @param l + * the <tt>long</tt> to subtract. + * @return a <code>BigFraction</code> instance with the resulting values, or + * this object if the <tt>long</tt> is zero. + */ + public BigFraction subtract(final long l) { + return subtract(BigInteger.valueOf(l)); + } + + /** + * <p> + * Subtracts the value of another fraction from the value of this one, + * returning the result in reduced form. + * </p> + * + * @param fraction {@link BigFraction} to subtract, must not be {@code null}. + * @return a {@link BigFraction} instance with the resulting values + * @throws NullPointerException if the {@code fraction} is {@code null}. + */ + public BigFraction subtract(final BigFraction fraction) { + if (fraction == null) { + throw new NullPointerException(LocalizedFormats.FRACTION.getSourceString()); + } + if (ZERO.equals(fraction)) { + return this; + } + + BigInteger num = null; + BigInteger den = null; + if (denominator.equals(fraction.denominator)) { + num = numerator.subtract(fraction.numerator); + den = denominator; + } else { + num = (numerator.multiply(fraction.denominator)).subtract((fraction.numerator).multiply(denominator)); + den = denominator.multiply(fraction.denominator); + } + return new BigFraction(num, den); + + } + + /** + * <p> + * Returns the <code>String</code> representing this fraction, ie + * "num / dem" or just "num" if the denominator is one. + * </p> + * + * @return a string representation of the fraction. + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + String str = null; + if (BigInteger.ONE.equals(denominator)) { + str = numerator.toString(); + } else if (BigInteger.ZERO.equals(numerator)) { + str = "0"; + } else { + str = numerator + " / " + denominator; + } + return str; + } + + /** {@inheritDoc} */ + public BigFractionField getField() { + return BigFractionField.getInstance(); + } + +} |