예제 #1
0
 /**
  * Divide the value of this fraction by another.
  *
  * @param fraction the fraction to divide by, must not be {@code null}
  * @return a {@code Fraction} instance with the resulting values
  * @throws IllegalArgumentException if the fraction is {@code null}
  * @throws MathArithmeticException if the fraction to divide by is zero
  * @throws MathArithmeticException if the resulting numerator or denominator exceeds {@code
  *     Integer.MAX_VALUE}
  */
 public Fraction divide(Fraction fraction) {
   if (fraction == null) {
     throw new NullArgumentException(LocalizedFormats.FRACTION);
   }
   if (fraction.numerator == 0) {
     throw new MathArithmeticException(
         LocalizedFormats.ZERO_FRACTION_TO_DIVIDE_BY, fraction.numerator, fraction.denominator);
   }
   return multiply(fraction.reciprocal());
 }
예제 #2
0
  /**
   * Implement add and subtract using algorithm described in Knuth 4.5.1.
   *
   * @param fraction the fraction to subtract, must not be {@code null}
   * @param isAdd true to add, false to subtract
   * @return a {@code Fraction} instance with the resulting values
   * @throws NullArgumentException if the fraction is {@code null}
   * @throws MathArithmeticException if the resulting numerator or denominator cannot be represented
   *     in an {@code int}.
   */
  private Fraction addSub(Fraction fraction, boolean isAdd) {
    if (fraction == null) {
      throw new NullArgumentException(LocalizedFormats.FRACTION);
    }
    // zero is identity for addition.
    if (numerator == 0) {
      return isAdd ? fraction : fraction.negate();
    }
    if (fraction.numerator == 0) {
      return this;
    }
    // if denominators are randomly distributed, d1 will be 1 about 61%
    // of the time.
    int d1 = ArithmeticUtils.gcd(denominator, fraction.denominator);
    if (d1 == 1) {
      // result is ( (u*v' +/- u'v) / u'v')
      int uvp = ArithmeticUtils.mulAndCheck(numerator, fraction.denominator);
      int upv = ArithmeticUtils.mulAndCheck(fraction.numerator, denominator);
      return new Fraction(
          isAdd ? ArithmeticUtils.addAndCheck(uvp, upv) : ArithmeticUtils.subAndCheck(uvp, upv),
          ArithmeticUtils.mulAndCheck(denominator, fraction.denominator));
    }
    // the quantity 't' requires 65 bits of precision; see knuth 4.5.1
    // exercise 7.  we're going to use a BigInteger.
    // t = u(v'/d1) +/- v(u'/d1)
    BigInteger uvp =
        BigInteger.valueOf(numerator).multiply(BigInteger.valueOf(fraction.denominator / d1));
    BigInteger upv =
        BigInteger.valueOf(fraction.numerator).multiply(BigInteger.valueOf(denominator / d1));
    BigInteger t = isAdd ? uvp.add(upv) : uvp.subtract(upv);
    // but d2 doesn't need extra precision because
    // d2 = gcd(t,d1) = gcd(t mod d1, d1)
    int tmodd1 = t.mod(BigInteger.valueOf(d1)).intValue();
    int d2 = (tmodd1 == 0) ? d1 : ArithmeticUtils.gcd(tmodd1, d1);

    // result is (t/d2) / (u'/d1)(v'/d2)
    BigInteger w = t.divide(BigInteger.valueOf(d2));
    if (w.bitLength() > 31) {
      throw new MathArithmeticException(LocalizedFormats.NUMERATOR_OVERFLOW_AFTER_MULTIPLY, w);
    }
    return new Fraction(
        w.intValue(), ArithmeticUtils.mulAndCheck(denominator / d1, fraction.denominator / d2));
  }