示例#1
0
文件: BigFraction.java 项目: ldez/svm
 /**
  * Returns the value of this fraction. If this value is beyond the range of a double,
  * Double.INFINITY or Double.NEGATIVE_INFINITY will be returned.
  */
 @Override
 public double doubleValue() {
   // note: must use precision+2 so that new BigFraction(d).doubleValue()
   // == d,
   // for all possible double values.
   return this.toBigDecimal(MathContext.DECIMAL64.getPrecision() + 2).doubleValue();
 }
示例#2
0
文件: BigFraction.java 项目: ldez/svm
  /**
   * Returns a BigDecimal representation of this fraction. If possible, the returned value will be
   * exactly equal to the fraction. If not, the BigDecimal will have a scale large enough to hold
   * the same number of significant figures as both numerator and denominator, or the equivalent of
   * a double-precision number, whichever is more.
   */
  public BigDecimal toBigDecimal() {
    // Implementation note: A fraction can be represented exactly in base-10
    // iff its
    // denominator is of the form 2^a * 5^b, where a and b are nonnegative
    // integers.
    // (In other words, if there are no prime factors of the denominator
    // except for
    // 2 and 5, or if the denominator is 1). So to determine if this
    // denominator is
    // of this form, continually divide by 2 to get the number of 2's, and
    // then
    // continually divide by 5 to get the number of 5's. Afterward, if the
    // denominator
    // is 1 then there are no other prime factors.

    // Note: number of 2's is given by the number of trailing 0 bits in the
    // number
    final int twos = this.denominator.getLowestSetBit();
    BigInteger tmpDen = this.denominator.shiftRight(twos); // x / 2^n === x >> n

    int fives = 0;
    BigInteger[] divMod = null;

    // while(tmpDen % 5 == 0) { tmpDen /= 5; fives++; }
    while (BigInteger.ZERO.equals((divMod = tmpDen.divideAndRemainder(BIGINT_FIVE))[1])) {
      tmpDen = divMod[0];
      fives++;
    }

    if (BigInteger.ONE.equals(tmpDen)) {
      // This fraction will terminate in base 10, so it can be represented
      // exactly as
      // a BigDecimal. We would now like to make the fraction of the form
      // unscaled / 10^scale. We know that 2^x * 5^x = 10^x, and our
      // denominator is
      // in the form 2^twos * 5^fives. So use max(twos, fives) as the
      // scale, and
      // multiply the numerator and deminator by the appropriate number of
      // 2's or 5's
      // such that the denominator is of the form 2^scale * 5^scale. (Of
      // course, we
      // only have to actually multiply the numerator, since all we need
      // for the
      // BigDecimal constructor is the scale.)
      BigInteger unscaled = this.numerator;
      final int scale = Math.max(twos, fives);

      if (twos < fives) {
        unscaled = unscaled.shiftLeft(fives - twos); // x
      } else if (fives < twos) {
        unscaled = unscaled.multiply(BIGINT_FIVE.pow(twos - fives));
      }

      return new BigDecimal(unscaled, scale);
    }

    // else: this number will repeat infinitely in base-10. So try to figure
    // out
    // a good number of significant digits. Start with the number of digits
    // required
    // to represent the numerator and denominator in base-10, which is given
    // by
    // bitLength / log[2](10). (bitLenth is the number of digits in base-2).
    final double LG10 = 3.321928094887362; // Precomputed ln(10)/ln(2),
    // a.k.a. log[2](10)
    int precision = Math.max(this.numerator.bitLength(), this.denominator.bitLength());
    precision = (int) Math.ceil(precision / LG10);

    // If the precision is less than that of a double, use double-precision
    // so
    // that the result will be at least as accurate as a cast to a double.
    // For
    // example, with the fraction 1/3, precision will be 1, giving a result
    // of
    // 0.3. This is quite a bit different from what a user would expect.
    if (precision < MathContext.DECIMAL64.getPrecision() + 2) {
      precision = MathContext.DECIMAL64.getPrecision() + 2;
    }

    return this.toBigDecimal(precision);
  }