/*
 * The contents of this file are subject to the Netscape Public
 * License Version 1.1 (the "License"); you may not use this file
 * except in compliance with the License. You may obtain a copy of
 * the License at http://www.mozilla.org/NPL/

 * Software distributed under the License is distributed on an "AS
 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * rights and limitations under the License.

 * The Original Code is Rhino code, released
 * May 6, 1999.

 * The Initial Developer of the Original Code is Netscape
 * Communications Corporation.  Portions created by Netscape are
 * Copyright (C) 1997-1999 Netscape Communications Corporation. All
 * Rights Reserved.

 * Contributor(s): 

 * Alternatively, the contents of this file may be used under the
 * terms of the GNU Public License (the "GPL"), in which case the
 * provisions of the GPL are applicable instead of those above.
 * If you wish to allow use of your version of this file only
 * under the terms of the GPL and not to allow others to use your
 * version of this file under the NPL, indicate your decision by
 * deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL.  If you do not delete
 * the provisions above, a recipient may use your version of this
 * file under either the NPL or the GPL.
 */
#ifdef DTOA

/* Header file */
#ifdef VX
#include <private/mathP.h>
#endif
#ifdef SUNOS5
#include <ieeefp.h>
#endif
#include <math.h>
#include "js-utils.h"
#include "js-dtoa.h"

/* Class data */
const double JSDToA::tens[23] = {
    1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
    1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
    1e20, 1e21, 1e22
};
const double JSDToA::bigtens[5] = { 1e16, 1e32, 1e64, 1e128, 1e256 };
const int JSDToA::dtoaModes[5] = {
    0,  /* DTOSTR_STANDARD */
    0,  /* DTOSTR_STANDARD_EXPONENTIAL, */
    3,  /* DTOSTR_FIXED, */
    2,  /* DTOSTR_EXPONENTIAL, */
    2   /* DTOSTR_PRECISION */
};

