alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (NumberToString.java)

This example Java source code file (NumberToString.java) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

biginteger, bval, math, mval, numbertostring, stringbuilder, sval

The NumberToString.java Java example source code

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

Other Java examples (source code examples)

Here is a short list of links related to this Java NumberToString.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.