X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/ba379fdc102753d6be2c4d937058fe40257329fe..14957cd040308e3eeec43d26bae5d76da13fcd85:/wtf/dtoa.cpp diff --git a/wtf/dtoa.cpp b/wtf/dtoa.cpp index d75c17a..b162543 100644 --- a/wtf/dtoa.cpp +++ b/wtf/dtoa.cpp @@ -3,7 +3,7 @@ * The author of this software is David M. Gay. * * Copyright (c) 1991, 2000, 2001 by Lucent Technologies. - * Copyright (C) 2002, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2002, 2005, 2006, 2007, 2008, 2010 Apple Inc. All rights reserved. * * Permission to use, copy, modify, and distribute this software for any * purpose without fee is hereby granted, provided that this entire notice @@ -18,14 +18,8 @@ * ***************************************************************/ -/* Please send bug reports to - David M. Gay - Bell Laboratories, Room 2C-463 - 600 Mountain Avenue - Murray Hill, NJ 07974-0636 - U.S.A. - dmg@bell-labs.com - */ +/* Please send bug reports to David M. Gay (dmg at acm dot org, + * with " at " changed at "@" and " dot " changed to "."). */ /* On a machine with IEEE extended-precision registers, it is * necessary to specify double-precision (53-bit) rounding precision @@ -50,7 +44,7 @@ * * Modifications: * - * 1. We only require IEEE. + * 1. We only require IEEE double-precision arithmetic (not IEEE double-extended). * 2. We get by with floating-point arithmetic in a case that * Clinger missed -- when we're computing d * 10^n * for a small integer d and the integer n is not too @@ -67,91 +61,26 @@ * for 0 <= k <= 22). */ -/* - * #define IEEE_8087 for IEEE-arithmetic machines where the least - * significant byte has the lowest address. - * #define IEEE_MC68k for IEEE-arithmetic machines where the most - * significant byte has the lowest address. - * #define No_leftright to omit left-right logic in fast floating-point - * computation of dtoa. - * #define Check_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3 - * and Honor_FLT_ROUNDS is not #defined. - * #define Inaccurate_Divide for IEEE-format with correctly rounded - * products but inaccurate quotients, e.g., for Intel i860. - * #define USE_LONG_LONG on machines that have a "long long" - * integer type (of >= 64 bits), and performance testing shows that - * it is faster than 32-bit fallback (which is often not the case - * on 32-bit machines). On such machines, you can #define Just_16 - * to store 16 bits per 32-bit int32_t when doing high-precision integer - * arithmetic. Whether this speeds things up or slows things down - * depends on the machine and the number being converted. - * #define Bad_float_h if your system lacks a float.h or if it does not - * define some or all of DBL_DIG, DBL_MAX_10_EXP, DBL_MAX_EXP, - * FLT_RADIX, FLT_ROUNDS, and DBL_MAX. - * #define INFNAN_CHECK on IEEE systems to cause strtod to check for - * Infinity and NaN (case insensitively). On some systems (e.g., - * some HP systems), it may be necessary to #define NAN_WORD0 - * appropriately -- to the most significant word of a quiet NaN. - * (On HP Series 700/800 machines, -DNAN_WORD0=0x7ff40000 works.) - * When INFNAN_CHECK is #defined and No_Hex_NaN is not #defined, - * strtod also accepts (case insensitively) strings of the form - * NaN(x), where x is a string of hexadecimal digits and spaces; - * if there is only one string of hexadecimal digits, it is taken - * for the 52 fraction bits of the resulting NaN; if there are two - * or more strings of hex digits, the first is for the high 20 bits, - * the second and subsequent for the low 32 bits, with intervening - * white space ignored; but if this results in none of the 52 - * fraction bits being on (an IEEE Infinity symbol), then NAN_WORD0 - * and NAN_WORD1 are used instead. - * #define NO_IEEE_Scale to disable new (Feb. 1997) logic in strtod that - * avoids underflows on inputs whose result does not underflow. - * If you #define NO_IEEE_Scale on a machine that uses IEEE-format - * floating-point numbers and flushes underflows to zero rather - * than implementing gradual underflow, then you must also #define - * Sudden_Underflow. - * #define YES_ALIAS to permit aliasing certain double values with - * arrays of ULongs. This leads to slightly better code with - * some compilers and was always used prior to 19990916, but it - * is not strictly legal and can cause trouble with aggressively - * optimizing compilers (e.g., gcc 2.95.1 under -O2). - * #define SET_INEXACT if IEEE arithmetic is being used and extra - * computation should be done to set the inexact flag when the - * result is inexact and avoid setting inexact when the result - * is exact. In this case, dtoa.c must be compiled in - * an environment, perhaps provided by #include "dtoa.c" in a - * suitable wrapper, that defines two functions, - * int get_inexact(void); - * void clear_inexact(void); - * such that get_inexact() returns a nonzero value if the - * inexact bit is already set, and clear_inexact() sets the - * inexact bit to 0. When SET_INEXACT is #defined, strtod - * also does extra computations to set the underflow and overflow - * flags when appropriate (i.e., when the result is tiny and - * inexact or when it is a numeric value rounded to +-infinity). - * #define NO_ERRNO if strtod should not assign errno = ERANGE when - * the result overflows to +-Infinity or underflows to 0. - */ - #include "config.h" #include "dtoa.h" #if HAVE(ERRNO_H) #include -#else -#define NO_ERRNO #endif #include #include #include +#include #include #include #include #include +#include #include -#include +#include #include - -#include +#include +#include #if COMPILER(MSVC) #pragma warning(disable: 4244) @@ -159,57 +88,42 @@ #pragma warning(disable: 4554) #endif -#if PLATFORM(BIG_ENDIAN) -#define IEEE_MC68k -#elif PLATFORM(MIDDLE_ENDIAN) -#define IEEE_ARM -#else -#define IEEE_8087 -#endif - -#define INFNAN_CHECK - -#if defined(IEEE_8087) + defined(IEEE_MC68k) + defined(IEEE_ARM) != 1 -Exactly one of IEEE_8087, IEEE_ARM or IEEE_MC68k should be defined. -#endif - namespace WTF { -#if ENABLE(JSC_MULTIPLE_THREADS) +#if ENABLE(WTF_MULTIPLE_THREADS) Mutex* s_dtoaP5Mutex; #endif -typedef union { double d; uint32_t L[2]; } U; +typedef union { + double d; + uint32_t L[2]; +} U; -#ifdef YES_ALIAS -#define dval(x) x -#ifdef IEEE_8087 -#define word0(x) ((uint32_t*)&x)[1] -#define word1(x) ((uint32_t*)&x)[0] -#else -#define word0(x) ((uint32_t*)&x)[0] -#define word1(x) ((uint32_t*)&x)[1] -#endif +#if CPU(BIG_ENDIAN) || CPU(MIDDLE_ENDIAN) +#define word0(x) (x)->L[0] +#define word1(x) (x)->L[1] #else -#ifdef IEEE_8087 #define word0(x) (x)->L[1] #define word1(x) (x)->L[0] -#else -#define word0(x) (x)->L[0] -#define word1(x) (x)->L[1] #endif #define dval(x) (x)->d -#endif /* The following definition of Storeinc is appropriate for MIPS processors. * An alternative that might be better on some machines is - * #define Storeinc(a,b,c) (*a++ = b << 16 | c & 0xffff) + * *p++ = high << 16 | low & 0xffff; */ -#if defined(IEEE_8087) || defined(IEEE_ARM) -#define Storeinc(a,b,c) (((unsigned short*)a)[1] = (unsigned short)b, ((unsigned short*)a)[0] = (unsigned short)c, a++) +static ALWAYS_INLINE uint32_t* storeInc(uint32_t* p, uint16_t high, uint16_t low) +{ + uint16_t* p16 = reinterpret_cast(p); +#if CPU(BIG_ENDIAN) + p16[0] = high; + p16[1] = low; #else -#define Storeinc(a,b,c) (((unsigned short*)a)[0] = (unsigned short)b, ((unsigned short*)a)[1] = (unsigned short)c, a++) + p16[1] = high; + p16[0] = low; #endif + return p + 1; +} #define Exp_shift 20 #define Exp_shift1 20 @@ -236,50 +150,18 @@ typedef union { double d; uint32_t L[2]; } U; #define Quick_max 14 #define Int_max 14 -#if !defined(NO_IEEE_Scale) -#undef Avoid_Underflow -#define Avoid_Underflow -#endif - -#if !defined(Flt_Rounds) -#if defined(FLT_ROUNDS) -#define Flt_Rounds FLT_ROUNDS -#else -#define Flt_Rounds 1 -#endif -#endif /*Flt_Rounds*/ - - -#define rounded_product(a,b) a *= b -#define rounded_quotient(a,b) a /= b +#define rounded_product(a, b) a *= b +#define rounded_quotient(a, b) a /= b #define Big0 (Frac_mask1 | Exp_msk1 * (DBL_MAX_EXP + Bias - 1)) #define Big1 0xffffffff - -// FIXME: we should remove non-Pack_32 mode since it is unused and unmaintained -#ifndef Pack_32 -#define Pack_32 -#endif - -#if PLATFORM(PPC64) || PLATFORM(X86_64) +#if CPU(PPC64) || CPU(X86_64) +// FIXME: should we enable this on all 64-bit CPUs? // 64-bit emulation provided by the compiler is likely to be slower than dtoa own code on 32-bit hardware. #define USE_LONG_LONG #endif -#ifndef USE_LONG_LONG -#ifdef Just_16 -#undef Pack_32 -/* When Pack_32 is not defined, we store 16 bits per 32-bit int32_t. - * This makes some inner loops simpler and sometimes saves work - * during multiplications, but it often seems to make things slightly - * slower. Hence the default is now to store 32 bits per int32_t. - */ -#endif -#endif - -#define Kmax 15 - struct BigInt { BigInt() : sign(0) { } int sign; @@ -289,7 +171,7 @@ struct BigInt { sign = 0; m_words.clear(); } - + size_t size() const { return m_words.size(); @@ -299,7 +181,7 @@ struct BigInt { { m_words.resize(s); } - + uint32_t* words() { return m_words.data(); @@ -309,12 +191,12 @@ struct BigInt { { return m_words.data(); } - + void append(uint32_t w) { m_words.append(w); } - + Vector m_words; }; @@ -336,17 +218,11 @@ static void multadd(BigInt& b, int m, int a) /* multiply by m and add a */ carry = y >> 32; *x++ = (uint32_t)y & 0xffffffffUL; #else -#ifdef Pack_32 uint32_t xi = *x; uint32_t y = (xi & 0xffff) * m + carry; uint32_t z = (xi >> 16) * m + (y >> 16); carry = z >> 16; *x++ = (z << 16) + (y & 0xffff); -#else - uint32_t y = *x * m + carry; - carry = y >> 16; - *x++ = y & 0xffff; -#endif #endif } while (++i < wds); @@ -356,20 +232,9 @@ static void multadd(BigInt& b, int m, int a) /* multiply by m and add a */ static void s2b(BigInt& b, const char* s, int nd0, int nd, uint32_t y9) { - int k; - int32_t y; - int32_t x = (nd + 8) / 9; - - for (k = 0, y = 1; x > y; y <<= 1, k++) { } -#ifdef Pack_32 b.sign = 0; b.resize(1); b.words()[0] = y9; -#else - b.sign = 0; - b.resize((b->x[1] = y9 >> 16) ? 2 : 1); - b.words()[0] = y9 & 0xffff; -#endif int i = 9; if (9 < nd0) { @@ -412,7 +277,7 @@ static int hi0bits(uint32_t x) return k; } -static int lo0bits (uint32_t* y) +static int lo0bits(uint32_t* y) { int k; uint32_t x = *y; @@ -447,7 +312,7 @@ static int lo0bits (uint32_t* y) if (!(x & 1)) { k++; x >>= 1; - if (!x & 1) + if (!x) return 32; } *y = x; @@ -467,8 +332,13 @@ static void mult(BigInt& aRef, const BigInt& bRef) const BigInt* b = &bRef; BigInt c; int wa, wb, wc; - const uint32_t *x = 0, *xa, *xb, *xae, *xbe; - uint32_t *xc, *xc0; + const uint32_t* x = 0; + const uint32_t* xa; + const uint32_t* xb; + const uint32_t* xae; + const uint32_t* xbe; + uint32_t* xc; + uint32_t* xc0; uint32_t y; #ifdef USE_LONG_LONG unsigned long long carry, z; @@ -481,7 +351,7 @@ static void mult(BigInt& aRef, const BigInt& bRef) a = b; b = tmp; } - + wa = a->size(); wb = b->size(); wc = wa + wb; @@ -509,7 +379,6 @@ static void mult(BigInt& aRef, const BigInt& bRef) } } #else -#ifdef Pack_32 for (; xb < xbe; xb++, xc0++) { if ((y = *xb & 0xffff)) { x = xa; @@ -520,7 +389,7 @@ static void mult(BigInt& aRef, const BigInt& bRef) carry = z >> 16; uint32_t z2 = (*x++ >> 16) * y + (*xc >> 16) + carry; carry = z2 >> 16; - Storeinc(xc, z2, z); + xc = storeInc(xc, z2, z); } while (x < xae); *xc = carry; } @@ -532,28 +401,13 @@ static void mult(BigInt& aRef, const BigInt& bRef) do { z = (*x & 0xffff) * y + (*xc >> 16) + carry; carry = z >> 16; - Storeinc(xc, z, z2); + xc = storeInc(xc, z, z2); z2 = (*x++ >> 16) * y + (*xc & 0xffff) + carry; carry = z2 >> 16; } while (x < xae); *xc = z2; } } -#else - for(; xb < xbe; xc0++) { - if ((y = *xb++)) { - x = xa; - xc = xc0; - carry = 0; - do { - z = *x++ * y + *xc + carry; - carry = z >> 16; - *xc++ = z & 0xffff; - } while (x < xae); - *xc = carry; - } - } -#endif #endif for (xc0 = c.words(), xc = xc0 + wc; wc > 0 && !*--xc; --wc) { } c.resize(wc); @@ -561,12 +415,15 @@ static void mult(BigInt& aRef, const BigInt& bRef) } struct P5Node { + WTF_MAKE_NONCOPYABLE(P5Node); WTF_MAKE_FAST_ALLOCATED; +public: + P5Node() { } BigInt val; P5Node* next; }; - + static P5Node* p5s; -static int p5s_count; +static int p5sCount; static ALWAYS_INLINE void pow5mult(BigInt& b, int k) { @@ -578,7 +435,7 @@ static ALWAYS_INLINE void pow5mult(BigInt& b, int k) if (!(k >>= 2)) return; -#if ENABLE(JSC_MULTIPLE_THREADS) +#if ENABLE(WTF_MULTIPLE_THREADS) s_dtoaP5Mutex->lock(); #endif P5Node* p5 = p5s; @@ -589,14 +446,14 @@ static ALWAYS_INLINE void pow5mult(BigInt& b, int k) i2b(p5->val, 625); p5->next = 0; p5s = p5; - p5s_count = 1; + p5sCount = 1; } - int p5s_count_local = p5s_count; -#if ENABLE(JSC_MULTIPLE_THREADS) + int p5sCountLocal = p5sCount; +#if ENABLE(WTF_MULTIPLE_THREADS) s_dtoaP5Mutex->unlock(); #endif - int p5s_used = 0; + int p5sUsed = 0; for (;;) { if (k & 1) @@ -605,21 +462,21 @@ static ALWAYS_INLINE void pow5mult(BigInt& b, int k) if (!(k >>= 1)) break; - if (++p5s_used == p5s_count_local) { -#if ENABLE(JSC_MULTIPLE_THREADS) + if (++p5sUsed == p5sCountLocal) { +#if ENABLE(WTF_MULTIPLE_THREADS) s_dtoaP5Mutex->lock(); #endif - if (p5s_used == p5s_count) { + if (p5sUsed == p5sCount) { ASSERT(!p5->next); p5->next = new P5Node; p5->next->next = 0; p5->next->val = p5->val; mult(p5->next->val, p5->next->val); - ++p5s_count; + ++p5sCount; } - - p5s_count_local = p5s_count; -#if ENABLE(JSC_MULTIPLE_THREADS) + + p5sCountLocal = p5sCount; +#if ENABLE(WTF_MULTIPLE_THREADS) s_dtoaP5Mutex->unlock(); #endif } @@ -629,11 +486,7 @@ static ALWAYS_INLINE void pow5mult(BigInt& b, int k) static ALWAYS_INLINE void lshift(BigInt& b, int k) { -#ifdef Pack_32 int n = k >> 5; -#else - int n = k >> 4; -#endif int origSize = b.size(); int n1 = n + origSize + 1; @@ -647,7 +500,6 @@ static ALWAYS_INLINE void lshift(BigInt& b, int k) uint32_t* dstStart = b.words(); const uint32_t* src = srcStart + origSize - 1; uint32_t* dst = dstStart + n1 - 1; -#ifdef Pack_32 if (k) { uint32_t hiSubword = 0; int s = 32 - k; @@ -658,21 +510,8 @@ static ALWAYS_INLINE void lshift(BigInt& b, int k) *dst = hiSubword; ASSERT(dst == dstStart + n); - b.resize(origSize + n + (b.words()[n1 - 1] != 0)); + b.resize(origSize + n + !!b.words()[n1 - 1]); } -#else - if (k &= 0xf) { - uint32_t hiSubword = 0; - int s = 16 - k; - for (; src >= srcStart; --src) { - *dst-- = hiSubword | *src >> s; - hiSubword = (*src << k) & 0xffff; - } - *dst = hiSubword; - ASSERT(dst == dstStart + n); - result->wds = b->wds + n + (result->x[n1 - 1] != 0); - } - #endif else { do { *--dst = *src--; @@ -713,7 +552,7 @@ static ALWAYS_INLINE void diff(BigInt& c, const BigInt& aRef, const BigInt& bRef const BigInt* a = &aRef; const BigInt* b = &bRef; int i, wa, wb; - uint32_t *xc; + uint32_t* xc; i = cmp(*a, *b); if (!i) { @@ -754,33 +593,20 @@ static ALWAYS_INLINE void diff(BigInt& c, const BigInt& aRef, const BigInt& bRef } #else uint32_t borrow = 0; -#ifdef Pack_32 do { uint32_t y = (*xa & 0xffff) - (*xb & 0xffff) - borrow; borrow = (y & 0x10000) >> 16; uint32_t z = (*xa++ >> 16) - (*xb++ >> 16) - borrow; borrow = (z & 0x10000) >> 16; - Storeinc(xc, z, y); + xc = storeInc(xc, z, y); } while (xb < xbe); while (xa < xae) { uint32_t y = (*xa & 0xffff) - borrow; borrow = (y & 0x10000) >> 16; uint32_t z = (*xa++ >> 16) - borrow; borrow = (z & 0x10000) >> 16; - Storeinc(xc, z, y); + xc = storeInc(xc, z, y); } -#else - do { - uint32_t y = *xa++ - *xb++ - borrow; - borrow = (y & 0x10000) >> 16; - *xc++ = y & 0xffff; - } while (xb < xbe); - while (xa < xae) { - uint32_t y = *xa++ - borrow; - borrow = (y & 0x10000) >> 16; - *xc++ = y & 0xffff; - } -#endif #endif while (!*--xc) wa--; @@ -793,28 +619,8 @@ static double ulp(U *x) U u; L = (word0(x) & Exp_mask) - (P - 1) * Exp_msk1; -#ifndef Avoid_Underflow -#ifndef Sudden_Underflow - if (L > 0) { -#endif -#endif word0(&u) = L; word1(&u) = 0; -#ifndef Avoid_Underflow -#ifndef Sudden_Underflow - } else { - L = -L >> Exp_shift; - if (L < Exp_shift) { - word0(&u) = 0x80000 >> L; - word1(&u) = 0; - } else { - word0(&u) = 0; - L -= Exp_shift; - word1(&u) = L >= 31 ? 1 : 1 << 31 - L; - } - } -#endif -#endif return dval(&u); } @@ -837,12 +643,11 @@ static double b2d(const BigInt& a, int* e) ASSERT(y); k = hi0bits(y); *e = 32 - k; -#ifdef Pack_32 if (k < Ebits) { d0 = Exp_1 | (y >> (Ebits - k)); w = xa > xa0 ? *--xa : 0; d1 = (y << (32 - Ebits + k)) | (w >> (Ebits - k)); - goto ret_d; + goto returnD; } z = xa > xa0 ? *--xa : 0; if (k -= Ebits) { @@ -853,23 +658,7 @@ static double b2d(const BigInt& a, int* e) d0 = Exp_1 | y; d1 = z; } -#else - if (k < Ebits + 16) { - z = xa > xa0 ? *--xa : 0; - d0 = Exp_1 | y << k - Ebits | z >> Ebits + 16 - k; - w = xa > xa0 ? *--xa : 0; - y = xa > xa0 ? *--xa : 0; - d1 = z << k + 16 - Ebits | w << k - Ebits | y >> 16 + Ebits - k; - goto ret_d; - } - z = xa > xa0 ? *--xa : 0; - w = xa > xa0 ? *--xa : 0; - k -= Ebits + 16; - d0 = Exp_1 | y << k + 16 | z << k | w >> 16 - k; - y = xa > xa0 ? *--xa : 0; - d1 = w << k + 16 | y << k; -#endif -ret_d: +returnD: #undef d0 #undef d1 return dval(&d); @@ -878,105 +667,46 @@ ret_d: static ALWAYS_INLINE void d2b(BigInt& b, U* d, int* e, int* bits) { int de, k; - uint32_t *x, y, z; -#ifndef Sudden_Underflow + uint32_t* x; + uint32_t y, z; int i; -#endif #define d0 word0(d) #define d1 word1(d) b.sign = 0; -#ifdef Pack_32 b.resize(1); -#else - b.resize(2); -#endif x = b.words(); z = d0 & Frac_mask; d0 &= 0x7fffffff; /* clear sign bit, which we ignore */ -#ifdef Sudden_Underflow - de = (int)(d0 >> Exp_shift); -#else if ((de = (int)(d0 >> Exp_shift))) z |= Exp_msk1; -#endif -#ifdef Pack_32 if ((y = d1)) { if ((k = lo0bits(&y))) { x[0] = y | (z << (32 - k)); z >>= k; } else x[0] = y; - if (z) { - b.resize(2); - x[1] = z; - } + if (z) { + b.resize(2); + x[1] = z; + } -#ifndef Sudden_Underflow i = b.size(); -#endif } else { k = lo0bits(&z); x[0] = z; -#ifndef Sudden_Underflow i = 1; -#endif b.resize(1); k += 32; } -#else - if ((y = d1)) { - if ((k = lo0bits(&y))) { - if (k >= 16) { - x[0] = y | z << 32 - k & 0xffff; - x[1] = z >> k - 16 & 0xffff; - x[2] = z >> k; - i = 2; - } else { - x[0] = y & 0xffff; - x[1] = y >> 16 | z << 16 - k & 0xffff; - x[2] = z >> k & 0xffff; - x[3] = z >> k + 16; - i = 3; - } - } else { - x[0] = y & 0xffff; - x[1] = y >> 16; - x[2] = z & 0xffff; - x[3] = z >> 16; - i = 3; - } - } else { - k = lo0bits(&z); - if (k >= 16) { - x[0] = z; - i = 0; - } else { - x[0] = z & 0xffff; - x[1] = z >> 16; - i = 1; - } - k += 32; - } while (!x[i]) - --i; - b->resize(i + 1); -#endif -#ifndef Sudden_Underflow if (de) { -#endif *e = de - Bias - (P - 1) + k; *bits = P - k; -#ifndef Sudden_Underflow } else { *e = de - Bias - (P - 1) + 1 + k; -#ifdef Pack_32 *bits = (32 * i) - hi0bits(x[i - 1]); -#else - *bits = (i + 2) * 16 - hi0bits(x[i]); -#endif } -#endif } #undef d0 #undef d1 @@ -988,11 +718,7 @@ static double ratio(const BigInt& a, const BigInt& b) dval(&da) = b2d(a, &ka); dval(&db) = b2d(b, &kb); -#ifdef Pack_32 k = ka - kb + 32 * (a.size() - b.size()); -#else - k = ka - kb + 16 * (a.size() - b.size()); -#endif if (k > 0) word0(&da) += k * Exp_msk1; else { @@ -1003,19 +729,15 @@ static double ratio(const BigInt& a, const BigInt& b) } static const double tens[] = { - 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, - 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, - 1e20, 1e21, 1e22 + 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, + 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, + 1e20, 1e21, 1e22 }; static const double bigtens[] = { 1e16, 1e32, 1e64, 1e128, 1e256 }; static const double tinytens[] = { 1e-16, 1e-32, 1e-64, 1e-128, -#ifdef Avoid_Underflow - 9007199254740992. * 9007199254740992.e-256 - /* = 2^106 * 1e-53 */ -#else - 1e-256 -#endif + 9007199254740992. * 9007199254740992.e-256 + /* = 2^106 * 1e-256 */ }; /* The factor of 2^53 in tinytens[4] helps us avoid setting the underflow */ @@ -1023,118 +745,42 @@ static const double tinytens[] = { 1e-16, 1e-32, 1e-64, 1e-128, #define Scale_Bit 0x10 #define n_bigtens 5 -#if defined(INFNAN_CHECK) - -#ifndef NAN_WORD0 -#define NAN_WORD0 0x7ff80000 -#endif - -#ifndef NAN_WORD1 -#define NAN_WORD1 0 -#endif - -static int match(const char** sp, const char* t) -{ - int c, d; - const char* s = *sp; - - while ((d = *t++)) { - if ((c = *++s) >= 'A' && c <= 'Z') - c += 'a' - 'A'; - if (c != d) - return 0; - } - *sp = s + 1; - return 1; -} - -#ifndef No_Hex_NaN -static void hexnan(U* rvp, const char** sp) -{ - uint32_t c, x[2]; - const char* s; - int havedig, udx0, xshift; - - x[0] = x[1] = 0; - havedig = xshift = 0; - udx0 = 1; - s = *sp; - while ((c = *(const unsigned char*)++s)) { - if (c >= '0' && c <= '9') - c -= '0'; - else if (c >= 'a' && c <= 'f') - c += 10 - 'a'; - else if (c >= 'A' && c <= 'F') - c += 10 - 'A'; - else if (c <= ' ') { - if (udx0 && havedig) { - udx0 = 0; - xshift = 1; - } - continue; - } else if (/*(*/ c == ')' && havedig) { - *sp = s + 1; - break; - } else - return; /* invalid form: don't change *sp */ - havedig = 1; - if (xshift) { - xshift = 0; - x[0] = x[1]; - x[1] = 0; - } - if (udx0) - x[0] = (x[0] << 4) | (x[1] >> 28); - x[1] = (x[1] << 4) | c; - } - if ((x[0] &= 0xfffff) || x[1]) { - word0(rvp) = Exp_mask | x[0]; - word1(rvp) = x[1]; - } -} -#endif /*No_Hex_NaN*/ -#endif /* INFNAN_CHECK */ - double strtod(const char* s00, char** se) { -#ifdef Avoid_Underflow int scale; -#endif int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, dsign, - e, e1, esign, i, j, k, nd, nd0, nf, nz, nz0, sign; + e, e1, esign, i, j, k, nd, nd0, nf, nz, nz0, sign; const char *s, *s0, *s1; double aadj, aadj1; U aadj2, adj, rv, rv0; int32_t L; uint32_t y, z; BigInt bb, bb1, bd, bd0, bs, delta; -#ifdef SET_INEXACT - int inexact, oldinexact; -#endif sign = nz0 = nz = 0; dval(&rv) = 0; - for (s = s00; ; s++) + for (s = s00; ; s++) { switch (*s) { - case '-': - sign = 1; - /* no break */ - case '+': - if (*++s) - goto break2; - /* no break */ - case 0: - goto ret0; - case '\t': - case '\n': - case '\v': - case '\f': - case '\r': - case ' ': - continue; - default: + case '-': + sign = 1; + /* no break */ + case '+': + if (*++s) goto break2; + /* no break */ + case 0: + goto ret0; + case '\t': + case '\n': + case '\v': + case '\f': + case '\r': + case ' ': + continue; + default: + goto break2; } + } break2: if (*s == '0') { nz0 = 1; @@ -1159,12 +805,12 @@ break2: s0 = s; nf += nz; nz = 0; - goto have_dig; + goto haveDig; } - goto dig_done; + goto digDone; } for (; c >= '0' && c <= '9'; c = *++s) { -have_dig: +haveDig: nz++; if (c -= '0') { nf += nz; @@ -1181,19 +827,18 @@ have_dig: } } } -dig_done: +digDone: e = 0; if (c == 'e' || c == 'E') { - if (!nd && !nz && !nz0) { + if (!nd && !nz && !nz0) goto ret0; - } s00 = s; esign = 0; switch (c = *++s) { - case '-': - esign = 1; - case '+': - c = *++s; + case '-': + esign = 1; + case '+': + c = *++s; } if (c >= '0' && c <= '9') { while (c == '0') @@ -1219,33 +864,6 @@ dig_done: } if (!nd) { if (!nz && !nz0) { -#ifdef INFNAN_CHECK - /* Check for Nan and Infinity */ - switch(c) { - case 'i': - case 'I': - if (match(&s,"nf")) { - --s; - if (!match(&s,"inity")) - ++s; - word0(&rv) = 0x7ff00000; - word1(&rv) = 0; - goto ret; - } - break; - case 'n': - case 'N': - if (match(&s, "an")) { - word0(&rv) = NAN_WORD0; - word1(&rv) = NAN_WORD1; -#ifndef No_Hex_NaN - if (*s == '(') /*)*/ - hexnan(&rv, &s); -#endif - goto ret; - } - } -#endif /* INFNAN_CHECK */ ret0: s = s00; sign = 0; @@ -1263,14 +881,9 @@ ret0: nd0 = nd; k = nd < DBL_DIG + 1 ? nd : DBL_DIG + 1; dval(&rv) = y; - if (k > 9) { -#ifdef SET_INEXACT - if (k > DBL_DIG) - oldinexact = get_inexact(); -#endif + if (k > 9) dval(&rv) = tens[k - 9] * dval(&rv) + z; - } - if (nd <= DBL_DIG && Flt_Rounds == 1) { + if (nd <= DBL_DIG) { if (!e) goto ret; if (e > 0) { @@ -1288,24 +901,14 @@ ret0: /* rv = */ rounded_product(dval(&rv), tens[e]); goto ret; } - } -#ifndef Inaccurate_Divide - else if (e >= -Ten_pmax) { + } else if (e >= -Ten_pmax) { /* rv = */ rounded_quotient(dval(&rv), tens[-e]); goto ret; } -#endif } e1 += nd - k; -#ifdef SET_INEXACT - inexact = 1; - if (k <= DBL_DIG) - oldinexact = get_inexact(); -#endif -#ifdef Avoid_Underflow scale = 0; -#endif /* Get starting approximation = rv * 10**e1 */ @@ -1315,17 +918,12 @@ ret0: if (e1 &= ~15) { if (e1 > DBL_MAX_10_EXP) { ovfl: -#ifndef NO_ERRNO +#if HAVE(ERRNO_H) errno = ERANGE; #endif /* Can't trust HUGE_VAL */ word0(&rv) = Exp_mask; word1(&rv) = 0; -#ifdef SET_INEXACT - /* set overflow bit */ - dval(&rv0) = 1e300; - dval(&rv0) *= dval(&rv0); -#endif goto ret; } e1 >>= 4; @@ -1352,50 +950,30 @@ ovfl: if (e1 >>= 4) { if (e1 >= 1 << n_bigtens) goto undfl; -#ifdef Avoid_Underflow if (e1 & Scale_Bit) scale = 2 * P; for (j = 0; e1 > 0; j++, e1 >>= 1) if (e1 & 1) dval(&rv) *= tinytens[j]; if (scale && (j = (2 * P) + 1 - ((word0(&rv) & Exp_mask) >> Exp_shift)) > 0) { - /* scaled rv is denormal; zap j low bits */ + /* scaled rv is denormal; clear j low bits */ if (j >= 32) { word1(&rv) = 0; if (j >= 53) - word0(&rv) = (P + 2) * Exp_msk1; + word0(&rv) = (P + 2) * Exp_msk1; else - word0(&rv) &= 0xffffffff << (j - 32); + word0(&rv) &= 0xffffffff << (j - 32); } else word1(&rv) &= 0xffffffff << j; } -#else - for (j = 0; e1 > 1; j++, e1 >>= 1) - if (e1 & 1) - dval(&rv) *= tinytens[j]; - /* The last multiplication could underflow. */ - dval(&rv0) = dval(&rv); - dval(&rv) *= tinytens[j]; - if (!dval(&rv)) { - dval(&rv) = 2. * dval(&rv0); - dval(&rv) *= tinytens[j]; -#endif if (!dval(&rv)) { undfl: dval(&rv) = 0.; -#ifndef NO_ERRNO +#if HAVE(ERRNO_H) errno = ERANGE; #endif goto ret; } -#ifndef Avoid_Underflow - word0(&rv) = Tiny0; - word1(&rv) = Tiny1; - /* The refinement below will clean - * this approximation up. - */ - } -#endif } } @@ -1422,30 +1000,15 @@ undfl: else bd2 -= bbe; bs2 = bb2; -#ifdef Avoid_Underflow j = bbe - scale; i = j + bbbits - 1; /* logb(rv) */ if (i < Emin) /* denormal */ j += P - Emin; else j = P + 1 - bbbits; -#else /*Avoid_Underflow*/ -#ifdef Sudden_Underflow - j = P + 1 - bbbits; -#else /*Sudden_Underflow*/ - j = bbe; - i = j + bbbits - 1; /* logb(rv) */ - if (i < Emin) /* denormal */ - j += P - Emin; - else - j = P + 1 - bbbits; -#endif /*Sudden_Underflow*/ -#endif /*Avoid_Underflow*/ bb2 += j; bd2 += j; -#ifdef Avoid_Underflow bd2 += scale; -#endif i = bb2 < bd2 ? bb2 : bd2; if (i > bs2) i = bs2; @@ -1476,62 +1039,36 @@ undfl: * special case of mantissa a power of two. */ if (dsign || word1(&rv) || word0(&rv) & Bndry_mask -#ifdef Avoid_Underflow || (word0(&rv) & Exp_mask) <= (2 * P + 1) * Exp_msk1 -#else - || (word0(&rv) & Exp_mask) <= Exp_msk1 -#endif ) { -#ifdef SET_INEXACT - if (!delta->words()[0] && delta->size() <= 1) - inexact = 0; -#endif break; } if (!delta.words()[0] && delta.size() <= 1) { /* exact result */ -#ifdef SET_INEXACT - inexact = 0; -#endif break; } lshift(delta, Log2P); if (cmp(delta, bs) > 0) - goto drop_down; + goto dropDown; break; } - if (i == 0) { + if (!i) { /* exactly half-way between */ if (dsign) { if ((word0(&rv) & Bndry_mask1) == Bndry_mask1 && word1(&rv) == ( -#ifdef Avoid_Underflow (scale && (y = word0(&rv) & Exp_mask) <= 2 * P * Exp_msk1) ? (0xffffffff & (0xffffffff << (2 * P + 1 - (y >> Exp_shift)))) : -#endif 0xffffffff)) { /*boundary case -- increment exponent*/ word0(&rv) = (word0(&rv) & Exp_mask) + Exp_msk1; word1(&rv) = 0; -#ifdef Avoid_Underflow dsign = 0; -#endif break; } } else if (!(word0(&rv) & Bndry_mask) && !word1(&rv)) { -drop_down: +dropDown: /* boundary case -- decrement exponent */ -#ifdef Sudden_Underflow /*{{*/ - L = word0(&rv) & Exp_mask; -#ifdef Avoid_Underflow - if (L <= (scale ? (2 * P + 1) * Exp_msk1 : Exp_msk1)) -#else - if (L <= Exp_msk1) -#endif /*Avoid_Underflow*/ - goto undfl; - L -= Exp_msk1; -#else /*Sudden_Underflow}{*/ -#ifdef Avoid_Underflow if (scale) { L = word0(&rv) & Exp_mask; if (L <= (2 * P + 1) * Exp_msk1) { @@ -1543,9 +1080,7 @@ drop_down: goto undfl; } } -#endif /*Avoid_Underflow*/ L = (word0(&rv) & Exp_mask) - Exp_msk1; -#endif /*Sudden_Underflow}}*/ word0(&rv) = L | Bndry_mask1; word1(&rv) = 0xffffffff; break; @@ -1556,24 +1091,18 @@ drop_down: dval(&rv) += ulp(&rv); else { dval(&rv) -= ulp(&rv); -#ifndef Sudden_Underflow if (!dval(&rv)) goto undfl; -#endif } -#ifdef Avoid_Underflow dsign = 1 - dsign; -#endif break; } if ((aadj = ratio(delta, bs)) <= 2.) { if (dsign) aadj = aadj1 = 1.; else if (word1(&rv) || word0(&rv) & Bndry_mask) { -#ifndef Sudden_Underflow if (word1(&rv) == Tiny1 && !word0(&rv)) goto undfl; -#endif aadj = 1.; aadj1 = -1.; } else { @@ -1589,19 +1118,6 @@ drop_down: } else { aadj *= 0.5; aadj1 = dsign ? aadj : -aadj; -#ifdef Check_FLT_ROUNDS - switch (Rounding) { - case 2: /* towards +infinity */ - aadj1 -= 0.5; - break; - case 0: /* towards 0 */ - case 3: /* towards -infinity */ - aadj1 += 0.5; - } -#else - if (Flt_Rounds == 0) - aadj1 += 0.5; -#endif /*Check_FLT_ROUNDS*/ } y = word0(&rv) & Exp_mask; @@ -1618,10 +1134,9 @@ drop_down: word0(&rv) = Big0; word1(&rv) = Big1; goto cont; - } else - word0(&rv) += P * Exp_msk1; + } + word0(&rv) += P * Exp_msk1; } else { -#ifdef Avoid_Underflow if (scale && y <= 2 * P * Exp_msk1) { if (aadj <= 0x7fffffff) { if ((z = (uint32_t)aadj) <= 0) @@ -1635,51 +1150,9 @@ drop_down: } adj.d = aadj1 * ulp(&rv); dval(&rv) += adj.d; -#else -#ifdef Sudden_Underflow - if ((word0(&rv) & Exp_mask) <= P * Exp_msk1) { - dval(&rv0) = dval(&rv); - word0(&rv) += P * Exp_msk1; - adj.d = aadj1 * ulp(&rv); - dval(&rv) += adj.d; - if ((word0(&rv) & Exp_mask) <= P * Exp_msk1) - { - if (word0(&rv0) == Tiny0 && word1(&rv0) == Tiny1) - goto undfl; - word0(&rv) = Tiny0; - word1(&rv) = Tiny1; - goto cont; - } - else - word0(&rv) -= P * Exp_msk1; - } else { - adj.d = aadj1 * ulp(&rv); - dval(&rv) += adj.d; - } -#else /*Sudden_Underflow*/ - /* Compute adj so that the IEEE rounding rules will - * correctly round rv + adj in some half-way cases. - * If rv * ulp(rv) is denormalized (i.e., - * y <= (P - 1) * Exp_msk1), we must adjust aadj to avoid - * trouble from bits lost to denormalization; - * example: 1.2e-307 . - */ - if (y <= (P - 1) * Exp_msk1 && aadj > 1.) { - aadj1 = (double)(int)(aadj + 0.5); - if (!dsign) - aadj1 = -aadj1; - } - adj.d = aadj1 * ulp(&rv); - dval(&rv) += adj.d; -#endif /*Sudden_Underflow*/ -#endif /*Avoid_Underflow*/ } z = word0(&rv) & Exp_mask; -#ifndef SET_INEXACT -#ifdef Avoid_Underflow - if (!scale) -#endif - if (y == z) { + if (!scale && y == z) { /* Can we stop now? */ L = (int32_t)aadj; aadj -= L; @@ -1690,39 +1163,19 @@ drop_down: } else if (aadj < .4999999 / FLT_RADIX) break; } -#endif cont: - ; - } -#ifdef SET_INEXACT - if (inexact) { - if (!oldinexact) { - word0(&rv0) = Exp_1 + (70 << Exp_shift); - word1(&rv0) = 0; - dval(&rv0) += 1.; - } - } else if (!oldinexact) - clear_inexact(); -#endif -#ifdef Avoid_Underflow + {} + } if (scale) { word0(&rv0) = Exp_1 - 2 * P * Exp_msk1; word1(&rv0) = 0; dval(&rv) *= dval(&rv0); -#ifndef NO_ERRNO +#if HAVE(ERRNO_H) /* try to avoid the bug of testing an 8087 register value */ - if (word0(&rv) == 0 && word1(&rv) == 0) + if (!word0(&rv) && !word1(&rv)) errno = ERANGE; #endif } -#endif /* Avoid_Underflow */ -#ifdef SET_INEXACT - if (inexact && !(word0(&rv) & Exp_mask)) { - /* set underflow bit */ - dval(&rv0) = 1e-300; - dval(&rv0) *= dval(&rv0); - } -#endif ret: if (se) *se = const_cast(s); @@ -1732,14 +1185,16 @@ ret: static ALWAYS_INLINE int quorem(BigInt& b, BigInt& S) { size_t n; - uint32_t *bx, *bxe, q, *sx, *sxe; + uint32_t* bx; + uint32_t* bxe; + uint32_t q; + uint32_t* sx; + uint32_t* sxe; #ifdef USE_LONG_LONG unsigned long long borrow, carry, y, ys; #else uint32_t borrow, carry, y, ys; -#ifdef Pack_32 uint32_t si, z, zs; -#endif #endif ASSERT(b.size() <= 1 || b.words()[b.size() - 1]); ASSERT(S.size() <= 1 || S.words()[S.size() - 1]); @@ -1765,7 +1220,6 @@ static ALWAYS_INLINE int quorem(BigInt& b, BigInt& S) borrow = y >> 32 & (uint32_t)1; *bx++ = (uint32_t)y & 0xffffffffUL; #else -#ifdef Pack_32 si = *sx++; ys = (si & 0xffff) * q + carry; zs = (si >> 16) * q + (ys >> 16); @@ -1774,14 +1228,7 @@ static ALWAYS_INLINE int quorem(BigInt& b, BigInt& S) borrow = (y & 0x10000) >> 16; z = (*bx >> 16) - (zs & 0xffff) - borrow; borrow = (z & 0x10000) >> 16; - Storeinc(bx, z, y); -#else - ys = *sx++ * q + carry; - carry = ys >> 16; - y = *bx - (ys & 0xffff) - borrow; - borrow = (y & 0x10000) >> 16; - *bx++ = y & 0xffff; -#endif + bx = storeInc(bx, z, y); #endif } while (sx <= sxe); if (!*bxe) { @@ -1805,7 +1252,6 @@ static ALWAYS_INLINE int quorem(BigInt& b, BigInt& S) borrow = y >> 32 & (uint32_t)1; *bx++ = (uint32_t)y & 0xffffffffUL; #else -#ifdef Pack_32 si = *sx++; ys = (si & 0xffff) + carry; zs = (si >> 16) + (ys >> 16); @@ -1814,14 +1260,7 @@ static ALWAYS_INLINE int quorem(BigInt& b, BigInt& S) borrow = (y & 0x10000) >> 16; z = (*bx >> 16) - (zs & 0xffff) - borrow; borrow = (z & 0x10000) >> 16; - Storeinc(bx, z, y); -#else - ys = *sx++ + carry; - carry = ys >> 16; - y = *bx - (ys & 0xffff) - borrow; - borrow = (y & 0x10000) >> 16; - *bx++ = y & 0xffff; -#endif + bx = storeInc(bx, z, y); #endif } while (sx <= sxe); bx = b.words(); @@ -1838,7 +1277,7 @@ static ALWAYS_INLINE int quorem(BigInt& b, BigInt& S) /* 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]. + * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 112-126]. * * Modifications: * 1. Rather than iterating, we use a simple numeric overestimate @@ -1867,71 +1306,54 @@ static ALWAYS_INLINE int quorem(BigInt& b, BigInt& S) * "uniformly" distributed input, the probability is * something like 10^(k-15) that we must resort to the int32_t * calculation. + * + * Note: 'leftright' translates to 'generate shortest possible string'. */ - -void dtoa(char* result, double dd, int ndigits, int* decpt, int* sign, char** rve) +template +void dtoa(DtoaBuffer result, double dd, int ndigits, bool& signOut, int& exponentOut, unsigned& precisionOut) { - /* - 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. + // Exactly one rounding mode must be specified. + ASSERT(roundingNone + roundingSignificantFigures + roundingDecimalPlaces == 1); + // roundingNone only allowed (only sensible?) with leftright set. + ASSERT(!roundingNone || leftright); - */ + ASSERT(!isnan(dd) && !isinf(dd)); int bbits, b2, b5, be, dig, i, ieps, ilim = 0, ilim0, ilim1 = 0, - j, j1, k, k0, k_check, leftright, m2, m5, s2, s5, - spec_case, try_quick; + j, j1, k, k0, k_check, m2, m5, s2, s5, + spec_case; int32_t L; -#ifndef Sudden_Underflow int denorm; uint32_t x; -#endif - BigInt b, b1, delta, mlo, mhi, S; + BigInt b, delta, mlo, mhi, S; U d2, eps, u; double ds; - char *s, *s0; -#ifdef SET_INEXACT - int inexact, oldinexact; -#endif + char* s; + char* s0; u.d = dd; - if (word0(&u) & Sign_bit) { - /* set sign for everything, including 0's and NaNs */ - *sign = 1; - word0(&u) &= ~Sign_bit; /* clear sign bit */ - } else - *sign = 0; - if ((word0(&u) & Exp_mask) == Exp_mask) - { - /* Infinity or NaN */ - *decpt = 9999; - if (!word1(&u) && !(word0(&u) & 0xfffff)) - strcpy(result, "Infinity"); - else - strcpy(result, "NaN"); - return; - } + /* Infinity or NaN */ + ASSERT((word0(&u) & Exp_mask) != Exp_mask); + + // JavaScript toString conversion treats -0 as 0. if (!dval(&u)) { - *decpt = 1; + signOut = false; + exponentOut = 0; + precisionOut = 1; result[0] = '0'; result[1] = '\0'; return; } -#ifdef SET_INEXACT - try_quick = oldinexact = get_inexact(); - inexact = 1; -#endif + if (word0(&u) & Sign_bit) { + signOut = true; + word0(&u) &= ~Sign_bit; // clear sign bit + } else + signOut = false; d2b(b, &u, &be, &bbits); -#ifdef Sudden_Underflow - i = (int)(word0(&u) >> Exp_shift1 & (Exp_mask >> Exp_shift1)); -#else if ((i = (int)(word0(&u) >> Exp_shift1 & (Exp_mask >> Exp_shift1)))) { -#endif dval(&d2) = dval(&u); word0(&d2) &= Frac_mask1; word0(&d2) |= Exp_11; @@ -1959,7 +1381,6 @@ void dtoa(char* result, double dd, int ndigits, int* decpt, int* sign, char** rv */ i -= Bias; -#ifndef Sudden_Underflow denorm = 0; } else { /* d is denormalized */ @@ -1972,7 +1393,6 @@ void dtoa(char* result, double dd, int ndigits, int* decpt, int* sign, char** rv i -= (Bias + (P - 1) - 1) + 1; denorm = 1; } -#endif ds = (dval(&d2) - 1.5) * 0.289529654602168 + 0.1760912590558 + (i * 0.301029995663981); k = (int)ds; if (ds < 0. && ds != k) @@ -2001,22 +1421,27 @@ void dtoa(char* result, double dd, int ndigits, int* decpt, int* sign, char** rv s5 = 0; } -#ifndef SET_INEXACT -#ifdef Check_FLT_ROUNDS - try_quick = Rounding == 1; -#else - try_quick = 1; -#endif -#endif /*SET_INEXACT*/ + if (roundingNone) { + ilim = ilim1 = -1; + i = 18; + ndigits = 0; + } + if (roundingSignificantFigures) { + if (ndigits <= 0) + ndigits = 1; + ilim = ilim1 = i = ndigits; + } + if (roundingDecimalPlaces) { + i = ndigits + k + 1; + ilim = i; + ilim1 = i - 1; + if (i <= 0) + i = 1; + } - leftright = 1; - ilim = ilim1 = -1; - i = 18; - ndigits = 0; s = s0 = result; - if (ilim >= 0 && ilim <= Quick_max && try_quick) { - + if (ilim >= 0 && ilim <= Quick_max) { /* Try to get by with floating-point arithmetic. */ i = 0; @@ -2051,7 +1476,7 @@ void dtoa(char* result, double dd, int ndigits, int* decpt, int* sign, char** rv } if (k_check && dval(&u) < 1. && ilim > 0) { if (ilim1 <= 0) - goto fast_failed; + goto fastFailed; ilim = ilim1; k--; dval(&u) *= 10.; @@ -2059,17 +1484,16 @@ void dtoa(char* result, double dd, int ndigits, int* decpt, int* sign, char** rv } dval(&eps) = (ieps * dval(&u)) + 7.; word0(&eps) -= (P - 1) * Exp_msk1; - if (ilim == 0) { + if (!ilim) { S.clear(); mhi.clear(); dval(&u) -= 5.; if (dval(&u) > dval(&eps)) - goto one_digit; + goto oneDigit; if (dval(&u) < -dval(&eps)) - goto no_digits; - goto fast_failed; + goto noDigits; + goto fastFailed; } -#ifndef No_leftright if (leftright) { /* Use Steele & White method of only * generating digits needed. @@ -2082,14 +1506,13 @@ void dtoa(char* result, double dd, int ndigits, int* decpt, int* sign, char** rv if (dval(&u) < dval(&eps)) goto ret; if (1. - dval(&u) < dval(&eps)) - goto bump_up; + goto bumpUp; if (++i >= ilim) break; dval(&eps) *= 10.; dval(&u) *= 10.; } } else { -#endif /* Generate ilim digits, then fix them up. */ dval(&eps) *= tens[ilim - 1]; for (i = 1;; i++, dval(&u) *= 10.) { @@ -2099,8 +1522,8 @@ void dtoa(char* result, double dd, int ndigits, int* decpt, int* sign, char** rv *s++ = '0' + (int)L; if (i == ilim) { if (dval(&u) > 0.5 + dval(&eps)) - goto bump_up; - else if (dval(&u) < 0.5 - dval(&eps)) { + goto bumpUp; + if (dval(&u) < 0.5 - dval(&eps)) { while (*--s == '0') { } s++; goto ret; @@ -2108,10 +1531,8 @@ void dtoa(char* result, double dd, int ndigits, int* decpt, int* sign, char** rv break; } } -#ifndef No_leftright } -#endif -fast_failed: +fastFailed: s = s0; dval(&u) = dval(&d2); k = k0; @@ -2127,30 +1548,20 @@ fast_failed: S.clear(); mhi.clear(); if (ilim < 0 || dval(&u) <= 5 * ds) - goto no_digits; - goto one_digit; + goto noDigits; + goto oneDigit; } for (i = 1;; i++, dval(&u) *= 10.) { L = (int32_t)(dval(&u) / ds); dval(&u) -= L * ds; -#ifdef Check_FLT_ROUNDS - /* If FLT_ROUNDS == 2, L will usually be high by 1 */ - if (dval(&u) < 0) { - L--; - dval(&u) += ds; - } -#endif *s++ = '0' + (int)L; if (!dval(&u)) { -#ifdef SET_INEXACT - inexact = 0; -#endif break; } if (i == ilim) { dval(&u) += dval(&u); if (dval(&u) > ds || (dval(&u) == ds && (L & 1))) { -bump_up: +bumpUp: while (*--s == '9') if (s == s0) { k++; @@ -2170,11 +1581,7 @@ bump_up: mhi.clear(); mlo.clear(); if (leftright) { - i = -#ifndef Sudden_Underflow - denorm ? be + (Bias + (P - 1) - 1 + 1) : -#endif - 1 + P - bbits; + i = denorm ? be + (Bias + (P - 1) - 1 + 1) : 1 + P - bbits; b2 += i; s2 += i; i2b(mhi, 1); @@ -2195,7 +1602,7 @@ bump_up: pow5mult(b, j); } else pow5mult(b, b5); - } + } i2b(S, 1); if (s5 > 0) pow5mult(S, s5); @@ -2203,11 +1610,7 @@ bump_up: /* Check for special case that d is a normalized power of 2. */ spec_case = 0; - if (!word1(&u) && !(word0(&u) & Bndry_mask) -#ifndef Sudden_Underflow - && word0(&u) & (Exp_mask & ~Exp_msk1) -#endif - ) { + if ((roundingNone || leftright) && (!word1(&u) && !(word0(&u) & Bndry_mask) && word0(&u) & (Exp_mask & ~Exp_msk1))) { /* The special case */ b2 += Log2P; s2 += Log2P; @@ -2221,13 +1624,8 @@ bump_up: * and for all and pass them and a shift to quorem, so it * can do shifts and ors to compute the numerator for q. */ -#ifdef Pack_32 if ((i = ((s5 ? 32 - hi0bits(S.words()[S.size() - 1]) : 1) + s2) & 0x1f)) i = 32 - i; -#else - if ((i = ((s5 ? 32 - hi0bits(S.words()[S.size() - 1]) : 1) + s2) & 0xf)) - i = 16 - i; -#endif if (i > 4) { i -= 4; b2 += i; @@ -2244,7 +1642,7 @@ bump_up: if (s2 > 0) lshift(S, s2); if (k_check) { - if (cmp(b,S) < 0) { + if (cmp(b, S) < 0) { k--; multadd(b, 10, 0); /* we botched the k estimate */ if (leftright) @@ -2252,7 +1650,15 @@ bump_up: ilim = ilim1; } } - + if (ilim <= 0 && roundingDecimalPlaces) { + if (ilim < 0) + goto noDigits; + multadd(S, 5, 0); + // For IEEE-754 unbiased rounding this check should be <=, such that 0.5 would flush to zero. + if (cmp(b, S) < 0) + goto noDigits; + goto oneDigit; + } if (leftright) { if (m2 > 0) lshift(mhi, m2); @@ -2262,51 +1668,60 @@ bump_up: */ mlo = mhi; - if (spec_case) { - mhi = mlo; + if (spec_case) lshift(mhi, Log2P); - } for (i = 1;;i++) { - dig = quorem(b,S) + '0'; + dig = quorem(b, S) + '0'; /* Do we yet have the shortest decimal string * that will round to d? */ j = cmp(b, mlo); diff(delta, S, mhi); j1 = delta.sign ? 1 : cmp(b, delta); - if (j1 == 0 && !(word1(&u) & 1)) { +#ifdef DTOA_ROUND_BIASED + if (j < 0 || !j) { +#else + // FIXME: ECMA-262 specifies that equidistant results round away from + // zero, which probably means we shouldn't be on the unbiased code path + // (the (word1(&u) & 1) clause is looking highly suspicious). I haven't + // yet understood this code well enough to make the call, but we should + // probably be enabling DTOA_ROUND_BIASED. I think the interesting corner + // case to understand is probably "Math.pow(0.5, 24).toString()". + // I believe this value is interesting because I think it is precisely + // representable in binary floating point, and its decimal representation + // has a single digit that Steele & White reduction can remove, with the + // value 5 (thus equidistant from the next numbers above and below). + // We produce the correct answer using either codepath, and I don't as + // yet understand why. :-) + if (!j1 && !(word1(&u) & 1)) { if (dig == '9') - goto round_9_up; + goto round9up; if (j > 0) dig++; -#ifdef SET_INEXACT - else if (!b->x[0] && b->wds <= 1) - inexact = 0; -#endif *s++ = dig; goto ret; } - if (j < 0 || (j == 0 && !(word1(&u) & 1))) { - if (!b.words()[0] && b.size() <= 1) { -#ifdef SET_INEXACT - inexact = 0; + if (j < 0 || (!j && !(word1(&u) & 1))) { #endif - goto accept_dig; - } - if (j1 > 0) { + if ((b.words()[0] || b.size() > 1) && (j1 > 0)) { lshift(b, 1); j1 = cmp(b, S); - if ((j1 > 0 || (j1 == 0 && (dig & 1))) && dig++ == '9') - goto round_9_up; + // For IEEE-754 round-to-even, this check should be (j1 > 0 || (!j1 && (dig & 1))), + // but ECMA-262 specifies that equidistant values (e.g. (.5).toFixed()) should + // be rounded away from zero. + if (j1 >= 0) { + if (dig == '9') + goto round9up; + dig++; + } } -accept_dig: *s++ = dig; goto ret; } if (j1 > 0) { if (dig == '9') { /* possible if i == 1 */ -round_9_up: +round9up: *s++ = '9'; goto roundoff; } @@ -2320,25 +1735,25 @@ round_9_up: multadd(mlo, 10, 0); multadd(mhi, 10, 0); } - } else + } else { for (i = 1;; i++) { - *s++ = dig = quorem(b,S) + '0'; - if (!b.words()[0] && b.size() <= 1) { -#ifdef SET_INEXACT - inexact = 0; -#endif + *s++ = dig = quorem(b, S) + '0'; + if (!b.words()[0] && b.size() <= 1) goto ret; - } if (i >= ilim) break; multadd(b, 10, 0); } + } /* Round off last digit */ lshift(b, 1); j = cmp(b, S); - if (j > 0 || (j == 0 && (dig & 1))) { + // For IEEE-754 round-to-even, this check should be (j > 0 || (!j && (dig & 1))), + // but ECMA-262 specifies that equidistant values (e.g. (.5).toFixed()) should + // be rounded away from zero. + if (j >= 0) { roundoff: while (*--s == '9') if (s == s0) { @@ -2352,28 +1767,68 @@ roundoff: s++; } goto ret; -no_digits: - k = -1 - ndigits; - goto ret; -one_digit: +noDigits: + exponentOut = 0; + precisionOut = 1; + result[0] = '0'; + result[1] = '\0'; + return; +oneDigit: *s++ = '1'; k++; goto ret; ret: -#ifdef SET_INEXACT - if (inexact) { - if (!oldinexact) { - word0(&u) = Exp_1 + (70 << Exp_shift); - word1(&u) = 0; - dval(&u) += 1.; - } - } else if (!oldinexact) - clear_inexact(); -#endif + ASSERT(s > result); *s = 0; - *decpt = k + 1; - if (rve) - *rve = s; + exponentOut = k; + precisionOut = s - result; +} + +void dtoa(DtoaBuffer result, double dd, bool& sign, int& exponent, unsigned& precision) +{ + // flags are roundingNone, leftright. + dtoa(result, dd, 0, sign, exponent, precision); +} + +void dtoaRoundSF(DtoaBuffer result, double dd, int ndigits, bool& sign, int& exponent, unsigned& precision) +{ + // flag is roundingSignificantFigures. + dtoa(result, dd, ndigits, sign, exponent, precision); +} + +void dtoaRoundDP(DtoaBuffer result, double dd, int ndigits, bool& sign, int& exponent, unsigned& precision) +{ + // flag is roundingDecimalPlaces. + dtoa(result, dd, ndigits, sign, exponent, precision); +} + +static ALWAYS_INLINE void copyAsciiToUTF16(UChar* next, const char* src, unsigned size) +{ + for (unsigned i = 0; i < size; ++i) + *next++ = *src++; +} + +unsigned numberToString(double d, NumberToStringBuffer buffer) +{ + // Handle NaN and Infinity. + if (isnan(d) || isinf(d)) { + if (isnan(d)) { + copyAsciiToUTF16(buffer, "NaN", 3); + return 3; + } + if (d > 0) { + copyAsciiToUTF16(buffer, "Infinity", 8); + return 8; + } + copyAsciiToUTF16(buffer, "-Infinity", 9); + return 9; + } + + // Convert to decimal with rounding. + DecimalNumber number(d); + return number.exponent() >= -6 && number.exponent() < 21 + ? number.toStringDecimal(buffer, NumberToStringBufferLength) + : number.toStringExponential(buffer, NumberToStringBufferLength); } } // namespace WTF