[SCM] WebKit Debian packaging branch, debian/experimental, updated. upstream/1.3.3-9427-gc2be6fc

barraclough at apple.com barraclough at apple.com
Wed Dec 22 12:43:07 UTC 2010


The following commit has been merged in the debian/experimental branch:
commit 03f3c62ae3eea1220c7866832b12eb85484b869d
Author: barraclough at apple.com <barraclough at apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date:   Fri Aug 27 20:12:01 2010 +0000

    Bug 44745 - Number.toFixed/toExponential/toPrecision are inaccurate.
    
    Reviewed by Oliver Hunt.
    
    These methods should be using a version of dtoa that can generate results accurate
    to the requested precision, whereas our version of dtoa is only currently able to
    support producing results sufficiently accurate to distinguish the value from any
    other IEEE-754 double precision number.
    
    JavaScriptCore:
    
    This change has no impact on benchmarks we track.
    
    On microbenchmarks for these functions, this is a slight regression where a high
    precision is requested (dtoa now need to iterate further to generate a a greater
    number of digits), but with smaller precision values (hopefully more common) this
    improves performance, since it reduced the accurate of result dtoa is required,
    to produce, and removes the need to pre-round values before calling dtoa.
    
    * JavaScriptCore.exp:
        doubleToStringInJavaScriptFormat renamed to numberToString
    
    * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def:
        doubleToStringInJavaScriptFormat renamed to numberToString
    
    * runtime/UString.cpp:
    (JSC::UString::number):
        doubleToStringInJavaScriptFormat renamed to numberToString
    
    * wtf/DecimalNumber.h:
    (WTF::DecimalNumber::DecimalNumber):
    (WTF::DecimalNumber::toStringDecimal):
    (WTF::DecimalNumber::toStringExponential):
        Remove all pre-rounding of values, instead call dtoa correctly.
    
    * wtf/dtoa.cpp:
    (WTF::dtoa):
    * wtf/dtoa.h:
        Reenable support for rounding to specific-figures/decimal-places in dtoa.
        Modify to remove unbiased rounding, provide ECMA required away-from-zero.
        Rewrite doubleToStringInJavaScriptFormat to use DecimalNumber, rename to
        numberToString.
    
    WebCore:
    
    * html/HTMLTreeBuilder.cpp:
    (WebCore::serializeForNumberType):
        doubleToStringInJavaScriptFormat renamed to numberToString.
    
    LayoutTests:
    
    Updating expected results, corrected errors in fast/js/kde/script-tests/Number.js
    (corrected results confirmed with FireFox).
    
    * fast/js/kde/Number-expected.txt:
    * fast/js/kde/script-tests/Number.js:
    * fast/js/number-toExponential-expected.txt:
    * fast/js/number-tofixed-expected.txt:
    * fast/js/number-toprecision-expected.txt:
    
    
    
    git-svn-id: http://svn.webkit.org/repository/webkit/trunk@66245 268f45cc-cd09-0410-ab3c-d52691b4dbfc

diff --git a/JavaScriptCore/ChangeLog b/JavaScriptCore/ChangeLog
index 34b6c13..90c6f97 100644
--- a/JavaScriptCore/ChangeLog
+++ b/JavaScriptCore/ChangeLog
@@ -1,3 +1,46 @@
+2010-08-27  Gavin Barraclough  <barraclough at apple.com>
+
+        Reviewed by Oliver Hunt.
+
+        Bug 44745 - Number.toFixed/toExponential/toPrecision are inaccurate.
+
+        These methods should be using a version of dtoa that can generate results accurate
+        to the requested precision, whereas our version of dtoa is only currently able to
+        support producing results sufficiently accurate to distinguish the value from any
+        other IEEE-754 double precision number.
+
+        This change has no impact on benchmarks we track.
+
+        On microbenchmarks for these functions, this is a slight regression where a high
+        precision is requested (dtoa now need to iterate further to generate a a greater
+        number of digits), but with smaller precision values (hopefully more common) this
+        improves performance, since it reduced the accurate of result dtoa is required,
+        to produce, and removes the need to pre-round values before calling dtoa. 
+
+        * JavaScriptCore.exp:
+            doubleToStringInJavaScriptFormat renamed to numberToString
+
+        * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def:
+            doubleToStringInJavaScriptFormat renamed to numberToString
+
+        * runtime/UString.cpp:
+        (JSC::UString::number):
+            doubleToStringInJavaScriptFormat renamed to numberToString
+
+        * wtf/DecimalNumber.h:
+        (WTF::DecimalNumber::DecimalNumber):
+        (WTF::DecimalNumber::toStringDecimal):
+        (WTF::DecimalNumber::toStringExponential):
+            Remove all pre-rounding of values, instead call dtoa correctly.
+
+        * wtf/dtoa.cpp:
+        (WTF::dtoa):
+        * wtf/dtoa.h:
+            Reenable support for rounding to specific-figures/decimal-places in dtoa.
+            Modify to remove unbiased rounding, provide ECMA required away-from-zero.
+            Rewrite doubleToStringInJavaScriptFormat to use DecimalNumber, rename to
+            numberToString.
+
 2010-08-27  Chao-ying Fu  <fu at mips.com>
 
         Reviewed by Oliver Hunt.
diff --git a/JavaScriptCore/JavaScriptCore.exp b/JavaScriptCore/JavaScriptCore.exp
index 4131e23..30f5aa8 100644
--- a/JavaScriptCore/JavaScriptCore.exp
+++ b/JavaScriptCore/JavaScriptCore.exp
@@ -377,6 +377,7 @@ __ZN3WTF13currentThreadEv
 __ZN3WTF13tryFastCallocEmm
 __ZN3WTF13tryFastMallocEm
 __ZN3WTF14fastMallocSizeEPKv
+__ZN3WTF14numberToStringEdPt
 __ZN3WTF15ThreadCondition4waitERNS_5MutexE
 __ZN3WTF15ThreadCondition6signalEv
 __ZN3WTF15ThreadCondition9broadcastEv
@@ -411,7 +412,6 @@ __ZN3WTF23dayInMonthFromDayInYearEib
 __ZN3WTF23waitForThreadCompletionEjPPv
 __ZN3WTF27releaseFastMallocFreeMemoryEv
 __ZN3WTF28setMainThreadCallbacksPausedEb
-__ZN3WTF32doubleToStringInJavaScriptFormatEdPcPj
 __ZN3WTF36lockAtomicallyInitializedStaticMutexEv
 __ZN3WTF37parseDateFromNullTerminatedCharactersEPKc
 __ZN3WTF38unlockAtomicallyInitializedStaticMutexEv
diff --git a/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def b/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def
index 934688f..4291651 100644
--- a/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def
+++ b/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def
@@ -126,7 +126,6 @@ EXPORTS
     ?detach at Debugger@JSC@@UAEXPAVJSGlobalObject at 2@@Z
     ?detachThread at WTF@@YAXI at Z
     ?didTimeOut at TimeoutChecker@JSC@@QAE_NPAVExecState at 2@@Z
-    ?doubleToStringInJavaScriptFormat at WTF@@YAXNQADPAI at Z
     ?dumpSampleData at JSGlobalData@JSC@@QAEXPAVExecState at 2@@Z
     ?empty at StringImpl@WTF@@SAPAV12 at XZ
     ?enumerable at PropertyDescriptor@JSC@@QBE_NXZ
@@ -149,6 +148,7 @@ EXPORTS
     ?number at UString@JSC@@SA?AV12 at H@Z
     ?number at UString@JSC@@SA?AV12 at I@Z
     ?number at UString@JSC@@SA?AV12 at N@Z
+    ?numberToString at WTF@@YAINAAY0GA at _W@Z
     ?functionGetter at PropertySlot@JSC@@ABE?AVJSValue at 2@PAVExecState at 2@@Z
     ?functionName at DebuggerCallFrame@JSC@@QBEPBVUString at 2@XZ
     ?get at Structure@JSC@@QAEIPBVStringImpl at WTF@@AAIAAPAVJSCell at 2@@Z
diff --git a/JavaScriptCore/runtime/UString.cpp b/JavaScriptCore/runtime/UString.cpp
index 78e349b..17cd9b6 100644
--- a/JavaScriptCore/runtime/UString.cpp
+++ b/JavaScriptCore/runtime/UString.cpp
@@ -26,7 +26,6 @@
 
 #include "JSGlobalObjectFunctions.h"
 #include "Collector.h"
-#include "dtoa.h"
 #include "Identifier.h"
 #include "Operations.h"
 #include <ctype.h>
