Changeset 65959 in webkit for trunk/JavaScriptCore/wtf/dtoa.cpp


Ignore:
Timestamp:
Aug 24, 2010, 6:04:31 PM (15 years ago)
Author:
[email protected]
Message:

JavaScriptCore: https://bugs.webkit.org/show_bug.cgi?id=44487

Reviewed by Oliver Hunt.

Number.toExponential/toFixed/toPrecision all contain a spaghetti of duplicated
code & unnecessary complexity. Add a new DecimalNumber class to encapsulate
double to string conversion, share the implementations of rounding &
decimal-fraction/exponential formatting.

Update exports.

  • runtime/NumberPrototype.cpp:

(JSC::toThisNumber):
(JSC::getIntegerArgumentInRange):

Helper methods used in implementing toExponential/toFixed/toString.

(JSC::numberProtoFuncToExponential):
(JSC::numberProtoFuncToFixed):
(JSC::numberProtoFuncToPrecision):

Reimplemented using new DecimalNumber class.


  • runtime/UString.cpp:

(JSC::UString::number):

Updated to call numberToString.

  • wtf/DecimalNumber.h: Added.

(WTF::):
(WTF::DecimalNumber::DecimalNumber):
(WTF::DecimalNumber::toStringDecimal):
(WTF::DecimalNumber::toStringExponential):
(WTF::DecimalNumber::sign):
(WTF::DecimalNumber::exponent):
(WTF::DecimalNumber::significand):
(WTF::DecimalNumber::precision):
(WTF::DecimalNumber::init):
(WTF::DecimalNumber::isZero):
(WTF::DecimalNumber::roundToPrecision):

New class to perform double to string conversion.
Has three constructors, which allow conversion with no rounding,
rounding to significant-figures, or rounding to decimal-places,
and two methods for formatting strings, either using decimal
fraction or exponential encoding. Internal implementation uses
pre-rounding of the values before calling dtoa rather than
relying on dtoa to correctly round, which does not produce
fully accurate results. Hopefully we can address this in the
near future.

  • wtf/dtoa.cpp:

(WTF::intPow10):

  • wtf/dtoa.h:

intPow10 is used internally by DecimalNumber.


  • wtf/text/WTFString.cpp:

(WTF::copyToString):
(WTF::nanOrInfToString):

Used internally in numberToString for NaN/Infinity handling.

(WTF::numberToString):

Added new method to convert doubles to strings.

  • wtf/text/WTFString.h:

Added declaration for numberToString. This is here because
we should switch over to using this for all double to string
conversion in WebCore (see section 2.4.4.3 of the HTML5 spec).

JavaScriptGlue: https://bugs.webkit.org/show_bug.cgi?id=44487

Reviewed by Oliver Hunt.

  • ForwardingHeaders/wtf/text/WTFString.h: Added.

WebCore: https://bugs.webkit.org/show_bug.cgi?id=44487

Reviewed by Oliver Hunt.

  • html/LegacyHTMLTreeBuilder.cpp:

(WebCore::serializeForNumberType):

Update function call to numberToString.

LayoutTests: Bug 44487 - Clean up NumberPrototype.cpp

Reviewed by Oliver Hunt.

This patch changes some layout test results - in all these cases we were
not previously accurate to spec defined behaviour, and we are still not

  • but overall this changes reduces the overall magnitude of error due to

