]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - wtf/dtoa.cpp
JavaScriptCore-903.tar.gz
[apple/javascriptcore.git] / wtf / dtoa.cpp
index d75c17a9338daad47395023a10ebaa6eb2a62444..b162543e9169acb230297defa6d405ca806e0858 100644 (file)
@@ -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
  *
  ***************************************************************/
 
-/* 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
  *        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 <errno.h>
-#else
-#define NO_ERRNO
 #endif
 #include <float.h>
 #include <math.h>
 #include <stdint.h>
+#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <wtf/AlwaysInline.h>
 #include <wtf/Assertions.h>
+#include <wtf/DecimalNumber.h>
 #include <wtf/FastMalloc.h>
-#include <wtf/Vector.h>
+#include <wtf/MathExtras.h>
 #include <wtf/Threading.h>
-
-#include <stdio.h>
+#include <wtf/UnusedParam.h>
+#include <wtf/Vector.h>
 
 #if COMPILER(MSVC)
 #pragma warning(disable: 4244)
 #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<uint16_t*>(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<uint32_t, 16> 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_txc;
 
     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<char*>(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<bool roundingNone, bool roundingSignificantFigures, bool roundingDecimalPlaces, bool leftright>
+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<true, false, false, true>(result, dd, 0, sign, exponent, precision);
+}
+
+void dtoaRoundSF(DtoaBuffer result, double dd, int ndigits, bool& sign, int& exponent, unsigned& precision)
+{
+    // flag is roundingSignificantFigures.
+    dtoa<false, true, false, false>(result, dd, ndigits, sign, exponent, precision);
+}
+
+void dtoaRoundDP(DtoaBuffer result, double dd, int ndigits, bool& sign, int& exponent, unsigned& precision)
+{
+    // flag is roundingDecimalPlaces.
+    dtoa<false, false, true, false>(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