/**
  * Multiplies the value of this fraction by another, returning the result in reduced form.
  *
  * @param fraction the fraction to multiply by, must not be <code>null</code>
  * @return a <code>Fraction</code> instance with the resulting values
  * @throws IllegalArgumentException if the fraction is <code>null</code>
  * @throws ArithmeticException if the resulting numerator or denominator exceeds <code>
  *     Integer.MAX_VALUE</code>
  */
 public Fraction multiply(Fraction fraction) {
   if (fraction == null) {
     throw MathRuntimeException.createIllegalArgumentException("null fraction");
   }
   if (numerator == 0 || fraction.numerator == 0) {
     return ZERO;
   }
   // knuth 4.5.1
   // make sure we don't overflow unless the result *must* overflow.
   int d1 = MathUtils.gcd(numerator, fraction.denominator);
   int d2 = MathUtils.gcd(fraction.numerator, denominator);
   return getReducedFraction(
       MathUtils.mulAndCheck(numerator / d1, fraction.numerator / d2),
       MathUtils.mulAndCheck(denominator / d2, fraction.denominator / d1));
 }
 /**
  * Creates a <code>Fraction</code> instance with the 2 parts of a fraction Y/Z.
  *
  * <p>Any negative signs are resolved to be on the numerator.
  *
  * @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 Fraction getReducedFraction(int numerator, int denominator) {
   if (denominator == 0) {
     throw MathRuntimeException.createArithmeticException(
         "zero denominator in fraction {0}/{1}", numerator, denominator);
   }
   if (numerator == 0) {
     return ZERO; // normalize zero.
   }
   // allow 2^k/-2^31 as a valid fraction (where k>0)
   if (denominator == Integer.MIN_VALUE && (numerator & 1) == 0) {
     numerator /= 2;
     denominator /= 2;
   }
   if (denominator < 0) {
     if (numerator == Integer.MIN_VALUE || denominator == Integer.MIN_VALUE) {
       throw MathRuntimeException.createArithmeticException(
           "overflow in fraction {0}/{1}, cannot negate", numerator, denominator);
     }
     numerator = -numerator;
     denominator = -denominator;
   }
   // simplify fraction.
   int gcd = MathUtils.gcd(numerator, denominator);
   numerator /= gcd;
   denominator /= gcd;
   return new Fraction(numerator, denominator);
 }
  /**
   * Create a fraction given the numerator and denominator. The fraction is reduced to lowest terms.
   *
   * @param num the numerator.
   * @param den the denominator.
   * @throws ArithmeticException if the denominator is <code>zero</code>
   */
  public Fraction(int num, int den) {
    if (den == 0) {
      throw MathRuntimeException.createArithmeticException(
          "zero denominator in fraction {0}/{1}", num, den);
    }
    if (den < 0) {
      if (num == Integer.MIN_VALUE || den == Integer.MIN_VALUE) {
        throw MathRuntimeException.createArithmeticException(
            "overflow in fraction {0}/{1}, cannot negate", num, den);
      }
      num = -num;
      den = -den;
    }
    // reduce numerator and denominator by greatest common denominator.
    final int d = MathUtils.gcd(num, den);
    if (d > 1) {
      num /= d;
      den /= d;
    }

    // move sign to numerator.
    if (den < 0) {
      num = -num;
      den = -den;
    }
    this.numerator = num;
    this.denominator = den;
  }
Exemple #4
0
 /**
  * Creates a <code>Fraction</code> instance with the 2 parts of a fraction Y/Z.
  *
  * <p>Any negative signs are resolved to be on the numerator.
  *
  * @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 Fraction getReducedFraction(int numerator, int denominator) {
   if (denominator == 0) {
     throw MathRuntimeException.createArithmeticException(
         ZERO_DENOMINATOR_MESSAGE, numerator, denominator);
   }
   if (numerator == 0) {
     return ZERO; // normalize zero.
   }
   // allow 2^k/-2^31 as a valid fraction (where k>0)
   if (denominator == Integer.MIN_VALUE && (numerator & 1) == 0) {
     numerator /= 2;
     denominator /= 2;
   }
   if (denominator < 0) {
     if (numerator == Integer.MIN_VALUE || denominator == Integer.MIN_VALUE) {
       throw MathRuntimeException.createArithmeticException(
           OVERFLOW_MESSAGE, numerator, denominator);
     }
     numerator = -numerator;
     denominator = -denominator;
   }
   // simplify fraction.
   int gcd = MathUtils.gcd(numerator, denominator);
   numerator /= gcd;
   denominator /= gcd;
   return new Fraction(numerator, denominator);
 }
Exemple #5
0
  /**
   * Create a fraction given the numerator and denominator. The fraction is reduced to lowest terms.
   *
   * @param num the numerator.
   * @param den the denominator.
   * @throws ArithmeticException if the denominator is <code>zero</code>
   */
  public Fraction(int num, int den) {
    if (den == 0) {
      throw MathRuntimeException.createArithmeticException(ZERO_DENOMINATOR_MESSAGE, num, den);
    }
    if (den < 0) {
      if (num == Integer.MIN_VALUE || den == Integer.MIN_VALUE) {
        throw MathRuntimeException.createArithmeticException(OVERFLOW_MESSAGE, num, den);
      }
      num = -num;
      den = -den;
    }
    // reduce numerator and denominator by greatest common denominator.
    final int d = MathUtils.gcd(num, den);
    if (d > 1) {
      num /= d;
      den /= d;
    }

    // move sign to numerator.
    if (den < 0) {
      num = -num;
      den = -den;
    }
    this.numerator = num;
    this.denominator = den;
  }
  /**
   * Implement add and subtract using algorithm described in Knuth 4.5.1.
   *
   * @param fraction the fraction to subtract, must not be <code>null</code>
   * @param isAdd true to add, false to subtract
   * @return a <code>Fraction</code> instance with the resulting values
   * @throws IllegalArgumentException if the fraction is <code>null</code>
   * @throws ArithmeticException if the resulting numerator or denominator cannot be represented in
   *     an <code>int</code>.
   */
  private Fraction addSub(Fraction fraction, boolean isAdd) {
    if (fraction == null) {
      throw MathRuntimeException.createIllegalArgumentException("null 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 = MathUtils.gcd(denominator, fraction.denominator);
    if (d1 == 1) {
      // result is ( (u*v' +/- u'v) / u'v')
      int uvp = MathUtils.mulAndCheck(numerator, fraction.denominator);
      int upv = MathUtils.mulAndCheck(fraction.numerator, denominator);
      return new Fraction(
          isAdd ? MathUtils.addAndCheck(uvp, upv) : MathUtils.subAndCheck(uvp, upv),
          MathUtils.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 : MathUtils.gcd(tmodd1, d1);

    // result is (t/d2) / (u'/d1)(v'/d2)
    BigInteger w = t.divide(BigInteger.valueOf(d2));
    if (w.bitLength() > 31) {
      throw MathRuntimeException.createArithmeticException(
          "overflow, numerator too large after multiply: {0}", w);
    }
    return new Fraction(
        w.intValue(), MathUtils.mulAndCheck(denominator / d1, fraction.denominator / d2));
  }