rounding differences. The underlying problem is that we should be using
dtoa to generate results to a specified accuracy, rather than relying on
pre-rounding the input values. We should look at reenabling our dtoa
implementation to work in this fashion as a separate change.

  • 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:
  • fast/js/script-tests/number-toExponential.js:
  • fast/js/script-tests/number-tofixed.js:
  • fast/js/script-tests/number-toprecision.js:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/wtf/dtoa.cpp

    r65588 r65959  
    22862286}
    22872287
    2288 static ALWAYS_INLINE void append(char*& next, const char* src, unsigned size)
     2288double intPow10(int e)
    22892289{
    2290     for (unsigned i = 0; i < size; ++i)
    2291         *next++ = *src++;
     2290    // This function uses the "exponentiation by squaring" algorithm and
     2291    // long double to quickly and precisely calculate integer powers of 10.0.
     2292
     2293    // This is a handy workaround for <rdar://problem/4494756>
     2294
     2295    if (!e)
     2296        return 1.0;
     2297
     2298    bool negative = e < 0;
     2299    unsigned exp = negative ? -e : e;
     2300
     2301    long double result = 10.0;
     2302    bool foundOne = false;
     2303    for (int bit = 31; bit >= 0; bit--) {
     2304        if (!foundOne) {
     2305            if ((exp >> bit) & 1)
     2306                foundOne = true;
     2307        } else {
     2308            result = result * result;
     2309            if ((exp >> bit) & 1)
     2310                result = result * 10.0;
     2311        }
     2312    }
     2313
     2314    if (negative)
     2315        return static_cast<double>(1.0 / result);
     2316    return static_cast<double>(result);
    22922317}
    22932318
    2294 void doubleToStringInJavaScriptFormat(double d, DtoaBuffer buffer, unsigned* resultLength)
    2295 {
    2296     ASSERT(buffer);
    2297 
    2298     // avoid ever printing -NaN, in JS conceptually there is only one NaN value
    2299     if (isnan(d)) {
    2300         append(buffer, "NaN", 3);
    2301         if (resultLength)
    2302             *resultLength = 3;
    2303         return;
    2304     }
    2305     // -0 -> "0"
    2306     if (!d) {
    2307         buffer[0] = '0';
    2308         if (resultLength)
    2309             *resultLength = 1;
    2310         return;
    2311     }
    2312 
    2313     int decimalPoint;
    2314     int sign;
    2315 
    2316     DtoaBuffer result;
    2317     char* resultEnd = 0;
    2318     WTF::dtoa(result, d, 0, &decimalPoint, &sign, &resultEnd);
    2319     int length = resultEnd - result;
    2320 
    2321     char* next = buffer;
    2322     if (sign)
    2323         *next++ = '-';
    2324 
    2325     if (decimalPoint <= 0 && decimalPoint > -6) {
    2326         *next++ = '0';
    2327         *next++ = '.';
    2328         for (int j = decimalPoint; j < 0; j++)
    2329             *next++ = '0';
    2330         append(next, result, length);
    2331     } else if (decimalPoint <= 21 && decimalPoint > 0) {
    2332         if (length <= decimalPoint) {
    2333             append(next, result, length);
    2334             for (int j = 0; j < decimalPoint - length; j++)
    2335                 *next++ = '0';
    2336         } else {
    2337             append(next, result, decimalPoint);
    2338             *next++ = '.';
    2339             append(next, result + decimalPoint, length - decimalPoint);
    2340         }
    2341     } else if (result[0] < '0' || result[0] > '9')
    2342         append(next, result, length);
    2343     else {
    2344         *next++ = result[0];
    2345         if (length > 1) {
    2346             *next++ = '.';
    2347             append(next, result + 1, length - 1);
    2348         }
    2349 
    2350         *next++ = 'e';
    2351         *next++ = (decimalPoint >= 0) ? '+' : '-';
    2352         // decimalPoint can't be more than 3 digits decimal given the
    2353         // nature of float representation
    2354         int exponential = decimalPoint - 1;
    2355         if (exponential < 0)
    2356             exponential = -exponential;
    2357         if (exponential >= 100)
    2358             *next++ = static_cast<char>('0' + exponential / 100);
    2359         if (exponential >= 10)
    2360             *next++ = static_cast<char>('0' + (exponential % 100) / 10);
    2361         *next++ = static_cast<char>('0' + exponential % 10);
    2362     }
    2363     if (resultLength)
    2364         *resultLength = next - buffer;
    2365 }
    2366 
    23672319} // namespace WTF
Note: See TracChangeset for help on using the changeset viewer.