This is an automated email from the ASF dual-hosted git repository. aherbert pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/commons-numbers.git commit 7a94e4afb853c4e32b19a6ef0053937bf4bd7c2e Author: aherbert AuthorDate: Tue Apr 7 11:00:22 2020 +0100 Fraction/BigFraction to use same method order: private constructors factory constructors, including parse(String) Properties: zero(), one() numerator(), denominator() Computed properties: signum Conversions: abs, negate, reciprocal primitive values (double/float/int/longValue,etc) Math: Arithmetic add,subtract,multiply,divide Power functions Standard object stuff: toString(), compareTo, equals(), hashCode() --- .../commons/numbers/fraction/BigFraction.java | 1153 ++++++++++---------- .../apache/commons/numbers/fraction/Fraction.java | 414 +++---- 2 files changed, 786 insertions(+), 781 deletions(-) diff --git a/commons-numbers-fraction/src/main/java/org/apache/commons/numbers/fraction/BigFraction.java b/commons-numbers-fraction/src/main/java/org/apache/commons/numbers/fraction/BigFraction.java index a62e0d7..9a969c9 100644 --- a/commons-numbers-fraction/src/main/java/org/apache/commons/numbers/fraction/BigFraction.java +++ b/commons-numbers-fraction/src/main/java/org/apache/commons/numbers/fraction/BigFraction.java @@ -310,16 +310,13 @@ public final class BigFraction } /** - * Create a fraction given the numerator and denominator. - * The fraction is reduced to lowest terms. + * Create a fraction given the numerator. The denominator is {@code 1}. * * @param num the numerator. - * @param den the denominator. * @return a new instance. - * @throws ArithmeticException if {@code den} is zero. */ - public static BigFraction of(final int num, final int den) { - return new BigFraction(BigInteger.valueOf(num), BigInteger.valueOf(den)); + public static BigFraction of(final long num) { + return new BigFraction(BigInteger.valueOf(num), BigInteger.ONE); } /** @@ -327,9 +324,10 @@ public final class BigFraction * * @param num the numerator. * @return a new instance. + * @throws NullPointerException if numerator is null. */ - public static BigFraction of(final long num) { - return new BigFraction(BigInteger.valueOf(num), BigInteger.ONE); + public static BigFraction of(final BigInteger num) { + return new BigFraction(num, BigInteger.ONE); } /** @@ -341,19 +339,21 @@ public final class BigFraction * @return a new instance. * @throws ArithmeticException if {@code den} is zero. */ - public static BigFraction of(final long num, final long den) { + public static BigFraction of(final int num, final int den) { return new BigFraction(BigInteger.valueOf(num), BigInteger.valueOf(den)); } /** - * Create a fraction given the numerator. The denominator is {@code 1}. + * Create a fraction given the numerator and denominator. + * The fraction is reduced to lowest terms. * * @param num the numerator. + * @param den the denominator. * @return a new instance. - * @throws NullPointerException if numerator is null. + * @throws ArithmeticException if {@code den} is zero. */ - public static BigFraction of(final BigInteger num) { - return new BigFraction(num, BigInteger.ONE); + public static BigFraction of(final long num, final long den) { + return new BigFraction(BigInteger.valueOf(num), BigInteger.valueOf(den)); } /** @@ -366,10 +366,117 @@ public final class BigFraction * @throws ArithmeticException if the denominator is zero. * @throws NullPointerException if numerator or denominator are null. */ - public static BigFraction of(BigInteger num, BigInteger den) { + public static BigFraction of(final BigInteger num, final BigInteger den) { return new BigFraction(num, den); } + + /** + * Parses a string that would be produced by {@link #toString()} + * and instantiates the corresponding object. + * + * @param s String representation. + * @return an instance. + * @throws NumberFormatException if the string does not conform + * to the specification. + */ + public static BigFraction parse(String s) { + s = s.replace(",", ""); + final int slashLoc = s.indexOf('/'); + // if no slash, parse as single number + if (slashLoc == -1) { + return BigFraction.of(new BigInteger(s.trim())); + } + final BigInteger num = new BigInteger( + s.substring(0, slashLoc).trim()); + final BigInteger denom = new BigInteger(s.substring(slashLoc + 1).trim()); + return of(num, denom); + } + + @Override + public BigFraction zero() { + return ZERO; + } + + @Override + public BigFraction one() { + return ONE; + } + + /** + * Access the numerator as a {@code BigInteger}. + * + * @return the numerator as a {@code BigInteger}. + */ + public BigInteger getNumerator() { + return numerator; + } + + /** + * Access the numerator as an {@code int}. + * + * @return the numerator as an {@code int}. + */ + public int getNumeratorAsInt() { + return numerator.intValue(); + } + + /** + * Access the numerator as a {@code long}. + * + * @return the numerator as a {@code long}. + */ + public long getNumeratorAsLong() { + return numerator.longValue(); + } + + /** + * Access the denominator as a {@code BigInteger}. + * + * @return the denominator as a {@code BigInteger}. + */ + public BigInteger getDenominator() { + return denominator; + } + + /** + * Access the denominator as an {@code int}. + * + * @return the denominator as an {@code int}. + */ + public int getDenominatorAsInt() { + return denominator.intValue(); + } + + /** + * Access the denominator as a {@code long}. + * + * @return the denominator as a {@code long}. + */ + public long getDenominatorAsLong() { + return denominator.longValue(); + } + + /** + * Retrieves the sign of this fraction. + * + * @return -1 if the value is strictly negative, 1 if it is strictly + * positive, 0 if it is 0. + */ + public int signum() { + final int numS = numerator.signum(); + final int denS = denominator.signum(); + + if ((numS > 0 && denS > 0) || + (numS < 0 && denS < 0)) { + return 1; + } else if (numS == 0) { + return 0; + } else { + return -1; + } + } + /** * Returns the absolute value of this fraction. * @@ -382,82 +489,72 @@ public final class BigFraction } /** - * Adds the value of this fraction to the passed {@link BigInteger}, - * returning the result in reduced form. + * Return the additive inverse of this fraction, returning the result in + * reduced form. * - * @param bg - * the {@link BigInteger} to add, must'nt be {@code null}. - * @return a {@code BigFraction} instance with the resulting values. + * @return the negation of this fraction. */ - public BigFraction add(final BigInteger bg) { - if (numerator.signum() == 0) { - return of(bg); - } - if (bg.signum() == 0) { - return this; - } - - return new BigFraction(numerator.add(denominator.multiply(bg)), denominator); + @Override + public BigFraction negate() { + return new BigFraction(numerator.negate(), denominator); } /** - * Adds the value of this fraction to the passed {@code integer}, returning - * the result in reduced form. + * Return the multiplicative inverse of this fraction. * - * @param i - * the {@code integer} to add. - * @return a {@code BigFraction} instance with the resulting values. + * @return the reciprocal fraction. */ - public BigFraction add(final int i) { - return add(BigInteger.valueOf(i)); + @Override + public BigFraction reciprocal() { + return new BigFraction(denominator, numerator); } /** - * Adds the value of this fraction to the passed {@code long}, returning - * the result in reduced form. + * Gets the fraction as a {@code double}. This calculates the fraction as + * the numerator divided by denominator. * - * @param l - * the {@code long} to add. - * @return a {@code BigFraction} instance with the resulting values. + * @return the fraction as a {@code double} + * @see java.lang.Number#doubleValue() */ - public BigFraction add(final long l) { - return add(BigInteger.valueOf(l)); + @Override + public double doubleValue() { + return Double.longBitsToDouble(toFloatingPointBits(11, 52)); } /** - * Adds the value of this fraction to another, returning the result in - * reduced form. + * Retrieves the {@code float} value closest to this fraction. + * This calculates the fraction as numerator divided by denominator. * - * @param fraction - * the {@link BigFraction} to add, must not be {@code null}. - * @return a {@link BigFraction} instance with the resulting values. + * @return the fraction as a {@code float}. + * @see java.lang.Number#floatValue() */ @Override - public BigFraction add(final BigFraction fraction) { - if (fraction.numerator.signum() == 0) { - return this; - } - if (numerator.signum() == 0) { - return fraction; - } - - final BigInteger num; - final BigInteger den; - - 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); - } - - if (num.signum() == 0) { - return ZERO; - } + public float floatValue() { + return Float.intBitsToFloat((int) toFloatingPointBits(8, 23)); + } - return new BigFraction(num, den); + /** + * Gets the fraction as an {@code int}. This returns the whole number part + * of the fraction. + * + * @return the whole number fraction part. + * @see java.lang.Number#intValue() + */ + @Override + public int intValue() { + return numerator.divide(denominator).intValue(); + } + /** + * Gets the fraction as a {@code long}. This returns the whole number part + * of the fraction. + * + * @return the whole number fraction part. + * @see java.lang.Number#longValue() + */ + @Override + public long longValue() { + return numerator.divide(denominator).longValue(); } /** @@ -506,47 +603,213 @@ public final class BigFraction } /** - * Compares this object to another based on size. - * - * @param other Object to compare to, must not be {@code null}. - * @return -1 if this is less than {@code object}, +1 if this is greater - * than {@code object}, 0 if they are equal. + * Adds the value of this fraction to the passed {@code integer}, returning + * the result in reduced form. * - * @see Comparable#compareTo(Object) + * @param i + * the {@code integer} to add. + * @return a {@code BigFraction} instance with the resulting values. */ - @Override - public int compareTo(final BigFraction other) { - final int lhsSigNum = signum(); - final int rhsSigNum = other.signum(); - - if (lhsSigNum != rhsSigNum) { - return (lhsSigNum > rhsSigNum) ? 1 : -1; - } - if (lhsSigNum == 0) { - return 0; - } + public BigFraction add(final int i) { + return add(BigInteger.valueOf(i)); + } - final BigInteger nOd = numerator.multiply(other.denominator); - final BigInteger dOn = denominator.multiply(other.numerator); - return nOd.compareTo(dOn); + /** + * Adds the value of this fraction to the passed {@code long}, returning + * the result in reduced form. + * + * @param l + * the {@code long} to add. + * @return a {@code BigFraction} instance with the resulting values. + */ + public BigFraction add(final long l) { + return add(BigInteger.valueOf(l)); } /** - * Divide the value of this fraction by the passed {@code BigInteger}, - * ie {@code this * 1 / bg}, returning the result in reduced form. + * Adds the value of this fraction to the passed {@link BigInteger}, + * returning the result in reduced form. * - * @param bg the {@code BigInteger} to divide by, must not be {@code null} - * @return a {@link BigFraction} instance with the resulting values - * @throws ArithmeticException if the value to divide by is zero + * @param bg + * the {@link BigInteger} to add, must'nt be {@code null}. + * @return a {@code BigFraction} instance with the resulting values. */ - public BigFraction divide(final BigInteger bg) { + public BigFraction add(final BigInteger bg) { + if (numerator.signum() == 0) { + return of(bg); + } if (bg.signum() == 0) { - throw new FractionException(FractionException.ERROR_ZERO_DENOMINATOR); + return this; + } + + return new BigFraction(numerator.add(denominator.multiply(bg)), denominator); + } + + /** + * Adds the value of this fraction to another, returning the result in + * reduced form. + * + * @param fraction + * the {@link BigFraction} to add, must not be {@code null}. + * @return a {@link BigFraction} instance with the resulting values. + */ + @Override + public BigFraction add(final BigFraction fraction) { + if (fraction.numerator.signum() == 0) { + return this; } if (numerator.signum() == 0) { + return fraction; + } + + final BigInteger num; + final BigInteger den; + + 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); + } + + if (num.signum() == 0) { return ZERO; } - return new BigFraction(numerator, denominator.multiply(bg)); + + return new BigFraction(num, den); + } + + /** + * Subtracts the value of an {@code integer} from the value of this + * {@code BigFraction}, returning the result in reduced form. + * + * @param i the {@code integer} to subtract. + * @return a {@code BigFraction} instance with the resulting values. + */ + public BigFraction subtract(final int i) { + return subtract(BigInteger.valueOf(i)); + } + + /** + * Subtracts the value of a {@code long} from the value of this + * {@code BigFraction}, returning the result in reduced form. + * + * @param l the {@code long} to subtract. + * @return a {@code BigFraction} instance with the resulting values. + */ + public BigFraction subtract(final long l) { + return subtract(BigInteger.valueOf(l)); + } + + /** + * Subtracts the value of an {@link BigInteger} from the value of this + * {@code BigFraction}, returning the result in reduced form. + * + * @param bg the {@link BigInteger} to subtract, cannot be {@code null}. + * @return a {@code BigFraction} instance with the resulting values. + */ + public BigFraction subtract(final BigInteger bg) { + if (bg.signum() == 0) { + return this; + } + if (numerator.signum() == 0) { + return of(bg.negate()); + } + + return new BigFraction(numerator.subtract(denominator.multiply(bg)), denominator); + } + + /** + * Subtracts the value of another fraction from the value of this one, + * returning the result in reduced form. + * + * @param fraction {@link BigFraction} to subtract, must not be {@code null}. + * @return a {@link BigFraction} instance with the resulting values + */ + @Override + public BigFraction subtract(final BigFraction fraction) { + if (fraction.numerator.signum() == 0) { + return this; + } + if (numerator.signum() == 0) { + return fraction.negate(); + } + + final BigInteger num; + final BigInteger den; + 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); + } + + /** + * Multiply the value of this fraction by the passed {@code int}, returning + * the result in reduced form. + * + * @param i + * the {@code int} to multiply by. + * @return a {@link BigFraction} instance with the resulting values. + */ + @Override + public BigFraction multiply(final int i) { + if (i == 0 || numerator.signum() == 0) { + return ZERO; + } + + return multiply(BigInteger.valueOf(i)); + } + + /** + * Multiply the value of this fraction by the passed {@code long}, + * returning the result in reduced form. + * + * @param l + * the {@code long} to multiply by. + * @return a {@link BigFraction} instance with the resulting values. + */ + public BigFraction multiply(final long l) { + if (l == 0 || numerator.signum() == 0) { + return ZERO; + } + + return multiply(BigInteger.valueOf(l)); + } + + /** + * Multiplies the value of this fraction by the passed + * {@code BigInteger}, returning the result in reduced form. + * + * @param bg the {@code BigInteger} to multiply by. + * @return a {@code BigFraction} instance with the resulting values. + */ + public BigFraction multiply(final BigInteger bg) { + if (numerator.signum() == 0 || bg.signum() == 0) { + return ZERO; + } + return new BigFraction(bg.multiply(numerator), denominator); + } + + /** + * Multiplies the value of this fraction by another, returning the result in + * reduced form. + * + * @param fraction Fraction to multiply by, must not be {@code null}. + * @return a {@link BigFraction} instance with the resulting values. + */ + @Override + public BigFraction multiply(final BigFraction fraction) { + if (numerator.signum() == 0 || + fraction.numerator.signum() == 0) { + return ZERO; + } + return new BigFraction(numerator.multiply(fraction.numerator), + denominator.multiply(fraction.denominator)); } /** @@ -574,6 +837,24 @@ public final class BigFraction } /** + * Divide the value of this fraction by the passed {@code BigInteger}, + * ie {@code this * 1 / bg}, returning the result in reduced form. + * + * @param bg the {@code BigInteger} to divide by, must not be {@code null} + * @return a {@link BigFraction} instance with the resulting values + * @throws ArithmeticException if the value to divide by is zero + */ + public BigFraction divide(final BigInteger bg) { + if (bg.signum() == 0) { + throw new FractionException(FractionException.ERROR_ZERO_DENOMINATOR); + } + if (numerator.signum() == 0) { + return ZERO; + } + return new BigFraction(numerator, denominator.multiply(bg)); + } + + /** * Divide the value of this fraction by another, returning the result in * reduced form. * @@ -594,40 +875,205 @@ public final class BigFraction } /** - * Calculates the sign bit, the biased exponent and the significand for a - * binary floating-point representation of this {@code BigFraction} - * according to the IEEE 754 standard, and encodes these values into a {@code long} - * variable. The representative bits are arranged adjacent to each other and - * placed at the low-order end of the returned {@code long} value, with the - * least significant bits used for the significand, the next more - * significant bits for the exponent, and next more significant bit for the - * sign. - * - *

Warning: The arguments are not validated. + * Returns a {@code BigFraction} whose value is + * {@code (thisexponent)}, returning the result in reduced form. * - * @param exponentLength the number of bits allowed for the exponent; must be - * between 1 and 32 (inclusive), and must not be greater - * than {@code 63 - significandLength} - * @param significandLength the number of bits allowed for the significand - * (excluding the implicit leading 1-bit in - * normalized numbers, e.g. 52 for a double-precision - * floating-point number); must be between 1 and - * {@code 63 - exponentLength} (inclusive) - * @return the bits of an IEEE 754 binary floating-point representation of - * this fraction encoded in a {@code long}, as described above. + * @param exponent + * exponent to which this {@code BigFraction} is to be + * raised. + * @return \(\mathit{this}^{\mathit{exponent}}\). */ - private long toFloatingPointBits(int exponentLength, int significandLength) { - // Assume the following conditions: - //assert exponentLength >= 1; - //assert exponentLength <= 32; - //assert significandLength >= 1; - //assert significandLength <= 63 - exponentLength; - + @Override + public BigFraction pow(final int exponent) { + if (exponent == 0) { + return ONE; + } if (numerator.signum() == 0) { - return 0L; + return this; } - final long sign = (numerator.signum() * denominator.signum()) == -1 ? 1L : 0L; + if (exponent < 0) { + return new BigFraction(denominator.pow(-exponent), numerator.pow(-exponent)); + } + return new BigFraction(numerator.pow(exponent), denominator.pow(exponent)); + } + + /** + * Returns a {@code BigFraction} whose value is + * \(\mathit{this}^{\mathit{exponent}}\), returning the result in reduced form. + * + * @param exponent + * exponent to which this {@code BigFraction} is to be raised. + * @return \(\mathit{this}^{\mathit{exponent}}\) as a {@code BigFraction}. + */ + public BigFraction pow(final long exponent) { + if (exponent == 0) { + return ONE; + } + if (numerator.signum() == 0) { + return this; + } + + if (exponent < 0) { + return new BigFraction(ArithmeticUtils.pow(denominator, -exponent), + ArithmeticUtils.pow(numerator, -exponent)); + } + return new BigFraction(ArithmeticUtils.pow(numerator, exponent), + ArithmeticUtils.pow(denominator, exponent)); + } + + /** + * Returns a {@code BigFraction} whose value is + * \(\mathit{this}^{\mathit{exponent}}\), returning the result in reduced form. + * + * @param exponent + * exponent to which this {@code BigFraction} is to be raised. + * @return \(\mathit{this}^{\mathit{exponent}}\) as a {@code BigFraction}. + */ + public BigFraction pow(final BigInteger exponent) { + if (exponent.signum() == 0) { + return ONE; + } + if (numerator.signum() == 0) { + return this; + } + + if (exponent.signum() == -1) { + final BigInteger eNeg = exponent.negate(); + return new BigFraction(ArithmeticUtils.pow(denominator, eNeg), + ArithmeticUtils.pow(numerator, eNeg)); + } + return new BigFraction(ArithmeticUtils.pow(numerator, exponent), + ArithmeticUtils.pow(denominator, exponent)); + } + + /** + * Returns a {@code double} whose value is + * \(\mathit{this}^{\mathit{exponent}}\), returning the result in reduced form. + * + * @param exponent + * exponent to which this {@code BigFraction} is to be raised. + * @return \(\mathit{this}^{\mathit{exponent}}\). + */ + public double pow(final double exponent) { + return Math.pow(numerator.doubleValue(), exponent) / + Math.pow(denominator.doubleValue(), exponent); + } + + /** + * Returns the {@code String} representing this fraction. + * Uses: + *

+ * + * @return a string representation of the fraction. + */ + @Override + public String toString() { + final String str; + if (BigInteger.ONE.equals(denominator)) { + str = numerator.toString(); + } else if (BigInteger.ZERO.equals(numerator)) { + str = "0"; + } else { + str = numerator + " / " + denominator; + } + return str; + } + + /** + * Compares this object to another based on size. + * + * @param other Object to compare to, must not be {@code null}. + * @return -1 if this is less than {@code object}, +1 if this is greater + * than {@code object}, 0 if they are equal. + * + * @see Comparable#compareTo(Object) + */ + @Override + public int compareTo(final BigFraction other) { + final int lhsSigNum = signum(); + final int rhsSigNum = other.signum(); + + if (lhsSigNum != rhsSigNum) { + return (lhsSigNum > rhsSigNum) ? 1 : -1; + } + if (lhsSigNum == 0) { + return 0; + } + + final BigInteger nOd = numerator.multiply(other.denominator); + final BigInteger dOn = denominator.multiply(other.numerator); + return nOd.compareTo(dOn); + } + + /** + * 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. + * + * @param other {@inheritDoc} + * @return {@inheritDoc} + */ + @Override + public boolean equals(final Object other) { + if (this == other) { + return true; + } else if (other instanceof BigFraction) { + final BigFraction rhs = (BigFraction) other; + + if (signum() == rhs.signum()) { + return numerator.abs().equals(rhs.numerator.abs()) && + denominator.abs().equals(rhs.denominator.abs()); + } + } + + return false; + } + + @Override + public int hashCode() { + return 37 * (37 * 17 + numerator.hashCode()) + denominator.hashCode(); + } + + /** + * Calculates the sign bit, the biased exponent and the significand for a + * binary floating-point representation of this {@code BigFraction} + * according to the IEEE 754 standard, and encodes these values into a {@code long} + * variable. The representative bits are arranged adjacent to each other and + * placed at the low-order end of the returned {@code long} value, with the + * least significant bits used for the significand, the next more + * significant bits for the exponent, and next more significant bit for the + * sign. + * + *

Warning: The arguments are not validated. + * + * @param exponentLength the number of bits allowed for the exponent; must be + * between 1 and 32 (inclusive), and must not be greater + * than {@code 63 - significandLength} + * @param significandLength the number of bits allowed for the significand + * (excluding the implicit leading 1-bit in + * normalized numbers, e.g. 52 for a double-precision + * floating-point number); must be between 1 and + * {@code 63 - exponentLength} (inclusive) + * @return the bits of an IEEE 754 binary floating-point representation of + * this fraction encoded in a {@code long}, as described above. + */ + private long toFloatingPointBits(int exponentLength, int significandLength) { + // Assume the following conditions: + //assert exponentLength >= 1; + //assert exponentLength <= 32; + //assert significandLength >= 1; + //assert significandLength <= 63 - exponentLength; + + if (numerator.signum() == 0) { + return 0L; + } + + final long sign = (numerator.signum() * denominator.signum()) == -1 ? 1L : 0L; final BigInteger positiveNumerator = numerator.abs(); final BigInteger positiveDenominator = denominator.abs(); @@ -757,18 +1203,6 @@ public final class BigFraction } /** - * Gets the fraction as a {@code double}. This calculates the fraction as - * the numerator divided by denominator. - * - * @return the fraction as a {@code double} - * @see java.lang.Number#doubleValue() - */ - @Override - public double doubleValue() { - return Double.longBitsToDouble(toFloatingPointBits(11, 52)); - } - - /** * Rounds an integer to the specified power of two (i.e. the minimum number of * low-order bits that must be zero) and performs a right-shift by this * amount. The rounding mode applied is round to nearest, with ties rounding @@ -798,445 +1232,4 @@ public final class BigFraction return result; } - - /** - * 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. - * - * @param other - * fraction to test for equality to this fraction, can be - * {@code null}. - * @return true if two fractions are equal, false if object is - * {@code null}, 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) { - if (this == other) { - return true; - } else if (other instanceof BigFraction) { - final BigFraction rhs = (BigFraction) other; - - if (signum() == rhs.signum()) { - return numerator.abs().equals(rhs.numerator.abs()) && - denominator.abs().equals(rhs.denominator.abs()); - } else { - return false; - } - } - - return false; - } - - /** - * Retrieves the {@code float} value closest to this fraction. - * This calculates the fraction as numerator divided by denominator. - * - * @return the fraction as a {@code float}. - * @see java.lang.Number#floatValue() - */ - @Override - public float floatValue() { - return Float.intBitsToFloat((int) toFloatingPointBits(8, 23)); - } - - /** - * Access the denominator as a {@code BigInteger}. - * - * @return the denominator as a {@code BigInteger}. - */ - public BigInteger getDenominator() { - return denominator; - } - - /** - * Access the denominator as an {@code int}. - * - * @return the denominator as an {@code int}. - */ - public int getDenominatorAsInt() { - return denominator.intValue(); - } - - /** - * Access the denominator as a {@code long}. - * - * @return the denominator as a {@code long}. - */ - public long getDenominatorAsLong() { - return denominator.longValue(); - } - - /** - * Access the numerator as a {@code BigInteger}. - * - * @return the numerator as a {@code BigInteger}. - */ - public BigInteger getNumerator() { - return numerator; - } - - /** - * Access the numerator as an {@code int}. - * - * @return the numerator as an {@code int}. - */ - public int getNumeratorAsInt() { - return numerator.intValue(); - } - - /** - * Access the numerator as a {@code long}. - * - * @return the numerator as a {@code long}. - */ - public long getNumeratorAsLong() { - return numerator.longValue(); - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - return 37 * (37 * 17 + numerator.hashCode()) + denominator.hashCode(); - } - - /** - * Gets the fraction as an {@code int}. This returns the whole number part - * of the fraction. - * - * @return the whole number fraction part. - * @see java.lang.Number#intValue() - */ - @Override - public int intValue() { - return numerator.divide(denominator).intValue(); - } - - /** - * Gets the fraction as a {@code long}. This returns the whole number part - * of the fraction. - * - * @return the whole number fraction part. - * @see java.lang.Number#longValue() - */ - @Override - public long longValue() { - return numerator.divide(denominator).longValue(); - } - - /** - * Multiplies the value of this fraction by the passed - * {@code BigInteger}, returning the result in reduced form. - * - * @param bg the {@code BigInteger} to multiply by. - * @return a {@code BigFraction} instance with the resulting values. - */ - public BigFraction multiply(final BigInteger bg) { - if (numerator.signum() == 0 || bg.signum() == 0) { - return ZERO; - } - return new BigFraction(bg.multiply(numerator), denominator); - } - - /** - * Multiply the value of this fraction by the passed {@code int}, returning - * the result in reduced form. - * - * @param i - * the {@code int} to multiply by. - * @return a {@link BigFraction} instance with the resulting values. - */ - @Override - public BigFraction multiply(final int i) { - if (i == 0 || numerator.signum() == 0) { - return ZERO; - } - - return multiply(BigInteger.valueOf(i)); - } - - /** - * Multiply the value of this fraction by the passed {@code long}, - * returning the result in reduced form. - * - * @param l - * the {@code long} to multiply by. - * @return a {@link BigFraction} instance with the resulting values. - */ - public BigFraction multiply(final long l) { - if (l == 0 || numerator.signum() == 0) { - return ZERO; - } - - return multiply(BigInteger.valueOf(l)); - } - - /** - * Multiplies the value of this fraction by another, returning the result in - * reduced form. - * - * @param fraction Fraction to multiply by, must not be {@code null}. - * @return a {@link BigFraction} instance with the resulting values. - */ - @Override - public BigFraction multiply(final BigFraction fraction) { - if (numerator.signum() == 0 || - fraction.numerator.signum() == 0) { - return ZERO; - } - return new BigFraction(numerator.multiply(fraction.numerator), - denominator.multiply(fraction.denominator)); - } - - /** - * Retrieves the sign of this fraction. - * - * @return -1 if the value is strictly negative, 1 if it is strictly - * positive, 0 if it is 0. - */ - public int signum() { - final int numS = numerator.signum(); - final int denS = denominator.signum(); - - if ((numS > 0 && denS > 0) || - (numS < 0 && denS < 0)) { - return 1; - } else if (numS == 0) { - return 0; - } else { - return -1; - } - } - - /** - * Return the additive inverse of this fraction, returning the result in - * reduced form. - * - * @return the negation of this fraction. - */ - @Override - public BigFraction negate() { - return new BigFraction(numerator.negate(), denominator); - } - - /** - * Returns a {@code BigFraction} whose value is - * {@code (thisexponent)}, returning the result in reduced form. - * - * @param exponent - * exponent to which this {@code BigFraction} is to be - * raised. - * @return \(\mathit{this}^{\mathit{exponent}}\). - */ - @Override - public BigFraction pow(final int exponent) { - if (exponent == 0) { - return ONE; - } - if (numerator.signum() == 0) { - return this; - } - - if (exponent < 0) { - return new BigFraction(denominator.pow(-exponent), numerator.pow(-exponent)); - } - return new BigFraction(numerator.pow(exponent), denominator.pow(exponent)); - } - - /** - * Returns a {@code BigFraction} whose value is - * \(\mathit{this}^{\mathit{exponent}}\), returning the result in reduced form. - * - * @param exponent - * exponent to which this {@code BigFraction} is to be raised. - * @return \(\mathit{this}^{\mathit{exponent}}\) as a {@code BigFraction}. - */ - public BigFraction pow(final long exponent) { - if (exponent == 0) { - return ONE; - } - if (numerator.signum() == 0) { - return this; - } - - if (exponent < 0) { - return new BigFraction(ArithmeticUtils.pow(denominator, -exponent), - ArithmeticUtils.pow(numerator, -exponent)); - } - return new BigFraction(ArithmeticUtils.pow(numerator, exponent), - ArithmeticUtils.pow(denominator, exponent)); - } - - /** - * Returns a {@code BigFraction} whose value is - * \(\mathit{this}^{\mathit{exponent}}\), returning the result in reduced form. - * - * @param exponent - * exponent to which this {@code BigFraction} is to be raised. - * @return \(\mathit{this}^{\mathit{exponent}}\) as a {@code BigFraction}. - */ - public BigFraction pow(final BigInteger exponent) { - if (exponent.signum() == 0) { - return ONE; - } - if (numerator.signum() == 0) { - return this; - } - - if (exponent.signum() == -1) { - final BigInteger eNeg = exponent.negate(); - return new BigFraction(ArithmeticUtils.pow(denominator, eNeg), - ArithmeticUtils.pow(numerator, eNeg)); - } - return new BigFraction(ArithmeticUtils.pow(numerator, exponent), - ArithmeticUtils.pow(denominator, exponent)); - } - - /** - * Returns a {@code double} whose value is - * \(\mathit{this}^{\mathit{exponent}}\), returning the result in reduced form. - * - * @param exponent - * exponent to which this {@code BigFraction} is to be raised. - * @return \(\mathit{this}^{\mathit{exponent}}\). - */ - public double pow(final double exponent) { - return Math.pow(numerator.doubleValue(), exponent) / - Math.pow(denominator.doubleValue(), exponent); - } - - /** - * Return the multiplicative inverse of this fraction. - * - * @return the reciprocal fraction. - */ - @Override - public BigFraction reciprocal() { - return new BigFraction(denominator, numerator); - } - - /** - * Subtracts the value of an {@link BigInteger} from the value of this - * {@code BigFraction}, returning the result in reduced form. - * - * @param bg the {@link BigInteger} to subtract, cannot be {@code null}. - * @return a {@code BigFraction} instance with the resulting values. - */ - public BigFraction subtract(final BigInteger bg) { - if (bg.signum() == 0) { - return this; - } - if (numerator.signum() == 0) { - return of(bg.negate()); - } - - return new BigFraction(numerator.subtract(denominator.multiply(bg)), denominator); - } - - /** - * Subtracts the value of an {@code integer} from the value of this - * {@code BigFraction}, returning the result in reduced form. - * - * @param i the {@code integer} to subtract. - * @return a {@code BigFraction} instance with the resulting values. - */ - public BigFraction subtract(final int i) { - return subtract(BigInteger.valueOf(i)); - } - - /** - * Subtracts the value of a {@code long} from the value of this - * {@code BigFraction}, returning the result in reduced form. - * - * @param l the {@code long} to subtract. - * @return a {@code BigFraction} instance with the resulting values. - */ - public BigFraction subtract(final long l) { - return subtract(BigInteger.valueOf(l)); - } - - /** - * Subtracts the value of another fraction from the value of this one, - * returning the result in reduced form. - * - * @param fraction {@link BigFraction} to subtract, must not be {@code null}. - * @return a {@link BigFraction} instance with the resulting values - */ - @Override - public BigFraction subtract(final BigFraction fraction) { - if (fraction.numerator.signum() == 0) { - return this; - } - if (numerator.signum() == 0) { - return fraction.negate(); - } - - final BigInteger num; - final BigInteger den; - 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); - } - - /** - * Returns the {@code String} representing this fraction, ie - * "num / dem" or just "num" if the denominator is one. - * - * @return a string representation of the fraction. - * @see java.lang.Object#toString() - */ - @Override - public String toString() { - final String str; - if (BigInteger.ONE.equals(denominator)) { - str = numerator.toString(); - } else if (BigInteger.ZERO.equals(numerator)) { - str = "0"; - } else { - str = numerator + " / " + denominator; - } - return str; - } - - /** {@inheritDoc} */ - @Override - public BigFraction zero() { - return ZERO; - } - - /** {@inheritDoc} */ - @Override - public BigFraction one() { - return ONE; - } - - /** - * Parses a string that would be produced by {@link #toString()} - * and instantiates the corresponding object. - * - * @param s String representation. - * @return an instance. - * @throws NumberFormatException if the string does not conform - * to the specification. - */ - public static BigFraction parse(String s) { - s = s.replace(",", ""); - final int slashLoc = s.indexOf('/'); - // if no slash, parse as single number - if (slashLoc == -1) { - return BigFraction.of(new BigInteger(s.trim())); - } else { - final BigInteger num = new BigInteger( - s.substring(0, slashLoc).trim()); - final BigInteger denom = new BigInteger(s.substring(slashLoc + 1).trim()); - return of(num, denom); - } - } } diff --git a/commons-numbers-fraction/src/main/java/org/apache/commons/numbers/fraction/Fraction.java b/commons-numbers-fraction/src/main/java/org/apache/commons/numbers/fraction/Fraction.java index 00dd80e..8135438 100644 --- a/commons-numbers-fraction/src/main/java/org/apache/commons/numbers/fraction/Fraction.java +++ b/commons-numbers-fraction/src/main/java/org/apache/commons/numbers/fraction/Fraction.java @@ -35,23 +35,61 @@ public final class Fraction implements Comparable, NativeOperators, Serializable { - /** A fraction representing "1". */ - public static final Fraction ONE = new Fraction(1, 1); - /** A fraction representing "0". */ public static final Fraction ZERO = new Fraction(0, 1); + /** A fraction representing "1". */ + public static final Fraction ONE = new Fraction(1, 1); + /** Serializable version identifier. */ private static final long serialVersionUID = 20190701L; /** The default epsilon used for convergence. */ private static final double DEFAULT_EPSILON = 1e-5; + /** The numerator of this fraction reduced to lowest terms. */ + private final int numerator; + /** The denominator of this fraction reduced to lowest terms. */ private final int denominator; - /** The numerator of this fraction reduced to lowest terms. */ - private final int numerator; + + /** + * Constructs an instance. + * + * @param num Numerator. + * @param den Denominator. + * @throws ArithmeticException if the denominator is {@code zero} + * or if integer overflow occurs. + */ + private Fraction(int num, int den) { + if (den == 0) { + throw new ArithmeticException("division by zero"); + } + + if (num == den) { + numerator = 1; + denominator = 1; + } else { + // If num and den are both 2^-31, or if one is 0 and the other is 2^-31, + // the calculation of the gcd below will fail. Ensure that this does not + // happen by dividing both by 2 in case both are even. + if (((num | den) & 1) == 0) { + num >>= 1; + den >>= 1; + } + + // Reduce numerator and denominator by greatest common divisor. + final int d = ArithmeticUtils.gcd(num, den); + if (d > 1) { + num /= d; + den /= d; + } + + numerator = num; + denominator = den; + } + } /** * Create a fraction given the double value and either the maximum error @@ -85,7 +123,10 @@ public final class Fraction * @throws ArithmeticException if the continued fraction failed * to converge. */ - private Fraction(double value, double epsilon, int maxDenominator, int maxIterations) { + private Fraction(final double value, + final double epsilon, + final int maxDenominator, + final int maxIterations) { final long overflow = Integer.MAX_VALUE; double r0 = value; long a0 = (long)Math.floor(r0); @@ -157,43 +198,6 @@ public final class Fraction } /** - * Constructs an instance. - * - * @param num Numerator. - * @param den Denominator. - * @throws ArithmeticException if the denominator is {@code zero} - * or if integer overflow occurs. - */ - private Fraction(int num, int den) { - if (den == 0) { - throw new ArithmeticException("division by zero"); - } - - if (num == den) { - numerator = 1; - denominator = 1; - } else { - // If num and den are both 2^-31, or if one is 0 and the other is 2^-31, - // the calculation of the gcd below will fail. Ensure that this does not - // happen by dividing both by 2 in case both are even. - if (((num | den) & 1) == 0) { - num >>= 1; - den >>= 1; - } - - // Reduce numerator and denominator by greatest common divisor. - final int d = ArithmeticUtils.gcd(num, den); - if (d > 1) { - num /= d; - den /= d; - } - - numerator = num; - denominator = den; - } - } - - /** * Create a fraction given the double value. * * @param value Value to convert to a fraction. @@ -201,7 +205,7 @@ public final class Fraction * converge. * @return a new instance. */ - public static Fraction from(double value) { + public static Fraction from(final double value) { return from(value, DEFAULT_EPSILON, 100); } @@ -223,7 +227,9 @@ public final class Fraction * converge. * @return a new instance. */ - public static Fraction from(double value, double epsilon, int maxIterations) { + public static Fraction from(final double value, + final double epsilon, + final int maxIterations) { return new Fraction(value, epsilon, Integer.MAX_VALUE, maxIterations); } @@ -243,7 +249,8 @@ public final class Fraction * converge. * @return a new instance. */ - public static Fraction from(double value, int maxDenominator) { + public static Fraction from(final double value, + final int maxDenominator) { return new Fraction(value, 0, maxDenominator, 100); } @@ -253,7 +260,7 @@ public final class Fraction * @param num Numerator. * @return a new instance. */ - public static Fraction of(int num) { + public static Fraction of(final int num) { return of(num, 1); } @@ -267,11 +274,73 @@ public final class Fraction * or if integer overflow occurs. * @return a new instance. */ - public static Fraction of(int num, int den) { + public static Fraction of(final int num, final int den) { return new Fraction(num, den); } /** + * Parses a string that would be produced by {@link #toString()} + * and instantiates the corresponding object. + * + * @param s String representation. + * @return an instance. + * @throws NumberFormatException if the string does not conform to the + * specification. + */ + public static Fraction parse(String s) { + final int slashLoc = s.indexOf('/'); + // if no slash, parse as single number + if (slashLoc == -1) { + return Fraction.of(Integer.parseInt(s.trim())); + } else { + final int num = Integer.parseInt(s.substring(0, slashLoc).trim()); + final int denom = Integer.parseInt(s.substring(slashLoc + 1).trim()); + return of(num, denom); + } + } + + @Override + public Fraction zero() { + return ZERO; + } + + @Override + public Fraction one() { + return ONE; + } + + /** + * @return the numerator. + */ + public int getNumerator() { + return numerator; + } + + /** + * @return the denominator. + */ + public int getDenominator() { + return denominator; + } + + /** + * Retrieves the sign of this fraction. + * + * @return -1 if the value is strictly negative, 1 if it is strictly + * positive, 0 if it is 0. + */ + public int signum() { + if ((numerator > 0 && denominator > 0) || + (numerator < 0 && denominator < 0)) { + return 1; + } else if (numerator == 0) { + return 0; + } else { + return -1; + } + } + + /** * Returns the absolute value of this fraction. * * @return the absolute value. @@ -283,56 +352,36 @@ public final class Fraction } /** - * Compares this object to another based on size. + * Computes the additive inverse of this fraction. * - * @param other Object to compare to. - * @return -1 if this is less than {@code object}, +1 if this is greater - * than {@code object}, 0 if they are equal. + * @return the opposite. */ @Override - public int compareTo(Fraction other) { - return Long.compare(((long) numerator) * other.denominator, - ((long) denominator) * other.numerator); + public Fraction negate() { + return numerator == Integer.MIN_VALUE ? + new Fraction(numerator, -denominator) : + new Fraction(-numerator, denominator); } /** - * Retrieves the {@code double} value closest to this fraction. - * This calculates the fraction as numerator divided by denominator. + * Computes the multiplicative inverse of this fraction. * - * @return the fraction as a {@code double}. + * @return the reciprocal. */ @Override - public double doubleValue() { - return (double) numerator / (double) denominator; + public Fraction reciprocal() { + return new Fraction(denominator, numerator); } /** - * 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. - * @param other Fraction to test for equality with. - * @return {@code true} if the two fractions are equal, {@code false} - * otherwise. + * Retrieves the {@code double} value closest to this fraction. + * This calculates the fraction as numerator divided by denominator. + * + * @return the fraction as a {@code double}. */ @Override - public boolean equals(Object other) { - if (this == other) { - return true; - } - - if (other instanceof Fraction) { - // Since fractions are always in lowest terms, numerators and - // denominators can be compared directly for equality. - final Fraction rhs = (Fraction) other; - if (signum() == rhs.signum()) { - return Math.abs(numerator) == Math.abs(rhs.numerator) && - Math.abs(denominator) == Math.abs(rhs.denominator); - } else { - return false; - } - } - - return false; + public double doubleValue() { + return (double) numerator / (double) denominator; } /** @@ -347,26 +396,6 @@ public final class Fraction } /** - * @return the denominator. - */ - public int getDenominator() { - return denominator; - } - - /** - * @return the numerator. - */ - public int getNumerator() { - return numerator; - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - return 37 * (37 * 17 + numerator) + denominator; - } - - /** * Retrieves the whole number part of the fraction. * * @return the largest {@code int} value that is not larger than @@ -389,42 +418,13 @@ public final class Fraction } /** - * Retrieves the sign of this fraction. - * - * @return -1 if the value is strictly negative, 1 if it is strictly - * positive, 0 if it is 0. - */ - public int signum() { - if ((numerator > 0 && denominator > 0) || - (numerator < 0 && denominator < 0)) { - return 1; - } else if (numerator == 0) { - return 0; - } else { - return -1; - } - } - - /** - * Computes the additive inverse of this fraction. - * - * @return the opposite. - */ - @Override - public Fraction negate() { - return numerator == Integer.MIN_VALUE ? - new Fraction(numerator, -denominator) : - new Fraction(-numerator, denominator); - } - - /** - * Computes the multiplicative inverse of this fraction. + * Adds an integer to the fraction. * - * @return the reciprocal. + * @param i Value to add. + * @return {@code this + i}. */ - @Override - public Fraction reciprocal() { - return new Fraction(denominator, numerator); + public Fraction add(final int i) { + return new Fraction(numerator + i * denominator, denominator); } /** @@ -443,13 +443,13 @@ public final class Fraction } /** - * Adds an integer to the fraction. + * Subtracts an integer from this fraction. * - * @param i Value to add. - * @return {@code this + i}. + * @param i Value to subtract. + * @return {@code this - i}. */ - public Fraction add(final int i) { - return new Fraction(numerator + i * denominator, denominator); + public Fraction subtract(final int i) { + return new Fraction(numerator - i * denominator, denominator); } /** @@ -467,16 +467,6 @@ public final class Fraction } /** - * Subtracts an integer from this fraction. - * - * @param i Value to subtract. - * @return {@code this - i}. - */ - public Fraction subtract(final int i) { - return new Fraction(numerator - i * denominator, denominator); - } - - /** * Implements add and subtract using algorithm described in Knuth 4.5.1. * * @param fraction Fraction to add or subtract. @@ -529,6 +519,17 @@ public final class Fraction } /** + * Multiplies the fraction by an integer. + * + * @param i Value to multiply by. + * @return {@code this * i}. + */ + @Override + public Fraction multiply(final int i) { + return multiply(of(i)); + } + + /** * Multiplies the value of this fraction by another, returning the * result in reduced form. * @@ -553,14 +554,13 @@ public final class Fraction } /** - * Multiplies the fraction by an integer. + * Divides the fraction by an integer. * - * @param i Value to multiply by. + * @param i Value to divide by. * @return {@code this * i}. */ - @Override - public Fraction multiply(final int i) { - return multiply(of(i)); + public Fraction divide(final int i) { + return divide(of(i)); } /** @@ -583,36 +583,38 @@ public final class Fraction } /** - * Divides the fraction by an integer. + * {@inheritDoc} * - * @param i Value to divide by. - * @return {@code this * i}. - */ - public Fraction divide(final int i) { - return divide(of(i)); - } - - /** - * @param n Power. - * @return thisn. + * @param exponent {@inheritDoc} + * @return thisexponent. */ @Override - public Fraction pow(final int n) { - if (n == 0) { + public Fraction pow(final int exponent) { + if (exponent == 0) { return ONE; } if (numerator == 0) { return this; } - return n < 0 ? - new Fraction(ArithmeticUtils.pow(denominator, -n), - ArithmeticUtils.pow(numerator, -n)) : - new Fraction(ArithmeticUtils.pow(numerator, n), - ArithmeticUtils.pow(denominator, n)); + return exponent < 0 ? + new Fraction(ArithmeticUtils.pow(denominator, -exponent), + ArithmeticUtils.pow(numerator, -exponent)) : + new Fraction(ArithmeticUtils.pow(numerator, exponent), + ArithmeticUtils.pow(denominator, exponent)); } - /** {@inheritDoc} */ + /** + * Returns the {@code String} representing this fraction. + * Uses: + *

+ * + * @return a string representation of the fraction. + */ @Override public String toString() { final String str; @@ -626,36 +628,46 @@ public final class Fraction return str; } - /** {@inheritDoc} */ - @Override - public Fraction zero() { - return ZERO; - } - - /** {@inheritDoc} */ + /** + * Compares this object with the specified object for order using the signed magnitude. + * + * @param other {@inheritDoc} + * @return {@inheritDoc} + */ @Override - public Fraction one() { - return ONE; + public int compareTo(Fraction other) { + return Long.compare(((long) numerator) * other.denominator, + ((long) denominator) * other.numerator); } /** - * Parses a string that would be produced by {@link #toString()} - * and instantiates the corresponding object. + * Test for equality with another object. If the other object is a {@code Fraction} then a + * comparison is made of the sign and magnitude; otherwise {@code false} is returned. * - * @param s String representation. - * @return an instance. - * @throws NumberFormatException if the string does not conform to the - * specification. + * @param other {@inheritDoc} + * @return {@inheritDoc} */ - public static Fraction parse(String s) { - final int slashLoc = s.indexOf('/'); - // if no slash, parse as single number - if (slashLoc == -1) { - return Fraction.of(Integer.parseInt(s.trim())); - } else { - final int num = Integer.parseInt(s.substring(0, slashLoc).trim()); - final int denom = Integer.parseInt(s.substring(slashLoc + 1).trim()); - return of(num, denom); + @Override + public boolean equals(Object other) { + if (this == other) { + return true; } + + if (other instanceof Fraction) { + // Since fractions are always in lowest terms, numerators and + // denominators can be compared directly for equality. + final Fraction rhs = (Fraction) other; + if (signum() == rhs.signum()) { + return Math.abs(numerator) == Math.abs(rhs.numerator) && + Math.abs(denominator) == Math.abs(rhs.denominator); + } + } + + return false; + } + + @Override + public int hashCode() { + return 37 * (37 * 17 + numerator) + denominator; } }