| /* |
| * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| package jdk.nashorn.internal.runtime; |
| |
| import java.math.BigInteger; |
| |
| /** |
| * JavaScript number to string conversion, refinement of sun.misc.FloatingDecimal. |
| */ |
| public final class NumberToString { |
| /** Is not a number flag */ |
| private final boolean isNaN; |
| |
| /** Is a negative number flag. */ |
| private boolean isNegative; |
| |
| /** Decimal exponent value (for E notation.) */ |
| private int decimalExponent; |
| |
| /** Actual digits. */ |
| private char digits[]; |
| |
| /** Number of digits to use. (nDigits <= digits.length). */ |
| private int nDigits; |
| |
| /* |
| * IEEE-754 constants. |
| */ |
| |
| //private static final long signMask = 0x8000000000000000L; |
| private static final int expMask = 0x7FF; |
| private static final long fractMask = 0x000F_FFFF_FFFF_FFFFL; |
| private static final int expShift = 52; |
| private static final int expBias = 1_023; |
| private static final long fractHOB = (1L << expShift); |
| private static final long expOne = ((long)expBias) << expShift; |
| private static final int maxSmallBinExp = 62; |
| private static final int minSmallBinExp = -(63 / 3); |
| |
| /** Powers of 5 fitting a long. */ |
| private static final long powersOf5[] = { |
| 1L, |
| 5L, |
| 5L * 5, |
| 5L * 5 * 5, |
| 5L * 5 * 5 * 5, |
| 5L * 5 * 5 * 5 * 5, |
| 5L * 5 * 5 * 5 * 5 * 5, |
| 5L * 5 * 5 * 5 * 5 * 5 * 5, |
| 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5, |
| 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, |
| 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, |
| 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, |
| 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, |
| 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, |
| 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, |
| 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, |
| 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, |
| 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, |
| 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, |
| 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, |
| 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, |
| 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, |
| 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, |
| 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, |
| 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, |
| 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, |
| 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 |
| }; |
| |
| // Approximately ceil(log2(longPowers5[i])). |
| private static final int nBitsPowerOf5[] = { |
| 0, |
| 3, |
| 5, |
| 7, |
| 10, |
| 12, |
| 14, |
| 17, |
| 19, |
| 21, |
| 24, |
| 26, |
| 28, |
| 31, |
| 33, |
| 35, |
| 38, |
| 40, |
| 42, |
| 45, |
| 47, |
| 49, |
| 52, |
| 54, |
| 56, |
| 59, |
| 61 |
| }; |
| |
| /** Digits used for infinity result. */ |
| private static final char infinityDigits[] = { 'I', 'n', 'f', 'i', 'n', 'i', 't', 'y' }; |
| |
| /** Digits used for NaN result. */ |
| private static final char nanDigits[] = { 'N', 'a', 'N' }; |
| |
| /** Zeros used to pad result. */ |
| private static final char zeroes[] = { '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0' }; |
| |
| |
| /** |
| * Convert a number into a JavaScript string. |
| * @param value Double to convert. |
| * @return JavaScript formated number. |
| */ |
| public static String stringFor(final double value) { |
| return new NumberToString(value).toString(); |
| } |
| |
| /* |
| * Constructor. |
| */ |
| |
| private NumberToString(final double value) { |
| // Double as bits. |
| long bits = Double.doubleToLongBits(value); |
| |
| // Get upper word. |
| final int upper = (int)(bits >> 32); |
| |
| // Detect sign. |
| isNegative = upper < 0; |
| |
| // Extract exponent. |
| int exponent = (upper >> (expShift - 32)) & expMask; |
| |
| // Clear sign and exponent. |
| bits &= fractMask; |
| |
| // Detect NaN. |
| if (exponent == expMask) { |
| isNaN = true; |
| |
| // Detect Infinity. |
| if (bits == 0L) { |
| digits = infinityDigits; |
| } else { |
| digits = nanDigits; |
| isNegative = false; |
| } |
| |
| nDigits = digits.length; |
| |
| return; |
| } |
| |
| // We have a working double. |
| isNaN = false; |
| |
| int nSignificantBits; |
| |
| // Detect denormalized value. |
| if (exponent == 0) { |
| // Detect zero value. |
| if (bits == 0L) { |
| decimalExponent = 0; |
| digits = zeroes; |
| nDigits = 1; |
| |
| return; |
| } |
| |
| // Normalize value, using highest significant bit as HOB. |
| while ((bits & fractHOB) == 0L) { |
| bits <<= 1; |
| exponent -= 1; |
| } |
| |
| // Compute number of significant bits. |
| nSignificantBits = expShift + exponent +1; |
| // Bias exponent by HOB. |
| exponent += 1; |
| } else { |
| // Add implicit HOB. |
| bits |= fractHOB; |
| // Compute number of significant bits. |
| nSignificantBits = expShift + 1; |
| } |
| |
| // Unbias exponent (represents bit shift). |
| exponent -= expBias; |
| |
| // Determine the number of significant bits in the fraction. |
| final int nFractBits = countSignificantBits(bits); |
| |
| // Number of bits to the right of the decimal. |
| final int nTinyBits = Math.max(0, nFractBits - exponent - 1); |
| |
| // Computed decimal exponent. |
| int decExponent; |
| |
| if (exponent <= maxSmallBinExp && exponent >= minSmallBinExp) { |
| // Look more closely at the number to decide if, |
| // with scaling by 10^nTinyBits, the result will fit in |
| // a long. |
| if (nTinyBits < powersOf5.length && (nFractBits + nBitsPowerOf5[nTinyBits]) < 64) { |
| /* |
| * We can do this: |
| * take the fraction bits, which are normalized. |
| * (a) nTinyBits == 0: Shift left or right appropriately |
| * to align the binary point at the extreme right, i.e. |
| * where a long int point is expected to be. The integer |
| * result is easily converted to a string. |
| * (b) nTinyBits > 0: Shift right by expShift - nFractBits, |
| * which effectively converts to long and scales by |
| * 2^nTinyBits. Then multiply by 5^nTinyBits to |
| * complete the scaling. We know this won't overflow |
| * because we just counted the number of bits necessary |
| * in the result. The integer you get from this can |
| * then be converted to a string pretty easily. |
| */ |
| |
| if (nTinyBits == 0) { |
| long halfULP; |
| |
| if (exponent > nSignificantBits) { |
| halfULP = 1L << (exponent - nSignificantBits - 1); |
| } else { |
| halfULP = 0L; |
| } |
| |
| if (exponent >= expShift) { |
| bits <<= exponent - expShift; |
| } else { |
| bits >>>= expShift - exponent; |
| } |
| |
| // Discard non-significant low-order bits, while rounding, |
| // up to insignificant value. |
| int i; |
| for (i = 0; halfULP >= 10L; i++) { |
| halfULP /= 10L; |
| } |
| |
| /** |
| * This is the easy subcase -- |
| * all the significant bits, after scaling, are held in bits. |
| * isNegative and decExponent tell us what processing and scaling |
| * has already been done. Exceptional cases have already been |
| * stripped out. |
| * In particular: |
| * bits is a finite number (not Infinite, nor NaN) |
| * bits > 0L (not zero, nor negative). |
| * |
| * The only reason that we develop the digits here, rather than |
| * calling on Long.toString() is that we can do it a little faster, |
| * and besides want to treat trailing 0s specially. If Long.toString |
| * changes, we should re-evaluate this strategy! |
| */ |
| |
| int decExp = 0; |
| |
| if (i != 0) { |
| // 10^i == 5^i * 2^i |
| final long powerOf10 = powersOf5[i] << i; |
| final long residue = bits % powerOf10; |
| bits /= powerOf10; |
| decExp += i; |
| |
| if (residue >= (powerOf10 >> 1)) { |
| // Round up based on the low-order bits we're discarding. |
| bits++; |
| } |
| } |
| |
| int ndigits = 20; |
| final char[] digits0 = new char[26]; |
| int digitno = ndigits - 1; |
| int c = (int)(bits % 10L); |
| bits /= 10L; |
| |
| while (c == 0) { |
| decExp++; |
| c = (int)(bits % 10L); |
| bits /= 10L; |
| } |
| |
| while (bits != 0L) { |
| digits0[digitno--] = (char)(c + '0'); |
| decExp++; |
| c = (int)(bits % 10L); |
| bits /= 10; |
| } |
| |
| digits0[digitno] = (char)(c + '0'); |
| |
| ndigits -= digitno; |
| final char[] result = new char[ndigits]; |
| System.arraycopy(digits0, digitno, result, 0, ndigits); |
| |
| this.digits = result; |
| this.decimalExponent = decExp + 1; |
| this.nDigits = ndigits; |
| |
| return; |
| } |
| } |
| } |
| |
| /* |
| * This is the hard case. We are going to compute large positive |
| * integers B and S and integer decExp, s.t. |
| * d = (B / S) * 10^decExp |
| * 1 <= B / S < 10 |
| * Obvious choices are: |
| * decExp = floor(log10(d)) |
| * B = d * 2^nTinyBits * 10^max(0, -decExp) |
| * S = 10^max(0, decExp) * 2^nTinyBits |
| * (noting that nTinyBits has already been forced to non-negative) |
| * I am also going to compute a large positive integer |
| * M = (1/2^nSignificantBits) * 2^nTinyBits * 10^max(0, -decExp) |
| * i.e. M is (1/2) of the ULP of d, scaled like B. |
| * When we iterate through dividing B/S and picking off the |
| * quotient bits, we will know when to stop when the remainder |
| * is <= M. |
| * |
| * We keep track of powers of 2 and powers of 5. |
| */ |
| |
| /* |
| * Estimate decimal exponent. (If it is small-ish, |
| * we could double-check.) |
| * |
| * First, scale the mantissa bits such that 1 <= d2 < 2. |
| * We are then going to estimate |
| * log10(d2) ~=~ (d2-1.5)/1.5 + log(1.5) |
| * and so we can estimate |
| * log10(d) ~=~ log10(d2) + binExp * log10(2) |
| * take the floor and call it decExp. |
| */ |
| final double d2 = Double.longBitsToDouble(expOne | (bits & ~fractHOB)); |
| decExponent = (int)Math.floor((d2 - 1.5D) * 0.289529654D + 0.176091259D + exponent * 0.301029995663981D); |
| |
| // Powers of 2 and powers of 5, respectively, in B. |
| final int B5 = Math.max(0, -decExponent); |
| int B2 = B5 + nTinyBits + exponent; |
| |
| // Powers of 2 and powers of 5, respectively, in S. |
| final int S5 = Math.max(0, decExponent); |
| int S2 = S5 + nTinyBits; |
| |
| // Powers of 2 and powers of 5, respectively, in M. |
| final int M5 = B5; |
| int M2 = B2 - nSignificantBits; |
| |
| /* |
| * The long integer fractBits contains the (nFractBits) interesting |
| * bits from the mantissa of d (hidden 1 added if necessary) followed |
| * by (expShift + 1 - nFractBits) zeros. In the interest of compactness, |
| * I will shift out those zeros before turning fractBits into a |
| * BigInteger. The resulting whole number will be |
| * d * 2^(nFractBits - 1 - binExp). |
| */ |
| |
| bits >>>= expShift + 1 - nFractBits; |
| B2 -= nFractBits - 1; |
| final int common2factor = Math.min(B2, S2); |
| B2 -= common2factor; |
| S2 -= common2factor; |
| M2 -= common2factor; |
| |
| /* |
| * HACK!!For exact powers of two, the next smallest number |
| * is only half as far away as we think (because the meaning of |
| * ULP changes at power-of-two bounds) for this reason, we |
| * hack M2. Hope this works. |
| */ |
| if (nFractBits == 1) { |
| M2 -= 1; |
| } |
| |
| if (M2 < 0) { |
| // Oops. Since we cannot scale M down far enough, |
| // we must scale the other values up. |
| B2 -= M2; |
| S2 -= M2; |
| M2 = 0; |
| } |
| |
| /* |
| * Construct, Scale, iterate. |
| * Some day, we'll write a stopping test that takes |
| * account of the asymmetry of the spacing of floating-point |
| * numbers below perfect powers of 2 |
| * 26 Sept 96 is not that day. |
| * So we use a symmetric test. |
| */ |
| |
| final char digits0[] = this.digits = new char[32]; |
| int ndigit; |
| boolean low, high; |
| long lowDigitDifference; |
| int q; |
| |
| /* |
| * Detect the special cases where all the numbers we are about |
| * to compute will fit in int or long integers. |
| * In these cases, we will avoid doing BigInteger arithmetic. |
| * We use the same algorithms, except that we "normalize" |
| * our FDBigInts before iterating. This is to make division easier, |
| * as it makes our fist guess (quotient of high-order words) |
| * more accurate! |
| */ |
| |
| // Binary digits needed to represent B, approx. |
| final int Bbits = nFractBits + B2 + ((B5 < nBitsPowerOf5.length) ? nBitsPowerOf5[B5] : (B5*3)); |
| // Binary digits needed to represent 10*S, approx. |
| final int tenSbits = S2 + 1 + (((S5 + 1) < nBitsPowerOf5.length) ? nBitsPowerOf5[(S5 + 1)] : ((S5 + 1) * 3)); |
| |
| if (Bbits < 64 && tenSbits < 64) { |
| long b = (bits * powersOf5[B5]) << B2; |
| final long s = powersOf5[S5] << S2; |
| long m = powersOf5[M5] << M2; |
| final long tens = s * 10L; |
| |
| /* |
| * Unroll the first iteration. If our decExp estimate |
| * was too high, our first quotient will be zero. In this |
| * case, we discard it and decrement decExp. |
| */ |
| |
| ndigit = 0; |
| q = (int)(b / s); |
| b = 10L * (b % s); |
| m *= 10L; |
| low = b < m; |
| high = (b + m) > tens; |
| |
| if (q == 0 && !high) { |
| // Ignore leading zero. |
| decExponent--; |
| } else { |
| digits0[ndigit++] = (char)('0' + q); |
| } |
| |
| if (decExponent < -3 || decExponent >= 8) { |
| high = low = false; |
| } |
| |
| while (!low && !high) { |
| q = (int)(b / s); |
| b = 10 * (b % s); |
| m *= 10; |
| |
| if (m > 0L) { |
| low = b < m; |
| high = (b + m) > tens; |
| } else { |
| low = true; |
| high = true; |
| } |
| |
| if (low && q == 0) { |
| break; |
| } |
| digits0[ndigit++] = (char)('0' + q); |
| } |
| |
| lowDigitDifference = (b << 1) - tens; |
| } else { |
| /* |
| * We must do BigInteger arithmetic. |
| * First, construct our BigInteger initial values. |
| */ |
| |
| BigInteger Bval = multiplyPowerOf5And2(BigInteger.valueOf(bits), B5, B2); |
| BigInteger Sval = constructPowerOf5And2(S5, S2); |
| BigInteger Mval = constructPowerOf5And2(M5, M2); |
| |
| |
| // Normalize so that BigInteger division works better. |
| final int shiftBias = Long.numberOfLeadingZeros(bits) - 4; |
| Bval = Bval.shiftLeft(shiftBias); |
| Mval = Mval.shiftLeft(shiftBias); |
| Sval = Sval.shiftLeft(shiftBias); |
| final BigInteger tenSval = Sval.multiply(BigInteger.TEN); |
| |
| /* |
| * Unroll the first iteration. If our decExp estimate |
| * was too high, our first quotient will be zero. In this |
| * case, we discard it and decrement decExp. |
| */ |
| |
| ndigit = 0; |
| |
| BigInteger[] quoRem = Bval.divideAndRemainder(Sval); |
| q = quoRem[0].intValue(); |
| Bval = quoRem[1].multiply(BigInteger.TEN); |
| Mval = Mval.multiply(BigInteger.TEN); |
| low = (Bval.compareTo(Mval) < 0); |
| high = (Bval.add(Mval).compareTo(tenSval) > 0); |
| |
| if (q == 0 && !high) { |
| // Ignore leading zero. |
| decExponent--; |
| } else { |
| digits0[ndigit++] = (char)('0' + q); |
| } |
| |
| if (decExponent < -3 || decExponent >= 8) { |
| high = low = false; |
| } |
| |
| while(!low && !high) { |
| quoRem = Bval.divideAndRemainder(Sval); |
| q = quoRem[0].intValue(); |
| Bval = quoRem[1].multiply(BigInteger.TEN); |
| Mval = Mval.multiply(BigInteger.TEN); |
| low = (Bval.compareTo(Mval) < 0); |
| high = (Bval.add(Mval).compareTo(tenSval) > 0); |
| |
| if (low && q == 0) { |
| break; |
| } |
| digits0[ndigit++] = (char)('0' + q); |
| } |
| |
| if (high && low) { |
| Bval = Bval.shiftLeft(1); |
| lowDigitDifference = Bval.compareTo(tenSval); |
| } else { |
| lowDigitDifference = 0L; |
| } |
| } |
| |
| this.decimalExponent = decExponent + 1; |
| this.digits = digits0; |
| this.nDigits = ndigit; |
| |
| /* |
| * Last digit gets rounded based on stopping condition. |
| */ |
| |
| if (high) { |
| if (low) { |
| if (lowDigitDifference == 0L) { |
| // it's a tie! |
| // choose based on which digits we like. |
| if ((digits0[nDigits - 1] & 1) != 0) { |
| roundup(); |
| } |
| } else if (lowDigitDifference > 0) { |
| roundup(); |
| } |
| } else { |
| roundup(); |
| } |
| } |
| } |
| |
| /** |
| * Count number of significant bits. |
| * @param bits Double's fraction. |
| * @return Number of significant bits. |
| */ |
| private static int countSignificantBits(final long bits) { |
| if (bits != 0) { |
| return 64 - Long.numberOfLeadingZeros(bits) - Long.numberOfTrailingZeros(bits); |
| } |
| |
| return 0; |
| } |
| |
| /* |
| * Cache big powers of 5 handy for future reference. |
| */ |
| private static BigInteger powerOf5Cache[]; |
| |
| /** |
| * Determine the largest power of 5 needed (as BigInteger.) |
| * @param power Power of 5. |
| * @return BigInteger of power of 5. |
| */ |
| private static BigInteger bigPowerOf5(final int power) { |
| if (powerOf5Cache == null) { |
| powerOf5Cache = new BigInteger[power + 1]; |
| } else if (powerOf5Cache.length <= power) { |
| final BigInteger t[] = new BigInteger[ power+1 ]; |
| System.arraycopy(powerOf5Cache, 0, t, 0, powerOf5Cache.length); |
| powerOf5Cache = t; |
| } |
| |
| if (powerOf5Cache[power] != null) { |
| return powerOf5Cache[power]; |
| } else if (power < powersOf5.length) { |
| return powerOf5Cache[power] = BigInteger.valueOf(powersOf5[power]); |
| } else { |
| // Construct the value recursively. |
| // in order to compute 5^p, |
| // compute its square root, 5^(p/2) and square. |
| // or, let q = p / 2, r = p -q, then |
| // 5^p = 5^(q+r) = 5^q * 5^r |
| final int q = power >> 1; |
| final int r = power - q; |
| BigInteger bigQ = powerOf5Cache[q]; |
| |
| if (bigQ == null) { |
| bigQ = bigPowerOf5(q); |
| } |
| |
| if (r < powersOf5.length) { |
| return (powerOf5Cache[power] = bigQ.multiply(BigInteger.valueOf(powersOf5[r]))); |
| } |
| BigInteger bigR = powerOf5Cache[ r ]; |
| |
| if (bigR == null) { |
| bigR = bigPowerOf5(r); |
| } |
| |
| return (powerOf5Cache[power] = bigQ.multiply(bigR)); |
| } |
| } |
| |
| /** |
| * Multiply BigInteger by powers of 5 and 2 (i.e., 10) |
| * @param value Value to multiply. |
| * @param p5 Power of 5. |
| * @param p2 Power of 2. |
| * @return Result. |
| */ |
| private static BigInteger multiplyPowerOf5And2(final BigInteger value, final int p5, final int p2) { |
| BigInteger returnValue = value; |
| |
| if (p5 != 0) { |
| returnValue = returnValue.multiply(bigPowerOf5(p5)); |
| } |
| |
| if (p2 != 0) { |
| returnValue = returnValue.shiftLeft(p2); |
| } |
| |
| return returnValue; |
| } |
| |
| /** |
| * Construct a BigInteger power of 5 and 2 (i.e., 10) |
| * @param p5 Power of 5. |
| * @param p2 Power of 2. |
| * @return Result. |
| */ |
| private static BigInteger constructPowerOf5And2(final int p5, final int p2) { |
| BigInteger v = bigPowerOf5(p5); |
| |
| if (p2 != 0) { |
| v = v.shiftLeft(p2); |
| } |
| |
| return v; |
| } |
| |
| /** |
| * Round up last digit by adding one to the least significant digit. |
| * In the unlikely event there is a carry out, deal with it. |
| * assert that this will only happen where there |
| * is only one digit, e.g. (float)1e-44 seems to do it. |
| */ |
| private void roundup() { |
| int i; |
| int q = digits[ i = (nDigits-1)]; |
| |
| while (q == '9' && i > 0) { |
| if (decimalExponent < 0) { |
| nDigits--; |
| } else { |
| digits[i] = '0'; |
| } |
| |
| q = digits[--i]; |
| } |
| |
| if (q == '9') { |
| // Carryout! High-order 1, rest 0s, larger exp. |
| decimalExponent += 1; |
| digits[0] = '1'; |
| |
| return; |
| } |
| |
| digits[i] = (char)(q + 1); |
| } |
| |
| /** |
| * Format final number string. |
| * @return Formatted string. |
| */ |
| @Override |
| public String toString() { |
| final StringBuilder sb = new StringBuilder(32); |
| |
| if (isNegative) { |
| sb.append('-'); |
| } |
| |
| if (isNaN) { |
| sb.append(digits, 0, nDigits); |
| } else { |
| if (decimalExponent > 0 && decimalExponent <= 21) { |
| final int charLength = Math.min(nDigits, decimalExponent); |
| sb.append(digits, 0, charLength); |
| |
| if (charLength < decimalExponent) { |
| sb.append(zeroes, 0, decimalExponent - charLength); |
| } else if (charLength < nDigits) { |
| sb.append('.'); |
| sb.append(digits, charLength, nDigits - charLength); |
| } |
| } else if (decimalExponent <=0 && decimalExponent > -6) { |
| sb.append('0'); |
| sb.append('.'); |
| |
| if (decimalExponent != 0) { |
| sb.append(zeroes, 0, -decimalExponent); |
| } |
| |
| sb.append(digits, 0, nDigits); |
| } else { |
| sb.append(digits[0]); |
| |
| if (nDigits > 1) { |
| sb.append('.'); |
| sb.append(digits, 1, nDigits - 1); |
| } |
| |
| sb.append('e'); |
| final int exponent; |
| int e; |
| |
| if (decimalExponent <= 0) { |
| sb.append('-'); |
| exponent = e = -decimalExponent + 1; |
| } else { |
| sb.append('+'); |
| exponent = e = decimalExponent - 1; |
| } |
| |
| if (exponent > 99) { |
| sb.append((char)(e / 100 + '0')); |
| e %= 100; |
| } |
| |
| if (exponent > 9) { |
| sb.append((char)(e / 10 + '0')); |
| e %= 10; |
| } |
| |
| sb.append((char)(e + '0')); |
| } |
| } |
| |
| return sb.toString(); |
| } |
| } |