@@ -36,6 +35,7 @@
 #include <stdlib.h>
 #include <wtf/ASCIICType.h>
 #include <wtf/Assertions.h>
+#include <wtf/DecimalNumber.h>
 #include <wtf/MathExtras.h>
 #include <wtf/StringExtras.h>
 #include <wtf/Vector.h>
@@ -198,9 +198,8 @@ UString UString::number(long l)
 
 UString UString::number(double d)
 {
-    DtoaBuffer buffer;
-    unsigned length;
-    doubleToStringInJavaScriptFormat(d, buffer, &length);
+    NumberToStringBuffer buffer;
+    unsigned length = numberToString(d, buffer);
     return UString(buffer, length);
 }
 
diff --git a/JavaScriptCore/wtf/DecimalNumber.h b/JavaScriptCore/wtf/DecimalNumber.h
index a3e51b9..3a831b7 100644
--- a/JavaScriptCore/wtf/DecimalNumber.h
+++ b/JavaScriptCore/wtf/DecimalNumber.h
@@ -33,9 +33,6 @@
 
 namespace WTF {
 
-// Size = 80 for sizeof(DtoaBuffer) + some sign bits, decimal point, 'e', exponent digits.
-typedef UChar NumberToStringBuffer[96];
-
 enum RoundingSignificantFiguresType { RoundingSignificantFigures };
 enum RoundingDecimalPlacesType { RoundingDecimalPlaces };
 
@@ -43,111 +40,48 @@ class DecimalNumber {
 public:
     DecimalNumber(double d)
     {
-        bool sign = d < 0; // This (correctly) ignores the sign on -0.0.
-        init(sign, d);
+        ASSERT(!isnan(d) && !isinf(d));
+        dtoa(m_significand, d, m_sign, m_exponent, m_precision);
+
+        ASSERT(m_precision);
+        // Zero should always have exponent 0.
+        ASSERT(m_significand[0] != '0' || !m_exponent);
+        // No values other than zero should have a leading zero.
+        ASSERT(m_significand[0] != '0' || m_precision == 1);
+        // No values other than zero should have trailing zeros.
+        ASSERT(m_significand[0] == '0' || m_significand[m_precision - 1] != '0');
     }
 
-    // If our version of dtoa could round to a given number of significant figures then
-    // we could remove the pre-rounding code from here.  We could also do so just by
-    // calling dtoa and post-rounding, however currently this is slower, since it forces
-    // dtoa to generate a higher presision result.
     DecimalNumber(double d, RoundingSignificantFiguresType, unsigned significantFigures)
     {
         ASSERT(!isnan(d) && !isinf(d));
-        ASSERT(significantFigures && significantFigures <= 21);
-
-        bool sign = d < 0; // This (correctly) ignores the sign on -0.0.
-        d = fabs(d); // make d positive before going any further.
-
-        int adjust = 0;
-        if (d) {
-            // To round a number we align it such that the correct number of digits are
-            // to the left of the decimal point, then floor/ceil.  For example, to round
-            // 13579 to 3 s.f. we first adjust it to 135.79, use floor/ceil to obtain the
-            // values 135/136, and then select 136 (since this is closest to 135.79).
-            // There are currently (exp + 1) digits to the left of the decimal point,
-            // and we want thsi to be significantFigures, so we're going to adjust the
-            // exponent by ((exp + 1) - significantFigures).  Adjust is effectively
-            // a count of how many decimal digits to right-shift the number by.
-            int exp = static_cast<int>(floor(log10(d)));
-            adjust = (exp + 1) - significantFigures;
-
-            // If the adjust value might be positive or negative - or zero.  If zero, then
-            // nothing to do! - the number is already appropriately aligned.  If adjust
-            // is positive then divide d by 10^adjust.  If adjust is negative multiply d
-            // by 10^-adjust. This is mathematically the same, but avoids two fp divides
-            // (one inside intPow10, where the power is negative).
-            if (adjust > 0)
-                d /= intPow10(adjust);
-            else if (adjust < 0)
-                d *= intPow10(-adjust);
-
-            // Try rounding up & rounding down, select whichever is closest (rounding up if equal distance).
-            double floorOfD = floor(d);
-            double ceilOfD = floorOfD + 1;
-            d = (fabs(ceilOfD - d) <= fabs(floorOfD - d)) ? ceilOfD : floorOfD;
-
-            // The number's exponent has been altered - but don't change it back!  We can
-            // just run dtoa on the modified value, and adjust the exponent afterward to
-            // account for this.
-        }
-
-        init(sign, d);
+        dtoaRoundSF(m_significand, d, significantFigures, m_sign, m_exponent, m_precision);
 
-        // We alterered the value when rounding it - modify the exponent to adjust for this,
-        // but don't mess with the exponent of zero.
-        if (!isZero())
-            m_exponent += adjust;
+        ASSERT(significantFigures && significantFigures <= sizeof(DtoaBuffer));
+        while (m_precision < significantFigures)
+            m_significand[m_precision++] = '0';
 
-        // Make sure the significand does not contain more digits than requested.
-        roundToPrecision(significantFigures);
+        ASSERT(m_precision);
+        // Zero should always have exponent 0.
+        ASSERT(m_significand[0] != '0' || !m_exponent);
     }
 
-    // If our version of dtoa could round to a given number of decimal places then we
-    // could remove the pre-rounding code from here.  We could also do so just by calling
-    // dtoa and post-rounding, however currently this is slower, since it forces dtoa to
-    // generate a higher presision result.
     DecimalNumber(double d, RoundingDecimalPlacesType, unsigned decimalPlaces)
     {
         ASSERT(!isnan(d) && !isinf(d));
-        ASSERT(decimalPlaces <= 20);
-
-        bool sign = d < 0; // This (correctly) ignores the sign on -0.0.
-        d = fabs(d); // Make d positive before going any further.
-
-        ASSERT(d < 1e+21); // We don't currently support rounding to decimal places for values >= 1e+21.
-
-        // Adjust the number by increasing the exponent by decimalPlaces, such
-        // that we can round to this number of decimal places jsing floor.
-        if (decimalPlaces)
-            d *= intPow10(decimalPlaces);
-        // Try rounding up & rounding down, select whichever is closest (rounding up if equal distance).
-        double floorOfD = floor(d);
-        double ceilOfD = floorOfD + 1;
-        d = (fabs(ceilOfD - d) <= fabs(floorOfD - d)) ? ceilOfD : floorOfD;
-        // The number's exponent has been altered - but don't change it back!  We can
-        // just run dtoa on the modified value, and adjust the exponent afterward to
-        // account for this.
-
-        init(sign, d);
-
-        // We rouned the value before calling dtoa, so the result should not be fractional.
-        ASSERT(m_exponent >= 0);
-
-        // We alterered the value when rounding it - modify the exponent to adjust for this,
-        // but don't mess with the exponent of zero.
-        if (!isZero())
-            m_exponent -= decimalPlaces;
-
-        // The value was < 1e+21 before we started, should still be.
-        ASSERT(m_exponent < 21);
+        dtoaRoundDP(m_significand, d, decimalPlaces, m_sign, m_exponent, m_precision);
 
         unsigned significantFigures = 1 + m_exponent + decimalPlaces;
-        ASSERT(significantFigures && significantFigures <= 41);
-        roundToPrecision(significantFigures);
+        ASSERT(significantFigures && significantFigures <= sizeof(DtoaBuffer));
+        while (m_precision < significantFigures)
+            m_significand[m_precision++] = '0';
+
+        ASSERT(m_precision);
+        // Zero should always have exponent 0.
+        ASSERT(m_significand[0] != '0' || !m_exponent);
     }
 
-    unsigned toStringDecimal(NumberToStringBuffer& buffer)
+    unsigned toStringDecimal(NumberToStringBuffer buffer)
     {
         // Should always be at least one digit to add to the string!
         ASSERT(m_precision);
@@ -201,7 +135,7 @@ public:
         return next - buffer;
     }
 
-    unsigned toStringExponential(NumberToStringBuffer &buffer)
+    unsigned toStringExponential(NumberToStringBuffer buffer)
     {
         // Should always be at least one digit to add to the string!
         ASSERT(m_precision);
@@ -247,75 +181,6 @@ public:
     unsigned precision() { return m_precision; }
 
 private:
-    void init(bool sign, double d)
-    {
-        ASSERT(!isnan(d) && !isinf(d));
-
-        int decimalPoint;
-        int signUnused;
-        char* resultEnd = 0;
-        WTF::dtoa(m_significand, d, 0, &decimalPoint, &signUnused, &resultEnd);
-
-        m_sign = sign;
-        m_precision = resultEnd - m_significand;
-        m_exponent = decimalPoint - 1;
-
-        // No values other than zero should have a leading zero.
-        ASSERT(m_significand[0] != '0' || m_precision == 1);
-        // Zero should always have exponent 0.
-        ASSERT(m_significand[0] != '0' || !m_exponent);
-    }
-
-    bool isZero()
-    {
-        return m_significand[0] == '0';
-    }
-
-    // We pre-round the values to dtoa - which leads to it generating faster results.
-    // But dtoa won't have zero padded the significand to the precision we require,
-    // and also might have produced too many digits if rounding went wrong somehow.
-    // Adjust for this.
-    void roundToPrecision(unsigned significantFigures)
-    {
-        ASSERT(significantFigures && significantFigures <= sizeof(DtoaBuffer));
-
-        // If there are too few of too many digits in the significand then add more, or remove some!
-        for (unsigned i = m_precision; i < significantFigures; ++i)
-            m_significand[i] = '0';
-        m_precision = significantFigures;
-    }
-
-    double intPow10(int e)
-    {
-        // This function uses the "exponentiation by squaring" algorithm and
-        // long double to quickly and precisely calculate integer powers of 10.0.
-
-        // This is a handy workaround for <rdar://problem/4494756>
-
-        if (!e)
-            return 1.0;
-
-        bool negative = e < 0;
-        unsigned exp = negative ? -e : e;
-
-        long double result = 10.0;
-        bool foundOne = false;
-        for (int bit = 31; bit >= 0; bit--) {
-            if (!foundOne) {
-                if ((exp >> bit) & 1)
-                    foundOne = true;
-            } else {
-                result = result * result;
-                if ((exp >> bit) & 1)
-                    result = result * 10.0;
-            }
-        }
-
-        if (negative)
-            return static_cast<double>(1.0 / result);
-        return static_cast<double>(result);
-    }
-
     bool m_sign;
     int m_exponent;
     DtoaBuffer m_significand;
@@ -324,7 +189,6 @@ private:
 
 } // namespace WTF
 
-using WTF::NumberToStringBuffer;
 using WTF::DecimalNumber;
 using WTF::RoundingSignificantFigures;
 using WTF::RoundingDecimalPlaces;
diff --git a/JavaScriptCore/wtf/dtoa.cpp b/JavaScriptCore/wtf/dtoa.cpp
index 832627b..298bb27 100644
--- a/JavaScriptCore/wtf/dtoa.cpp
+++ b/JavaScriptCore/wtf/dtoa.cpp
@@ -75,6 +75,7 @@
 #include <string.h>
 #include <wtf/AlwaysInline.h>
 #include <wtf/Assertions.h>
+#include <wtf/DecimalNumber.h>
 #include <wtf/FastMalloc.h>
 #include <wtf/MathExtras.h>
 #include <wtf/Threading.h>
@@ -1302,21 +1303,21 @@ 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(DtoaBuffer 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)
 {
-    ASSERT(!isnan(dd) && !isinf(dd));
+    // Exactly one rounding mode must be specified.
+    ASSERT(roundingNone + roundingSignificantFigures + roundingDecimalPlaces == 1);
+    // roundingNone only allowed (only sensible?) with leftright set.
+    ASSERT(!roundingNone || leftright);
 
-    /*
-        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.
-    */
+    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,
+        j, j1, k, k0, k_check, m2, m5, s2, s5,
         spec_case;
     int32_t L;
     int denorm;
@@ -1328,25 +1329,26 @@ void dtoa(DtoaBuffer result, double dd, int ndigits, int* decpt, int* sign, char
     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;
 
     /* 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';
-        if (rve)
-            *rve = result + 1;
         return;
     }
 
+    if (word0(&u) & Sign_bit) {
+        signOut = true;
+        word0(&u) &= ~Sign_bit; // clear sign bit
+    } else
+        signOut = false;
+
     d2b(b, &u, &be, &bbits);
     if ((i = (int)(word0(&u) >> Exp_shift1 & (Exp_mask >> Exp_shift1)))) {
         dval(&d2) = dval(&u);
@@ -1416,10 +1418,24 @@ void dtoa(DtoaBuffer result, double dd, int ndigits, int* decpt, int* sign, char
         s5 = 0;
     }
 
-    leftright = 1;
-    ilim = ilim1 = -1;
-    i = 18;
-    ndigits = 0;
+    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;
+    }
+
     s = s0 = result;
 
     if (ilim >= 0 && ilim <= Quick_max) {
@@ -1591,7 +1607,7 @@ bumpUp:
     /* Check for special case that d is a normalized power of 2. */
 
     spec_case = 0;
-    if (!word1(&u) && !(word0(&u) & Bndry_mask) && word0(&u) & (Exp_mask & ~Exp_msk1)) {
+    if ((roundingNone || leftright) && (!word1(&u) && !(word0(&u) & Bndry_mask) && word0(&u) & (Exp_mask & ~Exp_msk1))) {
         /* The special case */
         b2 += Log2P;
         s2 += Log2P;
@@ -1631,7 +1647,15 @@ bumpUp:
             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);
@@ -1652,6 +1676,21 @@ bumpUp:
             j = cmp(b, mlo);
             diff(delta, S, mhi);
             j1 = delta.sign ? 1 : cmp(b, delta);
+#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 round9up;
@@ -1661,10 +1700,14 @@ bumpUp:
                 goto ret;
             }
             if (j < 0 || (!j && !(word1(&u) & 1))) {
+#endif
                 if ((b.words()[0] || b.size() > 1) && (j1 > 0)) {
                     lshift(b, 1);
                     j1 = cmp(b, S);
-                    if (j1 > 0 || (!j1 && (dig & 1))) {
+                    // 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++;
@@ -1689,22 +1732,25 @@ round9up:
             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) {
+            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 && (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) {
@@ -1719,107 +1765,67 @@ roundoff:
     }
     goto ret;
 noDigits:
-    k = -1 - ndigits;
-    goto ret;
+    exponentOut = 0;
+    precisionOut = 1;
+    result[0] = '0';
+    result[1] = '\0';
+    return;
 oneDigit:
     *s++ = '1';
     k++;
     goto ret;
 ret:
+    ASSERT(s > result);
     *s = 0;
-    *decpt = k + 1;
-    if (rve)
-        *rve = s;
+    exponentOut = k;
+    precisionOut = s - result;
 }
 
-static ALWAYS_INLINE void append(char*& next, const char* src, unsigned size)
+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++;
 }
 
-void doubleToStringInJavaScriptFormat(double d, DtoaBuffer buffer, unsigned* resultLength)
+unsigned numberToString(double d, NumberToStringBuffer buffer)
 {
-    ASSERT(buffer);
-
     // Handle NaN and Infinity.
     if (isnan(d) || isinf(d)) {
         if (isnan(d)) {
-            append(buffer, "NaN", 3);
-            if (resultLength)
-                *resultLength = 3;
-        } else if (d > 0) {
-            append(buffer, "Infinity", 8);
-            if (resultLength)
-                *resultLength = 8;
-        } else {
-            append(buffer, "-Infinity", 9);
-            if (resultLength)
-                *resultLength = 9;
-        }
-        return;
-    }
-
-    // -0 -> "0"
-    if (!d) {
-        buffer[0] = '0';
-        if (resultLength)
-            *resultLength = 1;
-        return;
-    }
-
-    int decimalPoint;
-    int sign;
-
-    DtoaBuffer result;
-    char* resultEnd = 0;
-    WTF::dtoa(result, d, 0, &decimalPoint, &sign, &resultEnd);
-    int length = resultEnd - result;
-
-    char* next = buffer;
-    if (sign)
-        *next++ = '-';
-
-    if (decimalPoint <= 0 && decimalPoint > -6) {
-        *next++ = '0';
-        *next++ = '.';
-        for (int j = decimalPoint; j < 0; j++)
-            *next++ = '0';
-        append(next, result, length);
-    } else if (decimalPoint <= 21 && decimalPoint > 0) {
-        if (length <= decimalPoint) {
-            append(next, result, length);
-            for (int j = 0; j < decimalPoint - length; j++)
-                *next++ = '0';
-        } else {
-            append(next, result, decimalPoint);
-            *next++ = '.';
-            append(next, result + decimalPoint, length - decimalPoint);
+            copyAsciiToUTF16(buffer, "NaN", 3);
+            return 3;
         }
-    } else if (result[0] < '0' || result[0] > '9')
-        append(next, result, length);
-    else {
-        *next++ = result[0];
-        if (length > 1) {
-            *next++ = '.';
-            append(next, result + 1, length - 1);
+        if (d > 0) {
+            copyAsciiToUTF16(buffer, "Infinity", 8);
+            return 8;
         }
+        copyAsciiToUTF16(buffer, "-Infinity", 9);
+        return 9;
+    }
 
-        *next++ = 'e';
-        *next++ = (decimalPoint >= 0) ? '+' : '-';
-        // decimalPoint can't be more than 3 digits decimal given the
-        // nature of float representation
-        int exponential = decimalPoint - 1;
-        if (exponential < 0)
-            exponential = -exponential;
-        if (exponential >= 100)
-            *next++ = static_cast<char>('0' + exponential / 100);
-        if (exponential >= 10)
-            *next++ = static_cast<char>('0' + (exponential % 100) / 10);
-        *next++ = static_cast<char>('0' + exponential % 10);
-    }
-    if (resultLength)
-        *resultLength = next - buffer;
+    // Convert to decimal with rounding.
+    DecimalNumber number(d);
+    return number.exponent() >= -6 && number.exponent() < 21
+        ? number.toStringDecimal(buffer)
+        : number.toStringExponential(buffer);
 }
 
 } // namespace WTF
diff --git a/JavaScriptCore/wtf/dtoa.h b/JavaScriptCore/wtf/dtoa.h
index e0938ff..7e4fc41 100644
--- a/JavaScriptCore/wtf/dtoa.h
+++ b/JavaScriptCore/wtf/dtoa.h
@@ -21,11 +21,10 @@
 #ifndef WTF_dtoa_h
 #define WTF_dtoa_h
 
-namespace WTF {
-class Mutex;
-}
+#include <wtf/unicode/Unicode.h>
 
 namespace WTF {
+class Mutex;
 
 extern WTF::Mutex* s_dtoaP5Mutex;
 
@@ -34,16 +33,18 @@ extern WTF::Mutex* s_dtoaP5Mutex;
 double strtod(const char* s00, char** se);
 
 typedef char DtoaBuffer[80];
-void dtoa(DtoaBuffer result, double d, int ndigits, int* decpt, int* sign, char** rve);
 
-// dtoa() for ECMA-262 'ToString Applied to the Number Type.'
-// The *resultLength will have the length of the resultant string in bufer.
-// The resultant string isn't terminated by 0.
-void doubleToStringInJavaScriptFormat(double, DtoaBuffer, unsigned* resultLength);
+void dtoa(DtoaBuffer result, double dd, bool& sign, int& exponent, unsigned& precision);
+void dtoaRoundSF(DtoaBuffer result, double dd, int ndigits, bool& sign, int& exponent, unsigned& precision);
+void dtoaRoundDP(DtoaBuffer result, double dd, int ndigits, bool& sign, int& exponent, unsigned& precision);
+
+// Size = 80 for sizeof(DtoaBuffer) + some sign bits, decimal point, 'e', exponent digits.
+typedef UChar NumberToStringBuffer[96];
+unsigned numberToString(double, NumberToStringBuffer);
 
 } // namespace WTF
 
-using WTF::DtoaBuffer;
-using WTF::doubleToStringInJavaScriptFormat;
+using WTF::NumberToStringBuffer;
+using WTF::numberToString;
 
 #endif // WTF_dtoa_h
diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index adea28d..768f338 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,23 @@
+2010-08-27  Gavin Barraclough  <barraclough at apple.com>
+
+        Reviewed by Oliver Hunt.
+
+        Bug 44745 - Number.toFixed/toExponential/toPrecision are inaccurate.
+
+        These methods should be using a version of dtoa that can generate results accurate
+        to the requested precision, whereas our version of dtoa is only currently able to
+        support producing results sufficiently accurate to distinguish the value from any
+        other IEEE-754 double precision number.
+
+        Updating expected results, corrected errors in fast/js/kde/script-tests/Number.js
+        (corrected results confirmed with FireFox).
+
+        * fast/js/kde/Number-expected.txt:
+        * fast/js/kde/script-tests/Number.js:
+        * fast/js/number-toExponential-expected.txt:
+        * fast/js/number-tofixed-expected.txt:
+        * fast/js/number-toprecision-expected.txt:
+
 2010-08-27  Tony Chang  <tony at chromium.org>
 
         Unreviewed.  Add google-chrome linux ia32 results.  These are slightly
diff --git a/LayoutTests/fast/js/kde/Number-expected.txt b/LayoutTests/fast/js/kde/Number-expected.txt
index cb50804..f2b2015 100644
--- a/LayoutTests/fast/js/kde/Number-expected.txt
+++ b/LayoutTests/fast/js/kde/Number-expected.txt
@@ -93,10 +93,10 @@ PASS Number(123.456).toExponential(13) is "1.2345600000000e+2"
 PASS Number(123.456).toExponential(14) is "1.23456000000000e+2"
 PASS Number(123.456).toExponential(15) is "1.234560000000000e+2"
 PASS Number(123.456).toExponential(16) is "1.2345600000000000e+2"
-PASS Number(123.456).toExponential(17) is "1.23456000000000000e+2"
-PASS Number(123.456).toExponential(18) is "1.234560000000000000e+2"
-PASS Number(123.456).toExponential(19) is "1.2345600000000000000e+2"
-PASS Number(123.456).toExponential(20) is "1.23456000000000000000e+2"
+PASS Number(123.456).toExponential(17) is "1.23456000000000003e+2"
+PASS Number(123.456).toExponential(18) is "1.234560000000000031e+2"
+PASS Number(123.456).toExponential(19) is "1.2345600000000000307e+2"
+PASS Number(123.456).toExponential(20) is "1.23456000000000003070e+2"
 PASS try { Number(123.456).toExponential(21) } catch (e) { String(e).indexOf('Range') >= 0; } is true
 PASS Number(-123.456).toExponential() is "-1.23456e+2"
 PASS try { Number(-123.456).toExponential(-1) } catch (e) { String(e).indexOf('Range') >= 0; } is true
@@ -117,10 +117,10 @@ PASS Number(-123.456).toExponential(13) is "-1.2345600000000e+2"
 PASS Number(-123.456).toExponential(14) is "-1.23456000000000e+2"
 PASS Number(-123.456).toExponential(15) is "-1.234560000000000e+2"
 PASS Number(-123.456).toExponential(16) is "-1.2345600000000000e+2"
-PASS Number(-123.456).toExponential(17) is "-1.23456000000000000e+2"
-PASS Number(-123.456).toExponential(18) is "-1.234560000000000000e+2"
-PASS Number(-123.456).toExponential(19) is "-1.2345600000000000000e+2"
-PASS Number(-123.456).toExponential(20) is "-1.23456000000000000000e+2"
+PASS Number(-123.456).toExponential(17) is "-1.23456000000000003e+2"
+PASS Number(-123.456).toExponential(18) is "-1.234560000000000031e+2"
+PASS Number(-123.456).toExponential(19) is "-1.2345600000000000307e+2"
+PASS Number(-123.456).toExponential(20) is "-1.23456000000000003070e+2"
 PASS try { Number(-123.456).toExponential(21) } catch (e) { String(e).indexOf('Range') >= 0; } is true
 PASS Number(.000123456).toExponential() is "1.23456e-4"
 PASS try { Number(.000123456).toExponential(-1) } catch (e) { String(e).indexOf('Range') >= 0; } is true
@@ -140,11 +140,11 @@ PASS Number(.000123456).toExponential(12) is "1.234560000000e-4"
 PASS Number(.000123456).toExponential(13) is "1.2345600000000e-4"
 PASS Number(.000123456).toExponential(14) is "1.23456000000000e-4"
 PASS Number(.000123456).toExponential(15) is "1.234560000000000e-4"
-PASS Number(.000123456).toExponential(16) is "1.2345600000000000e-4"
-PASS Number(.000123456).toExponential(17) is "1.23456000000000000e-4"
-PASS Number(.000123456).toExponential(18) is "1.234560000000000000e-4"
-PASS Number(.000123456).toExponential(19) is "1.2345600000000000000e-4"
-PASS Number(.000123456).toExponential(20) is "1.23456000000000000000e-4"
+PASS Number(.000123456).toExponential(16) is "1.2345600000000001e-4"
+PASS Number(.000123456).toExponential(17) is "1.23456000000000005e-4"
+PASS Number(.000123456).toExponential(18) is "1.234560000000000052e-4"
+PASS Number(.000123456).toExponential(19) is "1.2345600000000000519e-4"
+PASS Number(.000123456).toExponential(20) is "1.23456000000000005188e-4"
 PASS try { Number(.000123456).toExponential(21) } catch (e) { String(e).indexOf('Range') >= 0; } is true
 PASS Number(-.000123456).toExponential() is "-1.23456e-4"
 PASS try { Number(-.000123456).toExponential(-1) } catch (e) { String(e).indexOf('Range') >= 0; } is true
@@ -164,11 +164,11 @@ PASS Number(-.000123456).toExponential(12) is "-1.234560000000e-4"
 PASS Number(-.000123456).toExponential(13) is "-1.2345600000000e-4"
 PASS Number(-.000123456).toExponential(14) is "-1.23456000000000e-4"
 PASS Number(-.000123456).toExponential(15) is "-1.234560000000000e-4"
-PASS Number(-.000123456).toExponential(16) is "-1.2345600000000000e-4"
-PASS Number(-.000123456).toExponential(17) is "-1.23456000000000000e-4"
-PASS Number(-.000123456).toExponential(18) is "-1.234560000000000000e-4"
-PASS Number(-.000123456).toExponential(19) is "-1.2345600000000000000e-4"
-PASS Number(-.000123456).toExponential(20) is "-1.23456000000000000000e-4"
+PASS Number(-.000123456).toExponential(16) is "-1.2345600000000001e-4"
+PASS Number(-.000123456).toExponential(17) is "-1.23456000000000005e-4"
+PASS Number(-.000123456).toExponential(18) is "-1.234560000000000052e-4"
+PASS Number(-.000123456).toExponential(19) is "-1.2345600000000000519e-4"
+PASS Number(-.000123456).toExponential(20) is "-1.23456000000000005188e-4"
 PASS try { Number(-.000123456).toExponential(21) } catch (e) { String(e).indexOf('Range') >= 0; } is true
 PASS Number(123.4567890123456789012).toExponential() is "1.2345678901234568e+2"
 PASS try { Number(123.4567890123456789012).toExponential(-1) } catch (e) { String(e).indexOf('Range') >= 0; } is true
@@ -189,10 +189,10 @@ PASS Number(123.4567890123456789012).toExponential(13) is "1.2345678901235e+2"
 PASS Number(123.4567890123456789012).toExponential(14) is "1.23456789012346e+2"
 PASS Number(123.4567890123456789012).toExponential(15) is "1.234567890123457e+2"
 PASS Number(123.4567890123456789012).toExponential(16) is "1.2345678901234568e+2"
-PASS Number(123.4567890123456789012).toExponential(17) is "1.23456789012345680e+2"
-PASS Number(123.4567890123456789012).toExponential(18) is "1.234567890123456800e+2"
-PASS Number(123.4567890123456789012).toExponential(19) is "1.2345678901234567000e+2"
-PASS Number(123.4567890123456789012).toExponential(20) is "1.23456789012345680000e+2"
+PASS Number(123.4567890123456789012).toExponential(17) is "1.23456789012345681e+2"
+PASS Number(123.4567890123456789012).toExponential(18) is "1.234567890123456806e+2"
+PASS Number(123.4567890123456789012).toExponential(19) is "1.2345678901234568059e+2"
+PASS Number(123.4567890123456789012).toExponential(20) is "1.23456789012345680590e+2"
 PASS try { Number(123.4567890123456789012).toExponential(21) } catch (e) { String(e).indexOf('Range') >= 0; } is true
 PASS Number(-123.4567890123456789012).toExponential() is "-1.2345678901234568e+2"
 PASS try { Number(-123.4567890123456789012).toExponential(-1) } catch (e) { String(e).indexOf('Range') >= 0; } is true
@@ -213,10 +213,10 @@ PASS Number(-123.4567890123456789012).toExponential(13) is "-1.2345678901235e+2"
 PASS Number(-123.4567890123456789012).toExponential(14) is "-1.23456789012346e+2"
 PASS Number(-123.4567890123456789012).toExponential(15) is "-1.234567890123457e+2"
 PASS Number(-123.4567890123456789012).toExponential(16) is "-1.2345678901234568e+2"
-PASS Number(-123.4567890123456789012).toExponential(17) is "-1.23456789012345680e+2"
-PASS Number(-123.4567890123456789012).toExponential(18) is "-1.234567890123456800e+2"
-PASS Number(-123.4567890123456789012).toExponential(19) is "-1.2345678901234567000e+2"
-PASS Number(-123.4567890123456789012).toExponential(20) is "-1.23456789012345680000e+2"
+PASS Number(-123.4567890123456789012).toExponential(17) is "-1.23456789012345681e+2"
+PASS Number(-123.4567890123456789012).toExponential(18) is "-1.234567890123456806e+2"
+PASS Number(-123.4567890123456789012).toExponential(19) is "-1.2345678901234568059e+2"
+PASS Number(-123.4567890123456789012).toExponential(20) is "-1.23456789012345680590e+2"
 PASS try { Number(-123.4567890123456789012).toExponential(21) } catch (e) { String(e).indexOf('Range') >= 0; } is true
 PASS Number(.0000000000000000000001).toExponential() is "1e-22"
 PASS Number(.0000000000000000000012).toExponential() is "1.2e-21"
@@ -348,11 +348,11 @@ PASS Number(0.0001234567890123456789012345).toPrecision(13) is "0.00012345678901
 PASS Number(0.0001234567890123456789012345).toPrecision(14) is "0.00012345678901235"
 PASS Number(0.0001234567890123456789012345).toPrecision(15) is "0.000123456789012346"
 PASS Number(0.0001234567890123456789012345).toPrecision(16) is "0.0001234567890123457"
-FAIL Number(0.0001234567890123456789012345).toPrecision(17) should be 0.00012345678901234567. Was 0.00012345678901234568.
-FAIL Number(0.0001234567890123456789012345).toPrecision(18) should be 0.000123456789012345671. Was 0.000123456789012345660.
-FAIL Number(0.0001234567890123456789012345).toPrecision(19) should be 0.0001234567890123456713. Was 0.0001234567890123456800.
-FAIL Number(0.0001234567890123456789012345).toPrecision(20) should be 0.00012345678901234567130. Was 0.00012345678901234565000.
-FAIL Number(0.0001234567890123456789012345).toPrecision(21) should be 0.000123456789012345671297. Was 0.000123456789012345670000.
+PASS Number(0.0001234567890123456789012345).toPrecision(17) is "0.00012345678901234567"
+PASS Number(0.0001234567890123456789012345).toPrecision(18) is "0.000123456789012345671"
+PASS Number(0.0001234567890123456789012345).toPrecision(19) is "0.0001234567890123456713"
+PASS Number(0.0001234567890123456789012345).toPrecision(20) is "0.00012345678901234567130"
+PASS Number(0.0001234567890123456789012345).toPrecision(21) is "0.000123456789012345671298"
 PASS Number(12345.67890123456789012345).toPrecision() is "12345.678901234567"
 PASS Number(12345.67890123456789012345).toPrecision(1) is "1e+4"
 PASS Number(12345.67890123456789012345).toPrecision(2) is "1.2e+4"
@@ -370,11 +370,11 @@ PASS Number(12345.67890123456789012345).toPrecision(13) is "12345.67890123"
 PASS Number(12345.67890123456789012345).toPrecision(14) is "12345.678901235"
 PASS Number(12345.67890123456789012345).toPrecision(15) is "12345.6789012346"
 PASS Number(12345.67890123456789012345).toPrecision(16) is "12345.67890123457"
-PASS Number(12345.67890123456789012345).toPrecision(17) is "12345.678901234568"
-PASS Number(12345.67890123456789012345).toPrecision(18) is "12345.6789012345660"
-PASS Number(12345.67890123456789012345).toPrecision(19) is "12345.67890123456800"
-PASS Number(12345.67890123456789012345).toPrecision(20) is "12345.678901234567000"
-PASS Number(12345.67890123456789012345).toPrecision(21) is "12345.6789012345670000"
+PASS Number(12345.67890123456789012345).toPrecision(17) is "12345.678901234567"
+PASS Number(12345.67890123456789012345).toPrecision(18) is "12345.6789012345671"
+PASS Number(12345.67890123456789012345).toPrecision(19) is "12345.67890123456709"
+PASS Number(12345.67890123456789012345).toPrecision(20) is "12345.678901234567093"
+PASS Number(12345.67890123456789012345).toPrecision(21) is "12345.6789012345670926"
 PASS Number(-.0000000012345).toPrecision(2) is "-1.2e-9"
 PASS Number(-.000000012345).toPrecision(2) is "-1.2e-8"
 PASS Number(-.00000012345).toPrecision(2) is "-1.2e-7"
@@ -408,11 +408,11 @@ PASS Number(-0.0001234567890123456789012345).toPrecision(13) is "-0.000123456789
 PASS Number(-0.0001234567890123456789012345).toPrecision(14) is "-0.00012345678901235"
 PASS Number(-0.0001234567890123456789012345).toPrecision(15) is "-0.000123456789012346"
 PASS Number(-0.0001234567890123456789012345).toPrecision(16) is "-0.0001234567890123457"
-FAIL Number(-0.0001234567890123456789012345).toPrecision(17) should be -0.00012345678901234567. Was -0.00012345678901234568.
-FAIL Number(-0.0001234567890123456789012345).toPrecision(18) should be -0.000123456789012345671. Was -0.000123456789012345660.
-FAIL Number(-0.0001234567890123456789012345).toPrecision(19) should be -0.0001234567890123456713. Was -0.0001234567890123456800.
-FAIL Number(-0.0001234567890123456789012345).toPrecision(20) should be -0.00012345678901234567130. Was -0.00012345678901234565000.
-FAIL Number(-0.0001234567890123456789012345).toPrecision(21) should be -0.000123456789012345671297. Was -0.000123456789012345670000.
+PASS Number(-0.0001234567890123456789012345).toPrecision(17) is "-0.00012345678901234567"
+PASS Number(-0.0001234567890123456789012345).toPrecision(18) is "-0.000123456789012345671"
+PASS Number(-0.0001234567890123456789012345).toPrecision(19) is "-0.0001234567890123456713"
+PASS Number(-0.0001234567890123456789012345).toPrecision(20) is "-0.00012345678901234567130"
+PASS Number(-0.0001234567890123456789012345).toPrecision(21) is "-0.000123456789012345671298"
 PASS Number(-12345.67890123456789012345).toPrecision() is "-12345.678901234567"
 PASS Number(-12345.67890123456789012345).toPrecision(1) is "-1e+4"
 PASS Number(-12345.67890123456789012345).toPrecision(2) is "-1.2e+4"
@@ -430,11 +430,11 @@ PASS Number(-12345.67890123456789012345).toPrecision(13) is "-12345.67890123"
 PASS Number(-12345.67890123456789012345).toPrecision(14) is "-12345.678901235"
 PASS Number(-12345.67890123456789012345).toPrecision(15) is "-12345.6789012346"
 PASS Number(-12345.67890123456789012345).toPrecision(16) is "-12345.67890123457"
-PASS Number(-12345.67890123456789012345).toPrecision(17) is "-12345.678901234568"
-PASS Number(-12345.67890123456789012345).toPrecision(18) is "-12345.6789012345660"
-PASS Number(-12345.67890123456789012345).toPrecision(19) is "-12345.67890123456800"
-PASS Number(-12345.67890123456789012345).toPrecision(20) is "-12345.678901234567000"
-PASS Number(-12345.67890123456789012345).toPrecision(21) is "-12345.6789012345670000"
+PASS Number(-12345.67890123456789012345).toPrecision(17) is "-12345.678901234567"
+PASS Number(-12345.67890123456789012345).toPrecision(18) is "-12345.6789012345671"
+PASS Number(-12345.67890123456789012345).toPrecision(19) is "-12345.67890123456709"
+PASS Number(-12345.67890123456789012345).toPrecision(20) is "-12345.678901234567093"
+PASS Number(-12345.67890123456789012345).toPrecision(21) is "-12345.6789012345670926"
 PASS Number(0).toPrecision() is "0"
 PASS Number(0).toPrecision(1) is "0"
 PASS Number(0).toPrecision(2) is "0.0"
diff --git a/LayoutTests/fast/js/kde/script-tests/Number.js b/LayoutTests/fast/js/kde/script-tests/Number.js
index 05db865..2315e0a 100644
--- a/LayoutTests/fast/js/kde/script-tests/Number.js
+++ b/LayoutTests/fast/js/kde/script-tests/Number.js
@@ -108,10 +108,10 @@ shouldBe("Number(123.456).toExponential(13)","\"1.2345600000000e+2\"");
 shouldBe("Number(123.456).toExponential(14)","\"1.23456000000000e+2\"");
 shouldBe("Number(123.456).toExponential(15)","\"1.234560000000000e+2\"");
 shouldBe("Number(123.456).toExponential(16)","\"1.2345600000000000e+2\"");
-shouldBe("Number(123.456).toExponential(17)","\"1.23456000000000000e+2\"");
-shouldBe("Number(123.456).toExponential(18)","\"1.234560000000000000e+2\"");
-shouldBe("Number(123.456).toExponential(19)","\"1.2345600000000000000e+2\"");
-shouldBe("Number(123.456).toExponential(20)","\"1.23456000000000000000e+2\"");
+shouldBe("Number(123.456).toExponential(17)","\"1.23456000000000003e+2\"");
+shouldBe("Number(123.456).toExponential(18)","\"1.234560000000000031e+2\"");
+shouldBe("Number(123.456).toExponential(19)","\"1.2345600000000000307e+2\"");
+shouldBe("Number(123.456).toExponential(20)","\"1.23456000000000003070e+2\"");
 shouldBeTrue("try { Number(123.456).toExponential(21) } catch (e) { String(e).indexOf('Range') >= 0; }");
 shouldBe("Number(-123.456).toExponential()","\"-1.23456e+2\"");
 shouldBeTrue("try { Number(-123.456).toExponential(-1) } catch (e) { String(e).indexOf('Range') >= 0; }");
@@ -132,10 +132,10 @@ shouldBe("Number(-123.456).toExponential(13)","\"-1.2345600000000e+2\"");
 shouldBe("Number(-123.456).toExponential(14)","\"-1.23456000000000e+2\"");
 shouldBe("Number(-123.456).toExponential(15)","\"-1.234560000000000e+2\"");
 shouldBe("Number(-123.456).toExponential(16)","\"-1.2345600000000000e+2\"");
-shouldBe("Number(-123.456).toExponential(17)","\"-1.23456000000000000e+2\"");
-shouldBe("Number(-123.456).toExponential(18)","\"-1.234560000000000000e+2\"");
-shouldBe("Number(-123.456).toExponential(19)","\"-1.2345600000000000000e+2\"");
-shouldBe("Number(-123.456).toExponential(20)","\"-1.23456000000000000000e+2\"");
+shouldBe("Number(-123.456).toExponential(17)","\"-1.23456000000000003e+2\"");
+shouldBe("Number(-123.456).toExponential(18)","\"-1.234560000000000031e+2\"");
+shouldBe("Number(-123.456).toExponential(19)","\"-1.2345600000000000307e+2\"");
+shouldBe("Number(-123.456).toExponential(20)","\"-1.23456000000000003070e+2\"");
 shouldBeTrue("try { Number(-123.456).toExponential(21) } catch (e) { String(e).indexOf('Range') >= 0; }");
 shouldBe("Number(.000123456).toExponential()","\"1.23456e-4\"");
 shouldBeTrue("try { Number(.000123456).toExponential(-1) } catch (e) { String(e).indexOf('Range') >= 0; }");
@@ -155,11 +155,11 @@ shouldBe("Number(.000123456).toExponential(12)","\"1.234560000000e-4\"");
 shouldBe("Number(.000123456).toExponential(13)","\"1.2345600000000e-4\"");
 shouldBe("Number(.000123456).toExponential(14)","\"1.23456000000000e-4\"");
 shouldBe("Number(.000123456).toExponential(15)","\"1.234560000000000e-4\"");
-shouldBe("Number(.000123456).toExponential(16)","\"1.2345600000000000e-4\"");
-shouldBe("Number(.000123456).toExponential(17)","\"1.23456000000000000e-4\"");
-shouldBe("Number(.000123456).toExponential(18)","\"1.234560000000000000e-4\"");
-shouldBe("Number(.000123456).toExponential(19)","\"1.2345600000000000000e-4\"");
-shouldBe("Number(.000123456).toExponential(20)","\"1.23456000000000000000e-4\"");
+shouldBe("Number(.000123456).toExponential(16)","\"1.2345600000000001e-4\"");
+shouldBe("Number(.000123456).toExponential(17)","\"1.23456000000000005e-4\"");
+shouldBe("Number(.000123456).toExponential(18)","\"1.234560000000000052e-4\"");
+shouldBe("Number(.000123456).toExponential(19)","\"1.2345600000000000519e-4\"");
+shouldBe("Number(.000123456).toExponential(20)","\"1.23456000000000005188e-4\"");
 shouldBeTrue("try { Number(.000123456).toExponential(21) } catch (e) { String(e).indexOf('Range') >= 0; }");
 shouldBe("Number(-.000123456).toExponential()","\"-1.23456e-4\"");
 shouldBeTrue("try { Number(-.000123456).toExponential(-1) } catch (e) { String(e).indexOf('Range') >= 0; }");
@@ -179,11 +179,11 @@ shouldBe("Number(-.000123456).toExponential(12)","\"-1.234560000000e-4\"");
 shouldBe("Number(-.000123456).toExponential(13)","\"-1.2345600000000e-4\"");
 shouldBe("Number(-.000123456).toExponential(14)","\"-1.23456000000000e-4\"");
 shouldBe("Number(-.000123456).toExponential(15)","\"-1.234560000000000e-4\"");
-shouldBe("Number(-.000123456).toExponential(16)","\"-1.2345600000000000e-4\"");
-shouldBe("Number(-.000123456).toExponential(17)","\"-1.23456000000000000e-4\"");
-shouldBe("Number(-.000123456).toExponential(18)","\"-1.234560000000000000e-4\"");
-shouldBe("Number(-.000123456).toExponential(19)","\"-1.2345600000000000000e-4\"");
-shouldBe("Number(-.000123456).toExponential(20)","\"-1.23456000000000000000e-4\"");
+shouldBe("Number(-.000123456).toExponential(16)","\"-1.2345600000000001e-4\"");
+shouldBe("Number(-.000123456).toExponential(17)","\"-1.23456000000000005e-4\"");
+shouldBe("Number(-.000123456).toExponential(18)","\"-1.234560000000000052e-4\"");
+shouldBe("Number(-.000123456).toExponential(19)","\"-1.2345600000000000519e-4\"");
+shouldBe("Number(-.000123456).toExponential(20)","\"-1.23456000000000005188e-4\"");
 shouldBeTrue("try { Number(-.000123456).toExponential(21) } catch (e) { String(e).indexOf('Range') >= 0; }");
 shouldBe("Number(123.4567890123456789012).toExponential()","\"1.2345678901234568e+2\"");
 shouldBeTrue("try { Number(123.4567890123456789012).toExponential(-1) } catch (e) { String(e).indexOf('Range') >= 0; }");
@@ -204,10 +204,10 @@ shouldBe("Number(123.4567890123456789012).toExponential(13)","\"1.2345678901235e
 shouldBe("Number(123.4567890123456789012).toExponential(14)","\"1.23456789012346e+2\"");
 shouldBe("Number(123.4567890123456789012).toExponential(15)","\"1.234567890123457e+2\"");
 shouldBe("Number(123.4567890123456789012).toExponential(16)","\"1.2345678901234568e+2\"");
-shouldBe("Number(123.4567890123456789012).toExponential(17)","\"1.23456789012345680e+2\"");
-shouldBe("Number(123.4567890123456789012).toExponential(18)","\"1.234567890123456800e+2\"");
-shouldBe("Number(123.4567890123456789012).toExponential(19)","\"1.2345678901234567000e+2\"");
-shouldBe("Number(123.4567890123456789012).toExponential(20)","\"1.23456789012345680000e+2\"");
+shouldBe("Number(123.4567890123456789012).toExponential(17)","\"1.23456789012345681e+2\"");
+shouldBe("Number(123.4567890123456789012).toExponential(18)","\"1.234567890123456806e+2\"");
+shouldBe("Number(123.4567890123456789012).toExponential(19)","\"1.2345678901234568059e+2\"");
+shouldBe("Number(123.4567890123456789012).toExponential(20)","\"1.23456789012345680590e+2\"");
 shouldBeTrue("try { Number(123.4567890123456789012).toExponential(21) } catch (e) { String(e).indexOf('Range') >= 0; }");
 shouldBe("Number(-123.4567890123456789012).toExponential()","\"-1.2345678901234568e+2\"");
 shouldBeTrue("try { Number(-123.4567890123456789012).toExponential(-1) } catch (e) { String(e).indexOf('Range') >= 0; }");
@@ -228,10 +228,10 @@ shouldBe("Number(-123.4567890123456789012).toExponential(13)","\"-1.234567890123
 shouldBe("Number(-123.4567890123456789012).toExponential(14)","\"-1.23456789012346e+2\"");
 shouldBe("Number(-123.4567890123456789012).toExponential(15)","\"-1.234567890123457e+2\"");
 shouldBe("Number(-123.4567890123456789012).toExponential(16)","\"-1.2345678901234568e+2\"");
-shouldBe("Number(-123.4567890123456789012).toExponential(17)","\"-1.23456789012345680e+2\"");
-shouldBe("Number(-123.4567890123456789012).toExponential(18)","\"-1.234567890123456800e+2\"");
-shouldBe("Number(-123.4567890123456789012).toExponential(19)","\"-1.2345678901234567000e+2\"");
-shouldBe("Number(-123.4567890123456789012).toExponential(20)","\"-1.23456789012345680000e+2\"");
+shouldBe("Number(-123.4567890123456789012).toExponential(17)","\"-1.23456789012345681e+2\"");
+shouldBe("Number(-123.4567890123456789012).toExponential(18)","\"-1.234567890123456806e+2\"");
+shouldBe("Number(-123.4567890123456789012).toExponential(19)","\"-1.2345678901234568059e+2\"");
+shouldBe("Number(-123.4567890123456789012).toExponential(20)","\"-1.23456789012345680590e+2\"");
 shouldBeTrue("try { Number(-123.4567890123456789012).toExponential(21) } catch (e) { String(e).indexOf('Range') >= 0; }");
 shouldBe("Number(.0000000000000000000001).toExponential()","\"1e-22\"");
 shouldBe("Number(.0000000000000000000012).toExponential()","\"1.2e-21\"");
@@ -368,7 +368,7 @@ shouldBe("Number(0.0001234567890123456789012345).toPrecision(17)","\"0.000123456
 shouldBe("Number(0.0001234567890123456789012345).toPrecision(18)","\"0.000123456789012345671\"");
 shouldBe("Number(0.0001234567890123456789012345).toPrecision(19)","\"0.0001234567890123456713\"");
 shouldBe("Number(0.0001234567890123456789012345).toPrecision(20)","\"0.00012345678901234567130\"");
-shouldBe("Number(0.0001234567890123456789012345).toPrecision(21)","\"0.000123456789012345671297\"");
+shouldBe("Number(0.0001234567890123456789012345).toPrecision(21)","\"0.000123456789012345671298\"");
 shouldBe("Number(12345.67890123456789012345).toPrecision()","\"12345.678901234567\"");
 shouldBe("Number(12345.67890123456789012345).toPrecision(1)","\"1e+4\"");
 shouldBe("Number(12345.67890123456789012345).toPrecision(2)","\"1.2e+4\"");
@@ -386,11 +386,11 @@ shouldBe("Number(12345.67890123456789012345).toPrecision(13)","\"12345.67890123\
 shouldBe("Number(12345.67890123456789012345).toPrecision(14)","\"12345.678901235\"");
 shouldBe("Number(12345.67890123456789012345).toPrecision(15)","\"12345.6789012346\"");
 shouldBe("Number(12345.67890123456789012345).toPrecision(16)","\"12345.67890123457\"");
-shouldBe("Number(12345.67890123456789012345).toPrecision(17)","\"12345.678901234568\"");
-shouldBe("Number(12345.67890123456789012345).toPrecision(18)","\"12345.6789012345660\"");
-shouldBe("Number(12345.67890123456789012345).toPrecision(19)","\"12345.67890123456800\"");
-shouldBe("Number(12345.67890123456789012345).toPrecision(20)","\"12345.678901234567000\"");
-shouldBe("Number(12345.67890123456789012345).toPrecision(21)","\"12345.6789012345670000\"");
+shouldBe("Number(12345.67890123456789012345).toPrecision(17)","\"12345.678901234567\"");
+shouldBe("Number(12345.67890123456789012345).toPrecision(18)","\"12345.6789012345671\"");
+shouldBe("Number(12345.67890123456789012345).toPrecision(19)","\"12345.67890123456709\"");
+shouldBe("Number(12345.67890123456789012345).toPrecision(20)","\"12345.678901234567093\"");
+shouldBe("Number(12345.67890123456789012345).toPrecision(21)","\"12345.6789012345670926\"");
 shouldBe("Number(-.0000000012345).toPrecision(2)","\"-1.2e-9\"");
 shouldBe("Number(-.000000012345).toPrecision(2)","\"-1.2e-8\"");
 shouldBe("Number(-.00000012345).toPrecision(2)","\"-1.2e-7\"");
@@ -428,7 +428,7 @@ shouldBe("Number(-0.0001234567890123456789012345).toPrecision(17)","\"-0.0001234
 shouldBe("Number(-0.0001234567890123456789012345).toPrecision(18)","\"-0.000123456789012345671\"");
 shouldBe("Number(-0.0001234567890123456789012345).toPrecision(19)","\"-0.0001234567890123456713\"");
 shouldBe("Number(-0.0001234567890123456789012345).toPrecision(20)","\"-0.00012345678901234567130\"");
-shouldBe("Number(-0.0001234567890123456789012345).toPrecision(21)","\"-0.000123456789012345671297\"");
+shouldBe("Number(-0.0001234567890123456789012345).toPrecision(21)","\"-0.000123456789012345671298\"");
 shouldBe("Number(-12345.67890123456789012345).toPrecision()","\"-12345.678901234567\"");
 shouldBe("Number(-12345.67890123456789012345).toPrecision(1)","\"-1e+4\"");
 shouldBe("Number(-12345.67890123456789012345).toPrecision(2)","\"-1.2e+4\"");
@@ -446,11 +446,11 @@ shouldBe("Number(-12345.67890123456789012345).toPrecision(13)","\"-12345.6789012
 shouldBe("Number(-12345.67890123456789012345).toPrecision(14)","\"-12345.678901235\"");
 shouldBe("Number(-12345.67890123456789012345).toPrecision(15)","\"-12345.6789012346\"");
 shouldBe("Number(-12345.67890123456789012345).toPrecision(16)","\"-12345.67890123457\"");
-shouldBe("Number(-12345.67890123456789012345).toPrecision(17)","\"-12345.678901234568\"");
-shouldBe("Number(-12345.67890123456789012345).toPrecision(18)","\"-12345.6789012345660\"");
-shouldBe("Number(-12345.67890123456789012345).toPrecision(19)","\"-12345.67890123456800\"");
-shouldBe("Number(-12345.67890123456789012345).toPrecision(20)","\"-12345.678901234567000\"");
-shouldBe("Number(-12345.67890123456789012345).toPrecision(21)","\"-12345.6789012345670000\"");
+shouldBe("Number(-12345.67890123456789012345).toPrecision(17)","\"-12345.678901234567\"");
+shouldBe("Number(-12345.67890123456789012345).toPrecision(18)","\"-12345.6789012345671\"");
+shouldBe("Number(-12345.67890123456789012345).toPrecision(19)","\"-12345.67890123456709\"");
+shouldBe("Number(-12345.67890123456789012345).toPrecision(20)","\"-12345.678901234567093\"");
+shouldBe("Number(-12345.67890123456789012345).toPrecision(21)","\"-12345.6789012345670926\"");
 shouldBe("Number(0).toPrecision()","\"0\"");
 shouldBe("Number(0).toPrecision(1)","\"0\"");
 shouldBe("Number(0).toPrecision(2)","\"0.0\"");
diff --git a/LayoutTests/fast/js/number-toExponential-expected.txt b/LayoutTests/fast/js/number-toExponential-expected.txt
index 0e940ec..bcf9d69 100644
--- a/LayoutTests/fast/js/number-toExponential-expected.txt
+++ b/LayoutTests/fast/js/number-toExponential-expected.txt
@@ -16,7 +16,7 @@ PASS (123.456).toExponential(2.9) is "1.23e+2"
 PASS (123.456).toExponential(3) is "1.235e+2"
 PASS (123.456).toExponential(5) is "1.23456e+2"
 PASS (123.456).toExponential(6) is "1.234560e+2"
-FAIL (123.456).toExponential(20) should be 1.23456000000000003070e+2. Was 1.23456000000000000000e+2.
+PASS (123.456).toExponential(20) is "1.23456000000000003070e+2"
 PASS (123.456).toExponential(21) threw exception RangeError: toExponential() argument must be between 0 and 20.
 PASS (123.456).toExponential(100) threw exception RangeError: toExponential() argument must be between 0 and 20.
 PASS (123.456).toExponential(101) threw exception RangeError: toExponential() argument must be between 0 and 20.
diff --git a/LayoutTests/fast/js/number-tofixed-expected.txt b/LayoutTests/fast/js/number-tofixed-expected.txt
index 8751df5..cfd70a1 100644
--- a/LayoutTests/fast/js/number-tofixed-expected.txt
+++ b/LayoutTests/fast/js/number-tofixed-expected.txt
@@ -41,7 +41,7 @@ PASS (1234.567).toFixed('1') is "1234.6"
 PASS (1234.567).toFixed(2) is "1234.57"
 PASS (1234.567).toFixed(2.9) is "1234.57"
 PASS (1234.567).toFixed(5) is "1234.56700"
-FAIL (1234.567).toFixed(20) should be 1234.56700000000000727596. Was 1234.56700000000000000000.
+PASS (1234.567).toFixed(20) is "1234.56700000000000727596"
 PASS (1234.567).toFixed(21) threw exception RangeError: toFixed() argument must be between 0 and 20.
 PASS (1234.567).toFixed(100) threw exception RangeError: toFixed() argument must be between 0 and 20.
 PASS (1234.567).toFixed(101) threw exception RangeError: toFixed() argument must be between 0 and 20.
diff --git a/LayoutTests/fast/js/number-toprecision-expected.txt b/LayoutTests/fast/js/number-toprecision-expected.txt
index 71303d7..71c6b57 100644
--- a/LayoutTests/fast/js/number-toprecision-expected.txt
+++ b/LayoutTests/fast/js/number-toprecision-expected.txt
@@ -22,7 +22,7 @@ PASS (1234.567).toPrecision('1') is "1e+3"
 PASS (1234.567).toPrecision(2) is "1.2e+3"
 PASS (1234.567).toPrecision(2.9) is "1.2e+3"
 PASS (1234.567).toPrecision(5) is "1234.6"
-FAIL (1234.567).toPrecision(21) should be 1234.56700000000000728. Was 1234.56700000000000000.
+PASS (1234.567).toPrecision(21) is "1234.56700000000000728"
 PASS (1234.567).toPrecision(22) threw exception RangeError: toPrecision() argument must be between 1 and 21.
 PASS (1234.567).toPrecision(100) threw exception RangeError: toPrecision() argument must be between 1 and 21.
 PASS (1234.567).toPrecision(101) threw exception RangeError: toPrecision() argument must be between 1 and 21.
diff --git a/WebCore/ChangeLog b/WebCore/ChangeLog
index bdae17d..8298f74 100644
--- a/WebCore/ChangeLog
+++ b/WebCore/ChangeLog
@@ -1,3 +1,18 @@
+2010-08-27  Gavin Barraclough  <barraclough at apple.com>
+
+        Reviewed by Oliver Hunt.
+
+        Bug 44745 - Number.toFixed/toExponential/toPrecision are inaccurate.
+
+        These methods should be using a version of dtoa that can generate results accurate
+        to the requested precision, whereas our version of dtoa is only currently able to
+        support producing results sufficiently accurate to distinguish the value from any
+        other IEEE-754 double precision number.
+
+        * html/HTMLTreeBuilder.cpp:
+        (WebCore::serializeForNumberType):
+            doubleToStringInJavaScriptFormat renamed to numberToString.
+
 2010-08-27  Michael Nordman  <michaeln at google.com>
 
         Reviewed by David Levin.
diff --git a/WebCore/html/HTMLTreeBuilder.cpp b/WebCore/html/HTMLTreeBuilder.cpp
index 4f4bb20..693dc63 100644
--- a/WebCore/html/HTMLTreeBuilder.cpp
+++ b/WebCore/html/HTMLTreeBuilder.cpp
@@ -2850,9 +2850,8 @@ String serializeForNumberType(double number)
 {
     // According to HTML5, "the best representation of the number n as a floating
     // point number" is a string produced by applying ToString() to n.
-    DtoaBuffer buffer;
-    unsigned length;
-    doubleToStringInJavaScriptFormat(number, buffer, &length);
+    NumberToStringBuffer buffer;
+    unsigned length = numberToString(number, buffer);
     return String(buffer, length);
 }
 

-- 
WebKit Debian packaging



More information about the Pkg-webkit-commits mailing list