/** * 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(); }
/** * 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); }