/* Procedures */
int64_t JSDToA::doubleToLongBits(double d)
{
    union {
        double d;
        int64_t l;
    } v;

#ifdef VX
    if (isNan(d)) {
#else
    if (isnan(d)) {
#endif
        return ((int64_t) 0x7ff80000) << ((int64_t) 32);
    }

    v.d = d;
    return v.l;
}

double JSDToA::longBitsToDouble(int64_t bits)
{
    union {
        double d;
        int64_t l;
    } v;

    v.l = bits;
    return v.d;
}

jsChar_t JSDToA::BASEDIGIT(int digit)
{
    return (jsChar_t) ((digit >= 10) ? 'a' - 10 + digit : '0' + digit);
}

int JSDToA::lo0bits(int32_t y)
{
    int k;
    uint32_t x = y;

    if ((x & 7) != 0) {
        if ((x & 1) != 0) {
            return 0;
        }
        if ((x & 2) != 0) {
            return 1;
        }
        return 2;
    }
    k = 0;
    if ((x & 0xffff) == 0) {
        k = 16;
        x >>= 16;
    }
    if ((x & 0xff) == 0) {
        k += 8;
        x >>= 8;
    }
    if ((x & 0xf) == 0) {
        k += 4;
        x >>= 4;
    }
    if ((x & 0x3) == 0) {
        k += 2;
        x >>= 2;
    }
    if ((x & 1) == 0) {
        k++;
        x >>= 1;
        if ((x & 1) == 0) {
            return 32;
        }
    }
    return k;
}

/* Return the number (0 through 32) of most significant zero bits in x. */
int JSDToA::hi0bits(int32_t x)
{
    int k = 0;

    if ((x & 0xffff0000) == 0) {
        k = 16;
        x <<= 16;
    }
    if ((x & 0xff000000) == 0) {
        k += 8;
        x <<= 8;
    }
    if ((x & 0xf0000000) == 0) {
        k += 4;
        x <<= 4;
    }
    if ((x & 0xc0000000) == 0) {
        k += 2;
        x <<= 2;
    }
    if ((x & 0x80000000) == 0) {
        k++;
        if ((x & 0x40000000) == 0) {
            return 32;
        }
    }
    return k;
}
void JSDToA::stuffBits(JSBigInteger::Digit * bits, int offset, int val)
{
    bits[offset] = (JSBigInteger::Digit) val;
}

/*
 * Convert d into the form b*2^e, where b is an odd integer.  b is the returned
 * Bigint and e is the returned binary exponent.  Return the number of
 * significant bits in b in bits.  d must be finite and nonzero.
 */
JSBigInteger JSDToA::d2b(JSContext * cx, double d, int *e, int *bits)
{
    JSBigInteger::Digit * dbl_bits;
    int32_t i, k, de;
    uint32_t y, z;
    int64_t dBits = doubleToLongBits(d);
    uint32_t d0 = (uint32_t) (dBits >> 32);
    uint32_t d1 = (uint32_t) (dBits);
    int dbl_bitsLength;

    z = d0 & Frac_mask;
    d0 &= 0x7fffffff;   /* clear sign bit, which we ignore */

    if ((de = (uint32_t) (d0 >> Exp_shift)) != 0) {
        z |= Exp_msk1;
    }
    if ((y = d1) != 0) {
        dbl_bitsLength = 2;
        dbl_bits = (JSBigInteger::Digit *)
                JS_NewZoneObj(cx, sizeof(*dbl_bits) * dbl_bitsLength);
        k = lo0bits(y);
        y >>= k;
        if (k != 0) {
            stuffBits(dbl_bits, 1, y | z << (32 - k));
            z >>= k;
        }
        else {
            stuffBits(dbl_bits, 1, y);
        }
        stuffBits(dbl_bits, 0, z);
        i = (z != 0) ? 2 : 1;
    }
    else {
        dbl_bitsLength = 1;
        dbl_bits = (JSBigInteger::Digit *)
                JS_NewZoneObj(cx, sizeof(*dbl_bits) * dbl_bitsLength);
        k = lo0bits(z);
        z >>= k;
        stuffBits(dbl_bits, 0, z);
        k += 32;
        i = 1;
    }
    if (de != 0) {
        *e = de - Bias - (P - 1) + k;
        *bits = P - k;
    }
    else {
        *e = de - Bias - (P - 1) + 1 + k;
        *bits = 32 * i - hi0bits(z);
    }
    JSBigInteger result(cx, dbl_bits, dbl_bitsLength);

    JS_DeleteZoneObj(cx, dbl_bits);
    return result;
}

int32_t JSDToA::word0(double d)
{
    int64_t dBits = doubleToLongBits(d);

    return (int32_t) (dBits >> 32);
}
double JSDToA::setWord0(double d, int32_t i)
{
    int64_t dBits = doubleToLongBits(d);

    dBits = ((int64_t) i << 32) | (dBits & 0x0FFFFFFFFL);
    return longBitsToDouble(dBits);
}

int32_t JSDToA::word1(double d)
{
    int64_t dBits = doubleToLongBits(d);

    return (int32_t) dBits;
}

/* Return b * 5^k.  k must be nonnegative. */
JSBigInteger JSDToA::pow5mult(JSContext * cx, JSBigInteger & b, int k)
{
    JSBigInteger five = JSBigInteger::valueOf(cx, 5);
    JSBigInteger pow = five.pow(cx, k);

    return b.multiply(cx, pow);
}

jsBool_t JSDToA::roundOff(JSStringBuffer * buf)
{
    jsChar_t lastCh;

    while ((lastCh = buf->charAt(buf->length() - 1)) == '9') {
        buf->setLength(buf->length() - 1);
        if (buf->length() == 0) {
            return TRUE;
        }
    }
    buf->append((jsChar_t) (lastCh + 1));
    return FALSE;
}

jsString_t JSDToA::JS_dtobasestr(JSContext * cx, int base, double d)
{
    jsChar_t buffer[DTOBASESTR_BUFFER_SIZE];    /* The output string */
    int p;  /* index to current position in the buffer */
    int pInt;   /* index to the beginning of the integer part of the string */

    int digit;
    double di;  /* d truncated to an integer */
    double df;  /* The fractional part of d */

    p = 0;
    if (d < 0.0) {
        buffer[p++] = '-';
        d = -d;
    }

    /* Check for Infinity and NaN */
#ifdef VX
    if (isNan(d)) {
#else
    if (isnan(d)) {
#endif
        return JS_NewZoneString(cx, "NaN");
    }
    else {
#ifdef VX
        if (isNan(d) || isInf(d)) {
#else
        if (!finite(d)) {
#endif
            return JS_NewZoneString(cx, "Infinity");
        }
    }

    /* Output the integer part of d with the digits in reverse order. */
    pInt = p;
    di = (int)d;

    JSBigInteger b = JSBigInteger::valueOf(cx, (int64_t) di);
    jsString_t intDigits = b.toString(cx, base);
    int length = strlen(intDigits);

    memcpy(buffer + p, intDigits, length * sizeof(*buffer));
    p += length;
    JS_DeleteZoneObj(cx, intDigits);

    df = d - di;
    if (df != 0.0) {
        /* We have a fraction. */
        buffer[p++] = '.';

        int64_t dBits = doubleToLongBits(d);
        int32_t word0 = (int32_t) (dBits >> 32);
        int32_t word1 = (int32_t) (dBits);
        int e, bbits;

        b = d2b(cx, df, &e, &bbits);

        /* At this point df = b * 2^e.  e must be less than zero
         * because 0 < df < 1.
         */
        int s2 = -(((uint32_t) word0 >> Exp_shift1) & Exp_mask >> Exp_shift1);

        if (s2 == 0) {
            s2 = -1;
        }
        s2 += Bias + P;

        /* 1/2^s2 = (nextDouble(d) - d)/2 */
        JSBigInteger mlo = JSBigInteger::valueOf(cx, 1);
        JSBigInteger mhi = mlo;

        if ((word1 == 0) && ((word0 & Bndry_mask) == 0)
                && ((word0 & (Exp_mask & Exp_mask << 1)) != 0)) {
            /* The special case.  Here we want to be within a quarter of the
             * last input significant digit instead of one half of it when the
             * output string's value is less than d.
             */
            s2 += Log2P;
            mhi = JSBigInteger::valueOf(cx, 1 << Log2P);
        }
        b = b.shiftLeft(cx, e + s2);

        JSBigInteger s = JSBigInteger::valueOf(cx, 1);

        s = s.shiftLeft(cx, s2);
        /* At this point we have the following:
         *   s = 2^s2;
         *   1 > df = b/2^s2 > 0;
         *   (d - prevDouble(d))/2 = mlo/2^s2;
         *   (nextDouble(d) - d)/2 = mhi/2^s2. */
        JSBigInteger bigBase = JSBigInteger::valueOf(cx, base);

        jsBool_t done = FALSE;
        do {
            b = b.multiply(cx, bigBase);

            JSBigInteger div(cx), rem(cx);
            JSBigInteger *divResult[] = { &div, &rem };

            b.divideAndRemainder(cx, divResult, s);
            b = rem;
            digit = (jsChar_t) (divResult[0]->int64Value());
            if (mlo.equals(mhi)) {
                mlo = mhi = mlo.multiply(cx, bigBase);
            }
            else {
                mlo = mlo.multiply(cx, bigBase);
                mhi = mhi.multiply(cx, bigBase);
            }

            /* Do we yet have the shortest string that will round to d? */
            int j = b.compareTo(mlo);

            /* j is b/2^s2 compared with mlo/2^s2. */
            JSBigInteger delta = s.subtract(cx, mhi);
            int j1 = (delta.getSignum() <= 0) ? 1 : b.compareTo(delta);

            /* j1 is b/2^s2 compared with 1 - mhi/2^s2. */
            if (j1 == 0 && ((word1 & 1) == 0)) {
                if (j > 0)
                    digit++;
                done = TRUE;
            }
            else if (j < 0 || (j == 0 && ((word1 & 1) == 0))) {
                if (j1 > 0) {
                    /* Either dig or dig+1 would work here as the least
                     * significant digit.
                     * Use whichever would produce an output value closer
                     * to d.
                     */
                    b = b.shiftLeft(cx, 1);
                    j1 = b.compareTo(s);
                    if (j1 > 0) {
                        /* The even test (|| (j1 == 0 && (digit & 1))) is not
                         * here because it messes up odd base output
                         * such as 3.5 in base 3. 
                         */
                        digit++;
                    }
                }
                done = TRUE;
            }
            else if (j1 > 0) {
                digit++;
                done = TRUE;
            }
            buffer[p++] = BASEDIGIT(digit);
        } while (!done);
    }
    return JS_Substring(cx, buffer, 0, p);
}

/*
 * dtoa for IEEE arithmetic (dmg): convert double to ASCII string.
 *
 * Inspired by "How to Print Floating-Point Numbers Accurately" by
 * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 92-101].
 *
 * Modifications:
 *  1. Rather than iterating, we use a simple numeric overestimate
 * to determine k = floor(log10(d)).  We scale relevant
 * quantities using O(log2(k)) rather than O(k) multiplications.
 *  2. For some modes > 2 (corresponding to ecvt and fcvt), we don't
 * try to generate digits strictly left to right.  Instead, we
 * compute with fewer bits and propagate the carry if necessary
 * when rounding the final digit up.  This is often faster.
 *  3. Under the assumption that input will be rounded nearest,
 * mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22.
 * That is, we allow equality in stopping tests when the
 * round-nearest rule will give the same floating-point value
 * as would satisfaction of the stopping test with strict
 * inequality.
 *  4. We remove common factors of powers of 2 from relevant
 * quantities.
 *  5. When converting floating-point integers less than 1e16,
 * we use floating-point arithmetic rather than resorting
 * to multiple-precision integers.
 *  6. When asked to produce fewer than 15 digits, we first try
 * to get by with floating-point arithmetic; we resort to
 * multiple-precision integer arithmetic only if we cannot
 * guarantee that the floating-point calculation has given
 * the correctly rounded result.  For k requested digits and
 * "uniformly" distributed input, the probability is
 * something like 10^(k-15) that we must resort to the Long
 * calculation.
 */
/*
 * Always emits at least one digit.
 * If biasUp is set, then rounding in modes 2 and 3 will round away from zero
 * when the number is exactly halfway between two representable values.
 * For example, rounding 2.5 to zero digits after the decimal point will
 * return 3 and not 2.
 * 2.49 will still round to 2, and 2.51 will still round to 3.
 * bufsize should be at least 20 for modes 0 and 1.  For the other modes,
 * bufsize should be two greater than the maximum number of output characters
 * expected.
*/
int JSDToA::JS_dtoa(JSContext * cx, double d, int mode, jsBool_t biasUp, int ndigits, jsBool_t * sign, JSStringBuffer * buf)
{
    /*  Arguments ndigits, decpt, sign are similar to those
       of ecvt and fcvt; trailing zeros are suppressed from
       the returned string.  If not null, *rve is set to point
       to the end of the return value.  If d is +-Infinity or NaN,
       then *decpt is set to 9999.

       mode:
       0 ==> shortest string that yields d when read in
       and rounded to nearest.
       1 ==> like 0, but with Steele & White stopping rule;
       e.g. with IEEE P754 arithmetic , mode 0 gives
       1e23 whereas mode 1 gives 9.999999999999999e22.
       2 ==> max(1,ndigits) significant digits.  This gives a
       return value similar to that of ecvt, except
       that trailing zeros are suppressed.
       3 ==> through ndigits past the decimal point.  This
       gives a return value similar to that from fcvt,
       except that trailing zeros are suppressed, and
       ndigits can be negative.
       4-9 should give the same return values as 2-3, i.e.,
       4 <= mode <= 9 ==> same return as mode
       2 + (mode & 1).  These modes are mainly for
       debugging; often they run slower but sometimes
       faster than modes 2-3.
       4,5,8,9 ==> left-to-right digit generation.
       6-9 ==> don't try fast floating-point estimate
       (if applicable).

       Values of mode other than 0-9 are treated as mode 0.

       Sufficient space is allocated to the return value
       to hold the suppressed trailing zeros.
     */

    int b2, b5, i, ieps, ilim, ilim0, ilim1, j, j1, k, k0, m2, m5, s2, s5;
    jsChar_t dig;
    long L;
    long x;
    JSBigInteger b(cx), b1(cx), delta(cx), mlo(cx), mhi(cx), S(cx);
    int be;
    int bbits;
    double d2, ds, eps;
    jsBool_t spec_case, denorm, k_check, try_quick, leftright;

    if ((word0(d) & Sign_bit) != 0) {
        /* set sign for everything, including 0's and NaNs */
        *sign = TRUE;
        // word0(d) &= ~Sign_bit;  /* clear sign bit */
        d = setWord0(d, word0(d) & ~Sign_bit);
    }
    else {
        *sign = FALSE;
    }

    if ((word0(d) & Exp_mask) == Exp_mask) {
        /* Infinity or NaN */
        buf->append(((word1(d) == 0) && ((word0(d) & Frac_mask) == 0)) ? (jsString_t) "Infinity" : (jsString_t) "NaN");
        return 9999;
    }
    if (d == 0) {
        buf->setLength(0);
        buf->append('0');   /* copy "0" to buffer */
        return 1;
    }

    b = d2b(cx, d, &be, &bbits);
    i = (int32_t) (((uint32_t) word0(d) >> Exp_shift1)
            & (Exp_mask >> Exp_shift1));
    if (i != 0) {
        d2 = setWord0(d, (word0(d) & Frac_mask1) | Exp_11);

        /*
         * log(x)   ~=~ log(1.5) + (x-1.5)/1.5
         * log10(x)  =  log(x) / log(10)
         *      ~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10))
         * log10(d) = (i-Bias)*log(2)/log(10) + log10(d2)
         *
         * This suggests computing an approximation k to log10(d) by
         *
         * k = (i - Bias)*0.301029995663981
         *  + ( (d2-1.5)*0.289529654602168 + 0.176091259055681 );
         *
         * We want k to be too large rather than too small.
         * The error in the first-order Taylor series approximation
         * is in our favor, so we just round up the constant enough
         * to compensate for any error in the multiplication of
         * (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077,
         * and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14,
         * adding 1e-13 to the constant term more than suffices.
         * Hence we adjust the constant term to 0.1760912590558.
         * (We could get a more accurate k by invoking log10,
         *  but this is probably not worthwhile.)
         */
        i -= Bias;
        denorm = FALSE;
    }
    else {
        /* d is denormalized */
        i = bbits + be + (Bias + (P - 1) - 1);
        x = (i > 32) ? word0(d) << (64 - i)
                | ((uint32_t) word1(d)) >> (i - 32) : word1(d) << (32 - i);
        d2 = setWord0(x, word0(x) - 31 * Exp_msk1);
        i -= (Bias + (P - 1) - 1) + 1;
        denorm = TRUE;
    }
    /*
     * At this point d = f*2^i, where 1 <= f < 2. 
     * d2 is an approximation of f.
     */
    ds = (d2 - 1.5) * 0.289529654602168 + 0.1760912590558 + i * 0.301029995663981;
    k = (int32_t) ds;
    if (ds < 0.0 && ds != k) {
        k--;    /* want k = floor(ds) */
    }
    k_check = TRUE;
    if (k >= 0 && k <= Ten_pmax) {
        if (d < tens[k]) {
            k--;
        }
        k_check = FALSE;
    }
    /*
     * At this point floor(log10(d)) <= k <= floor(log10(d))+1.
     * If k_check is zero, we're guaranteed that k = floor(log10(d)).
     */
    j = bbits - i - 1;
    /* At this point d = b/2^j, where b is an odd integer. */
    if (j >= 0) {
        b2 = 0;
        s2 = j;
    }
    else {
        b2 = -j;
        s2 = 0;
    }
    if (k >= 0) {
        b5 = 0;
        s5 = k;
        s2 += k;
    }
    else {
        b2 -= k;
        b5 = -k;
        s5 = 0;
    }
    /*
     * At this point d/10^k = (b * 2^b2 * 5^b5) / (2^s2 * 5^s5),
     * where b is an odd integer, b2 >= 0, b5 >= 0, s2 >= 0, and s5 >= 0.
     */
    if (mode < 0 || mode > 9) {
        mode = 0;
    }
    try_quick = TRUE;
    if (mode > 5) {
        mode -= 4;
        try_quick = FALSE;
    }
    leftright = TRUE;
    ilim = ilim1 = 0;
    switch (mode) {
    case 0:
    case 1:
        ilim = ilim1 = -1;
        i = 18;
        ndigits = 0;
        break;
    case 2:
        leftright = FALSE;
        /* no break */
    case 4:
        if (ndigits <= 0) {
            ndigits = 1;
        }
        ilim = ilim1 = i = ndigits;
        break;
    case 3:
        leftright = FALSE;
        /* no break */
    case 5:
        i = ndigits + k + 1;
        ilim = i;
        ilim1 = i - 1;
        if (i <= 0) {
            i = 1;
        }
    }
    /*
     * ilim is the maximum number of significant digits we want, based on k and
     * ndigits.
     * ilim1 is the maximum number of significant digits we want, based on k
     * and ndigits, when it turns out that k was computed too high by one.
     */
    jsBool_t fast_failed = FALSE;

    if (ilim >= 0 && ilim <= Quick_max && try_quick) {
        /* Try to get by with floating-point arithmetic. */
        i = 0;
        d2 = d;
        k0 = k;
        ilim0 = ilim;
        ieps = 2;   /* conservative */
        /*
         * Divide d by 10^k, keeping track of the roundoff error and avoiding
         * overflows.
         */
        if (k > 0) {
            ds = tens[k & 0xf];
            j = k >> 4;
            if ((j & Bletch) != 0) {
                /* prevent overflows */
                j &= Bletch - 1;
                d /= bigtens[n_bigtens - 1];
                ieps++;
            }
            for (; (j != 0); j >>= 1, i++) {
                if ((j & 1) != 0) {
                    ieps++;
                    ds *= bigtens[i];
                }
            }
            d /= ds;
        }
        else if ((j1 = -k) != 0) {
            d *= tens[j1 & 0xf];
            for (j = j1 >> 4; (j != 0); j >>= 1, i++) {
                if ((j & 1) != 0) {
                    ieps++;
                    d *= bigtens[i];
                }
            }
        }
        /* Check that k was computed correctly. */
        if (k_check && d < 1.0 && ilim > 0) {
            if (ilim1 <= 0) {
                fast_failed = TRUE;
            }
            else {
                ilim = ilim1;
                k--;
                d *= 10.;
                ieps++;
            }
        }
        /* eps bounds the cumulative error. */
        eps = ieps * d + 7.0;
        eps = setWord0(eps, word0(eps) - (P - 1) * Exp_msk1);
        if (ilim == 0) {
            // S = mhi = null;
            d -= 5.0;
            if (d > eps) {
                buf->append('1');
                k++;
                return (k + 1);
            }
            if (d < -eps) {
                buf->setLength(0);
                buf->append('0');   /* copy "0" to buffer */
                return 1;
            }
            fast_failed = TRUE;
        }
        if (!fast_failed) {
            fast_failed = TRUE;
            if (leftright) {
                /*
                 * Use Steele & White method of only
                 * generating digits needed.
                 */
                eps = 0.5 / tens[ilim - 1] - eps;
                for (i = 0;;) {
                    L = (int64_t) d;
                    d -= L;
                    buf->append((jsChar_t) ('0' + L));
                    if (d < eps) {
                        return (k + 1);
                    }
                    if (1.0 - d < eps) {
                        char lastCh;

                        while (TRUE) {
                            lastCh = buf->charAt(buf->length() - 1);
                            buf->setLength(buf->length() - 1);
                            if (lastCh != '9')
                                break;
                            if (buf->length() == 0) {
                                k++;
                                lastCh = '0';
                                break;
                            }
                        }
                        buf->append((jsChar_t) (lastCh + 1));
                        return (k + 1);
                    }
                    if (++i >= ilim)
                        break;
                    eps *= 10.0;
                    d *= 10.0;
                }
            }
            else {
                /* Generate ilim digits, then fix them up. */
                eps *= tens[ilim - 1];
                for (i = 1;; i++, d *= 10.0) {
                    L = (int64_t) d;
                    d -= L;
                    buf->append((jsChar_t) ('0' + L));
                    if (i == ilim) {
                        if (d > 0.5 + eps) {
                            char lastCh;

                            while (TRUE) {
                                lastCh = buf->charAt(buf->length() - 1);
                                buf->setLength(buf->length() - 1);
                                if (lastCh != '9')
                                    break;
                                if (buf->length() == 0) {
                                    k++;
                                    lastCh = '0';
                                    break;
                                }
                            }
                            buf->append((jsChar_t) (lastCh + 1));
                            return (k + 1);
                        }
                        else if (d < 0.5 - eps) {
                            while (buf->charAt(buf->length() - 1) == '0') {
                                buf->setLength(buf->length() - 1);
                            }
                            return (k + 1);
                        }
                        break;
                    }
                }
            }
        }
        if (fast_failed) {
            buf->setLength(0);
            d = d2;
            k = k0;
            ilim = ilim0;
        }
    }

    /* Do we have a "small" integer? */

    if (be >= 0 && k <= Int_max) {
        /* Yes. */
        ds = tens[k];
        if (ndigits < 0 && ilim <= 0) {
            // S = mhi = null;
            if (ilim < 0 || d < 5 * ds || (!biasUp && d == 5 * ds)) {
                buf->setLength(0);
                buf->append('0');   /* copy "0" to buffer */
                return 1;
            }
            buf->append('1');
            k++;
            return (k + 1);
        }
        for (i = 1;; i++) {
            L = (int64_t) (d / ds);
            d -= L * ds;
            buf->append((jsChar_t) ('0' + L));
            if (i == ilim) {
                d += d;
                if ((d > ds) || (d == ds && (((L & 1) != 0) || biasUp))) {
                    char lastCh;

                    while (TRUE) {
                        lastCh = buf->charAt(buf->length() - 1);
                        buf->setLength(buf->length() - 1);
                        if (lastCh != '9')
                            break;
                        if (buf->length() == 0) {
                            k++;
                            lastCh = '0';
                            break;
                        }
                    }
                    buf->append((jsChar_t) (lastCh + 1));
                }
                break;
            }
            d *= 10.0;
            if (d == 0)
                break;
        }
        return (k + 1);
    }

    m2 = b2;
    m5 = b5;
    if (leftright) {
        if (mode < 2) {
            i = (denorm) ? be + (Bias + (P - 1) - 1 + 1) : 1 + P - bbits;
            /*
             * i is 1 plus the number of trailing zero bits in d's significand.
             * Thus, (2^m2 * 5^m5) / (2^(s2+i) * 5^s5) = (1/2 lsb of d)/10^k.
             */
        }
        else {
            j = ilim - 1;
            if (m5 >= j) {
                m5 -= j;
            }
            else {
                s5 += j -= m5;
                b5 += j;
                m5 = 0;
            }
            if ((i = ilim) < 0) {
                m2 -= i;
                i = 0;
            }
            /* (2^m2 * 5^m5) / (2^(s2+i) * 5^s5) = (1/2 * 10^(1-ilim))/10^k. */
        }
        b2 += i;
        s2 += i;
        mhi = JSBigInteger::valueOf(cx, 1);
        /*
         * (mhi * 2^m2 * 5^m5) / (2^s2 * 5^s5) = one-half of last printed
         * (when mode >= 2) or input (when mode < 2) significant digit,
         * divided by 10^k.
         */
    }
    /*
     * We still have d/10^k = (b * 2^b2 * 5^b5) / (2^s2 * 5^s5).
     * Reduce common factors in b2, m2, and s2 without changing the equalities.
     */
    if (m2 > 0 && s2 > 0) {
        i = (m2 < s2) ? m2 : s2;
        b2 -= i;
        m2 -= i;
        s2 -= i;
    }

    /* Fold b5 into b and m5 into mhi. */
    if (b5 > 0) {
        if (leftright) {
            if (m5 > 0) {
                mhi = pow5mult(cx, mhi, m5);
                b1 = mhi.multiply(cx, b);
                b = b1;
            }
            if ((j = b5 - m5) != 0) {
                b = pow5mult(cx, b, j);
            }
        }
        else {
            b = pow5mult(cx, b, b5);
        }
    }
    /* Now we have d/10^k = (b * 2^b2) / (2^s2 * 5^s5) and
     * (mhi * 2^m2) / (2^s2 * 5^s5) = one-half of last printed or input
     * significant digit, divided by 10^k.
     */

    S = JSBigInteger::valueOf(cx, 1);
    if (s5 > 0) {
        S = pow5mult(cx, S, s5);
    }
    /*
     * Now we have d/10^k = (b * 2^b2) / (S * 2^s2) and
     * (mhi * 2^m2) / (S * 2^s2) = one-half of last printed or input
     * significant digit, divided by 10^k.
     */

    /* Check for special case that d is a normalized power of 2. */
    spec_case = FALSE;
    if (mode < 2) {
        if ((word1(d) == 0) && ((word0(d) & Bndry_mask) == 0)
                && ((word0(d) & (Exp_mask & Exp_mask << 1)) != 0)
                ) {
            /*
             * The special case.  Here we want to be within a quarter of
             * the last input significant digit instead of one half of it
             * when the decimal output string's value is less than d.
             */
            b2 += Log2P;
            s2 += Log2P;
            spec_case = TRUE;
        }
    }

    /*
     * Arrange for convenient computation of quotients:
     * shift left if necessary so divisor has 4 leading 0 bits.
     *
     * Perhaps we should just compute leading 28 bits of S once
     * and for all and pass them and a shift to quorem, so it
     * can do shifts and ors to compute the numerator for q.
     */
    int S_bytesLength;
    JSBigInteger::Digit * S_bytes = S.toDigitArray(cx, &S_bytesLength);
    int S_hiWord = 0;

    for (int idx = 0; idx < (int)(sizeof(S_hiWord) / sizeof(JSBigInteger::Digit)); idx++) {
        int mask = (1LL << (8 * sizeof(JSBigInteger::Digit))) - 1;

        if (sizeof(S_hiWord) != sizeof(JSBigInteger::Digit)) {
            S_hiWord = S_hiWord << (8 * sizeof(JSBigInteger::Digit));
        }
        if (idx < S_bytesLength) {
            S_hiWord |= (S_bytes[idx] & mask);
        }
    }
    JS_DeleteZoneObj(cx, S_bytes);

    if ((i = (((s5 != 0) ? 32 - hi0bits(S_hiWord) : 1) + s2) & 0x1f) != 0) {
        i = 32 - i;
    }
    /*
     * i is the number of leading zero bits in the most significant
     * word of S*2^s2.
     */
    if (i > 4) {
        i -= 4;
        b2 += i;
        m2 += i;
        s2 += i;
    }
    else if (i < 4) {
        i += 28;
        b2 += i;
        m2 += i;
        s2 += i;
    }
    /*
     * Now S*2^s2 has exactly four leading zero bits in its most
     * significant word.
     */
    if (b2 > 0) {
        b = b.shiftLeft(cx, b2);
    }
    if (s2 > 0) {
        S = S.shiftLeft(cx, s2);
    }
    /*
     * Now we have d/10^k = b/S and
     * (mhi * 2^m2) / S = maximum acceptable error, divided by 10^k.
     */
    if (k_check) {
        if (b.compareTo(S) < 0) {
            k--;
            /* we botched the k estimate */
            JSBigInteger val = JSBigInteger::valueOf(cx, 10);

            b = b.multiply(cx, val);
            if (leftright) {
                mhi = mhi.multiply(cx, val);
            }
            ilim = ilim1;
        }
    }
    /* At this point 1 <= d/10^k = b/S < 10. */

    if (ilim <= 0 && mode > 2) {
        /*
         * We're doing fixed-mode output and d is less than the minimum
         * nonzero output in this mode.
         * Output either zero or the minimum nonzero output depending on
         * which is closer to d.
         */
        JSBigInteger val = JSBigInteger::valueOf(cx, 5);

        if ((ilim < 0)
                || ((i = b.compareTo(S = S.multiply(cx, val))) < 0)
                || (i == 0 && !biasUp)) {
            /*
             * Always emit at least one digit.  If the number appears to
             * be zero using the current mode, then emit one '0' digit
             * and set decpt to 1.
             */
            buf->setLength(0);
            buf->append('0');   /* copy "0" to buffer */
            return 1;
        }
        buf->append('1');
        k++;
        return (k + 1);
    }
    if (leftright) {
        if (m2 > 0) {
            mhi = mhi.shiftLeft(cx, m2);
        }
        /*
         * Compute mlo -- check for special case
         * that d is a normalized power of 2.
         */

        mlo = mhi;
        if (spec_case) {
            mhi = mlo;
            mhi = mhi.shiftLeft(cx, Log2P);
        }
        /*
         * mlo/S = maximum acceptable error, divided by 10^k, if the output
         * is less than d.
         * mhi/S = maximum acceptable error, divided by 10^k, if the output
         * is greater than d.
         */

        for (i = 1;; i++) {
            JSBigInteger div(cx), rem(cx);
            JSBigInteger *divResult[] = { &div, &rem };

            b.divideAndRemainder(cx, divResult, S);

            b = *divResult[1];
            dig = (jsChar_t) (divResult[0]->int64Value() + '0');

            /*
             * Do we yet have the shortest decimal string
             * that will round to d?
             */
            j = b.compareTo(mlo);

            /* j is b/S compared with mlo/S. */
            delta = S.subtract(cx, mhi);
            j1 = (delta.getSignum() <= 0) ? 1 : b.compareTo(delta);

            /* j1 is b/S compared with 1 - mhi/S. */
            if ((j1 == 0) && (mode == 0) && ((word1(d) & 1) == 0)) {
                if (dig == '9') {
                    buf->append('9');
                    if (roundOff(buf)) {
                        k++;
                        buf->append('1');
                    }
                    return (k + 1);
                }
                if (j > 0) {
                    dig++;
                }
                buf->append(dig);
                return (k + 1);
            }
            if ((j < 0)
                    || ((j == 0) && (mode == 0) && ((word1(d) & 1) == 0))) {
                if (j1 > 0) {
                    /*
                     * Either dig or dig+1 would work here as the least
                     * significant decimal digit.
                     * Use whichever would produce a decimal value closer to d.
                     */
                    b = b.shiftLeft(cx, 1);
                    j1 = b.compareTo(S);
                    if (((j1 > 0) || (j1 == 0 && (((dig & 1) == 1) || biasUp)))
                            && (dig++ == '9')) {
                        buf->append('9');
                        if (roundOff(buf)) {
                            k++;
                            buf->append('1');
                        }
                        return (k + 1);
                    }
                }
                buf->append(dig);
                return (k + 1);
            }
            if (j1 > 0) {
                if (dig == '9') {   /* possible if i == 1 */
                    buf->append('9');
                    if (roundOff(buf)) {
                        k++;
                        buf->append('1');
                    }
                    return (k + 1);
                }
                buf->append((jsChar_t) (dig + 1));
                return (k + 1);
            }
            buf->append(dig);
            if (i == ilim)
                break;

            JSBigInteger val = JSBigInteger::valueOf(cx, 10);

            b = b.multiply(cx, val);
            if (mlo.equals(mhi)) {
                mlo = mhi = mhi.multiply(cx, val);
            }
            else {
                mlo = mlo.multiply(cx, val);
                mhi = mhi.multiply(cx, val);
            }
        }
    }
    else {
        for (i = 1;; i++) {
            JSBigInteger div(cx), rem(cx);
            JSBigInteger *divResult[] = { &div, &rem };

            b.divideAndRemainder(cx, divResult, S);
            b = *divResult[1];
            dig = (jsChar_t) (divResult[0]->int64Value() + '0');
            buf->append(dig);
            if (i >= ilim)
                break;

            JSBigInteger val = JSBigInteger::valueOf(cx, 10);
            b = b.multiply(cx, val);
        }
    }

    /* Round off last digit */

    b = b.shiftLeft(cx, 1);
    j = b.compareTo(S);
    if ((j > 0) || (j == 0 && (((dig & 1) == 1) || biasUp))) {
        if (roundOff(buf)) {
            k++;
            buf->append('1');
            return (k + 1);
        }
    }
    else {
        /* Strip trailing zeros */
        while (buf->charAt(buf->length() - 1) == '0')
            buf->setLength(buf->length() - 1);
    }
    return k + 1;
}
void JSDToA::JS_dtostr(JSContext * cx, JSStringBuffer * buffer, int mode, int precision, double d)
{
    int decPt;  /* Position of decimal point relative to first digit
                   returned by JS_dtoa */
    jsBool_t sign;  /* true if the sign bit was set in d */
    int nDigits;    /* Number of significand digits returned by JS_dtoa */

    if (mode == DTOSTR_FIXED && (d >= 1e21 || d <= -1e21)) {
        /*
         * Change mode here rather than below because the buffer may not be
         * large enough to hold a large integer.
         */
        mode = DTOSTR_STANDARD;
    }

    decPt = JS_dtoa(cx, d, dtoaModes[mode], mode >= DTOSTR_FIXED, precision, &sign, buffer);
    nDigits = buffer->length();

    /*
     * If Infinity, -Infinity, or NaN, return the string regardless of
     * the mode.
     */
    if (decPt != 9999) {
        jsBool_t exponentialNotation = FALSE;
        int minNDigits = 0; /* Minimum number of significand digits
                               required by mode and precision */
        int p;

        switch (mode) {
        case DTOSTR_STANDARD:
            if (decPt < -5 || decPt > 21) {
                exponentialNotation = TRUE;
            }
            else {
                minNDigits = decPt;
            }
            break;

        case DTOSTR_FIXED:
            if (precision >= 0) {
                minNDigits = decPt + precision;
            }
            else {
                minNDigits = decPt;
            }
            break;

        case DTOSTR_EXPONENTIAL:
            minNDigits = precision;
            /* Fall through */
        case DTOSTR_STANDARD_EXPONENTIAL:
            exponentialNotation = TRUE;
            break;

        case DTOSTR_PRECISION:
            minNDigits = precision;
            if (decPt < -5 || decPt > precision) {
                exponentialNotation = TRUE;
            }
            break;
        }

        /*
         * If the number has fewer than minNDigits, pad it with zeros at the
         * end
         */
        if (nDigits < minNDigits) {
            p = minNDigits;
            nDigits = minNDigits;
            do {
                buffer->append('0');
            } while (buffer->length() != p);
        }

        if (exponentialNotation) {
            /* Insert a decimal point if more than one significand digit */
            if (nDigits != 1) {
                buffer->insert(1, '.');
            }
            buffer->append('e');
            if ((decPt - 1) >= 0) {
                buffer->append('+');
            }
            buffer->append(decPt - 1);
        }
        else if (decPt != nDigits) {
            /* Some kind of a fraction in fixed notation */
            if (decPt > 0) {
                /* dd...dd . dd...dd */
                buffer->insert(decPt, '.');
            }
            else {
                /* 0 . 00...00dd...dd */
                for (int i = 0; i < 1 - decPt; i++) {
                    buffer->insert(0, '0');
                }
                buffer->insert(1, '.');
            }
        }
    }

    /* If negative and neither -0.0 nor NaN, output a leading '-'. */
    if (sign && !(word0(d) == Sign_bit && word1(d) == 0) && !((word0(d) & Exp_mask) == Exp_mask && ((word1(d) != 0) || ((word0(d) & Frac_mask) != 0)))) {
        buffer->insert(0, '-');
    }
}

#endif /* DTOA */
