Changeset 29020 in webkit


Ignore:
Timestamp:
Dec 28, 2007 8:01:13 PM (16 years ago)
Author:
eric@webkit.org
Message:

Reviewed by Oliver.

Fix (-0).toFixed() and re-factor a little
Fix (-0).toExponential() and printing of trailing 0s in toExponential
Fix toPrecision(nan) handling

  • kjs/number_object.cpp: (KJS::numberToFixed): (KJS::fractionalPartToString): (KJS::numberToExponential): (KJS::numberToPrecision):
Location:
trunk
Files:
5 added
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/ChangeLog

    r29018 r29020  
     12007-12-28  Eric Seidel  <eric@webkit.org>
     2
     3        Reviewed by Oliver.
     4
     5        Fix (-0).toFixed() and re-factor a little
     6        Fix (-0).toExponential() and printing of trailing 0s in toExponential
     7        Fix toPrecision(nan) handling
     8
     9        * kjs/number_object.cpp:
     10        (KJS::numberToFixed):
     11        (KJS::fractionalPartToString):
     12        (KJS::numberToExponential):
     13        (KJS::numberToPrecision):
     14
    1152007-12-28  Eric Seidel  <eric@webkit.org>
    216
  • trunk/JavaScriptCore/kjs/number_object.cpp

    r29018 r29020  
    209209        s.append('-');
    210210        x = -x;
    211     }
     211    } else if (x == -0.0)
     212        x = 0;
    212213
    213214    if (x >= pow(10.0, 21.0))
     
    234235        return jsString(s + m.substr(0, kMinusf) + "." + m.substr(kMinusf));
    235236    return jsString(s + m.substr(0, kMinusf));
     237}
     238
     239void fractionalPartToString(char* buf, int& i, const char* result, int resultLength, int fractionalDigits)
     240{
     241    if (fractionalDigits <= 0)
     242        return;
     243
     244    int fDigitsInResult = static_cast<int>(resultLength) - 1;
     245    buf[i++] = '.';
     246    if (fDigitsInResult > 0) {
     247        if (fractionalDigits < fDigitsInResult) {
     248            strncpy(buf + i, result + 1, fractionalDigits);
     249            i += fractionalDigits;
     250        } else {
     251            strcpy(buf + i, result + 1);
     252            i += static_cast<int>(resultLength) - 1;
     253        }
     254    }
     255
     256    for (int j = 0; j < fractionalDigits - fDigitsInResult; j++)
     257        buf[i++] = '0';
    236258}
    237259
     
    259281        return jsString(UString::from(x));
    260282
    261     JSValue* fractionDigits = args[0];
    262     double df = fractionDigits->toInteger(exec);
     283    JSValue* fractionalDigitsValue = args[0];
     284    double df = fractionalDigitsValue->toInteger(exec);
    263285    if (!(df >= 0 && df <= 20))
    264286        return throwError(exec, RangeError, "toExponential() argument must between 0 and 20");
    265     int f = (int)df;
    266     bool includeAllDigits = fractionDigits->isUndefined();
     287    int fractionalDigits = (int)df;
     288    bool includeAllDigits = fractionalDigitsValue->isUndefined();
    267289
    268290    int decimalAdjust = 0;
    269     if (!includeAllDigits) {
     291    if (x && !includeAllDigits) {
    270292        double logx = floor(log10(fabs(x)));
    271293        x /= pow(10.0, logx);
    272         const double tenToTheF = pow(10.0, f);
     294        const double tenToTheF = pow(10.0, fractionalDigits);
    273295        double fx = floor(x * tenToTheF) / tenToTheF;
    274296        double cx = ceil(x * tenToTheF) / tenToTheF;
     
    285307        return jsString("NaN");
    286308
     309    if (x == -0.0) // (-0.0).toExponential() should print as 0 instead of -0
     310        x = 0;
     311
    287312    int decimalPoint;
    288313    int sign;
    289314    char* result = kjs_dtoa(x, 0, 0, &decimalPoint, &sign, NULL);
    290     size_t length = strlen(result);
     315    size_t resultLength = strlen(result);
    291316    decimalPoint += decimalAdjust;
    292317
    293318    int i = 0;
    294     char buf[80];
     319    char buf[80]; // digit + '.' + fractionDigits (max 20) + 'e' + sign + exponent (max?)
    295320    if (sign)
    296321        buf[i++] = '-';
     
    302327
    303328        if (includeAllDigits)
    304             f = static_cast<int>(length) - 1;
    305 
    306         if (length > 1 && f > 0) {
    307             buf[i++] = '.';
    308             int haveFDigits = static_cast<int>(length) - 1;
    309             if (f < haveFDigits) {
    310                 strncpy(buf + i, result + 1, f);
    311                 i += f;
    312             } else {
    313                 strcpy(buf + i, result + 1);
    314                 i += static_cast<int>(length) - 1;
    315                 for (int j = 0; j < f - haveFDigits; j++)
    316                     buf[i++] = '0';
    317             }
    318         }
     329            fractionalDigits = static_cast<int>(resultLength) - 1;
     330
     331        fractionalPartToString(buf, i, result, resultLength, fractionalDigits);
    319332        exponentialPartToString(buf, i, decimalPoint);
    320333        buf[i++] = '\0';
    321334    }
    322 
    323335    ASSERT(i <= 80);
    324336
     
    332344    double doublePrecision = args[0]->toIntegerPreserveNaN(exec);
    333345    double x = v->toNumber(exec);
    334     if (isnan(doublePrecision) || isnan(x) || isinf(x))
     346    if (args[0]->isUndefined() || isnan(x) || isinf(x))
    335347        return jsString(v->toString(exec));
    336348
     
    347359    int e = 0;
    348360    UString m;
    349     if (x != 0) {
     361    if (x) {
    350362        e = static_cast<int>(log10(x));
    351363        double tens = intPow10(e - precision + 1);
  • trunk/LayoutTests/ChangeLog

    r29012 r29020  
     12007-12-28  Eric Seidel  <eric@webkit.org>
     2
     3        Reviewed by Oliver.
     4
     5        Add more tests for toFixed, toPrecision and toExponential
     6        Add tests for toString to match Firefox's behavior
     7       
     8        All tests pass in Firefox, but some fail in WebKit
     9        I've chosen to land failing tests as I expect we'll move closer
     10        towards Firefox's behavior in the future, and it's better to have
     11        the tests now thus to notice any behavior changes in the future.
     12
     13        * fast/js/number-toExponential-expected.txt: Added.
     14        * fast/js/number-toString-expected.txt: Added.
     15        * fast/js/number-toString.html: Added.
     16        * fast/js/number-tofixed-expected.txt:
     17        * fast/js/number-toprecision-expected.txt:
     18        * fast/js/resources/number-toExponential.js: Added.
     19        * fast/js/resources/number-toString.js: Added.
     20        * fast/js/resources/number-tofixed.js:
     21        * fast/js/resources/number-toprecision.js:
     22
    1232007-12-29  Nikolas Zimmermann  <zimmermann@kde.org>
    224
  • trunk/LayoutTests/fast/js/number-tofixed-expected.txt

    r12000 r29020  
    2626PASS (-0.55).toFixed(1) is '-0.6'
    2727PASS (-0.551).toFixed(1) is '-0.6'
     28PASS (0.0).toFixed(4) is "0.0000"
     29PASS (-0.0).toFixed(4) is "0.0000"
     30PASS (0.0).toFixed() is "0"
     31PASS (-0.0).toFixed() is "0"
     32PASS (1234.567).toFixed() is "1235"
     33PASS (1234.567).toFixed(0) is "1235"
     34PASS (1234.567).toFixed(1) is "1234.6"
     35PASS (1234.567).toFixed(2) is "1234.57"
     36PASS (1234.567).toFixed(5) is "1234.56700"
     37FAIL (1234.567).toFixed(20) should be 1234.56700000000000727596. Was 1234.56700000000000000000.
     38FAIL (1234.567).toFixed(21) should be 1234.567000000000007275958. Threw exception RangeError: toFixed() digits argument must be between 0 and 20
     39FAIL (1234.567).toFixed(100) should be 1234.5670000000000072759576141834259033203125000000000000000000000000000000000000000000000000000000000000. Threw exception RangeError: toFixed() digits argument must be between 0 and 20
     40PASS (1234.567).toFixed(101) threw exception RangeError: toFixed() digits argument must be between 0 and 20.
     41FAIL (1234.567).toFixed(-1) should be 1230. Threw exception RangeError: toFixed() digits argument must be between 0 and 20
     42FAIL (1234.567).toFixed(-4) should be 0. Threw exception RangeError: toFixed() digits argument must be between 0 and 20
     43FAIL (1234.567).toFixed(-5) should be 0. Threw exception RangeError: toFixed() digits argument must be between 0 and 20
     44FAIL (1234.567).toFixed(-20) should be 0. Threw exception RangeError: toFixed() digits argument must be between 0 and 20
     45PASS (1234.567).toFixed(-21) threw exception RangeError: toFixed() digits argument must be between 0 and 20.
     46PASS (1234.567).toFixed(posInf) threw exception RangeError: toFixed() digits argument must be between 0 and 20.
     47PASS (1234.567).toFixed(negInf) threw exception RangeError: toFixed() digits argument must be between 0 and 20.
     48PASS (1234.567).toFixed(nan) is "1235"
     49PASS posInf.toFixed() is "Infinity"
     50PASS negInf.toFixed() is "-Infinity"
     51PASS nan.toFixed() is "NaN"
    2852PASS successfullyParsed is true
    2953
  • trunk/LayoutTests/fast/js/number-toprecision-expected.txt

    r26581 r29020  
    44
    55
    6 PASS (0.999).toPrecision(1) is '1'
    7 PASS (0.999).toPrecision(2) is '1.0'
    8 PASS (0.999).toPrecision(3) is '0.999'
     6PASS (0.999).toPrecision(1) is "1"
     7PASS (0.999).toPrecision(2) is "1.0"
     8PASS (0.999).toPrecision(3) is "0.999"
     9PASS (0.0).toPrecision(4) is "0.000"
     10PASS (-0.0).toPrecision(4) is "0.000"
     11FAIL (0.0).toPrecision() should be 0. Threw exception RangeError: toPrecision() argument must be between 1 and 21
     12FAIL (-0.0).toPrecision() should be 0. Threw exception RangeError: toPrecision() argument must be between 1 and 21
     13FAIL (1234.567).toPrecision() should be 1234.567. Threw exception RangeError: toPrecision() argument must be between 1 and 21
     14PASS (1234.567).toPrecision(0) threw exception RangeError: toPrecision() argument must be between 1 and 21.
     15PASS (1234.567).toPrecision(-1) threw exception RangeError: toPrecision() argument must be between 1 and 21.
     16PASS (1234.567).toPrecision(1) is "1e+3"
     17PASS (1234.567).toPrecision(2) is "1.2e+3"
     18PASS (1234.567).toPrecision(5) is "1234.6"
     19FAIL (1234.567).toPrecision(21) should be 1234.56700000000000728. Was 1234.56700000000000000.
     20FAIL (1234.567).toPrecision(22) should be 1234.567000000000007276. Threw exception RangeError: toPrecision() argument must be between 1 and 21
     21FAIL (1234.567).toPrecision(100) should be 1234.567000000000007275957614183425903320312500000000000000000000000000000000000000000000000000000000. Threw exception RangeError: toPrecision() argument must be between 1 and 21
     22PASS (1234.567).toPrecision(101) threw exception RangeError: toPrecision() argument must be between 1 and 21.
     23PASS (1234.567).toPrecision(posInf) threw exception RangeError: toPrecision() argument must be between 1 and 21.
     24PASS (1234.567).toPrecision(negInf) threw exception RangeError: toPrecision() argument must be between 1 and 21.
     25PASS (1234.567).toPrecision(nan) threw exception RangeError: toPrecision() argument must be between 1 and 21.
     26PASS posInf.toPrecision() is "Infinity"
     27PASS negInf.toPrecision() is "-Infinity"
     28PASS nan.toPrecision() is "NaN"
    929PASS successfullyParsed is true
    1030
  • trunk/LayoutTests/fast/js/resources/number-tofixed.js

    r12000 r29020  
    3434shouldBe("(-0.551).toFixed(1)", "'-0.6'");
    3535
     36var posInf = 1/0;
     37var negInf = -1/0;
     38var nan = 0/0;
     39
     40// From Acid3, http://bugs.webkit.org/show_bug.cgi?id=16640
     41shouldBeEqualToString("(0.0).toFixed(4)", "0.0000");
     42shouldBeEqualToString("(-0.0).toFixed(4)", "0.0000");
     43shouldBeEqualToString("(0.0).toFixed()", "0");
     44shouldBeEqualToString("(-0.0).toFixed()", "0");
     45
     46// From http://bugs.webkit.org/show_bug.cgi?id=5258
     47shouldBeEqualToString("(1234.567).toFixed()", "1235");
     48shouldBeEqualToString("(1234.567).toFixed(0)", "1235");
     49// 0 equivilents
     50shouldBeEqualToString("(1234.567).toFixed(null)", "1235");
     51shouldBeEqualToString("(1234.567).toFixed(false)", "1235");
     52shouldBeEqualToString("(1234.567).toFixed('foo')", "1235");
     53shouldBeEqualToString("(1234.567).toFixed(nan)", "1235"); // nan is treated like 0
     54
     55shouldBeEqualToString("(1234.567).toFixed(1)", "1234.6");
     56shouldBeEqualToString("(1234.567).toFixed(true)", "1234.6"); // just like 1
     57shouldBeEqualToString("(1234.567).toFixed('1')", "1234.6"); // just like 1
     58
     59shouldBeEqualToString("(1234.567).toFixed(2)", "1234.57");
     60shouldBeEqualToString("(1234.567).toFixed(5)", "1234.56700");
     61shouldBeEqualToString("(1234.567).toFixed(20)", "1234.56700000000000727596");
     62
     63// SpiderMonkey allows precision values -20 to 100, we only allow 0 to 20 currently
     64shouldBeEqualToString("(1234.567).toFixed(21)", "1234.567000000000007275958");
     65shouldBeEqualToString("(1234.567).toFixed(100)", "1234.5670000000000072759576141834259033203125000000000000000000000000000000000000000000000000000000000000");
     66shouldThrow("(1234.567).toFixed(101)");
     67shouldBeEqualToString("(1234.567).toFixed(-1)", "1230");
     68shouldBeEqualToString("(1234.567).toFixed(-4)", "0");
     69shouldBeEqualToString("(1234.567).toFixed(-5)", "0");
     70shouldBeEqualToString("(1234.567).toFixed(-20)", "0");
     71shouldThrow("(1234.567).toFixed(-21)");
     72
     73shouldThrow("(1234.567).toFixed(posInf)");
     74shouldThrow("(1234.567).toFixed(negInf)");
     75
     76shouldBeEqualToString("posInf.toFixed()", "Infinity");
     77shouldBeEqualToString("negInf.toFixed()", "-Infinity");
     78shouldBeEqualToString("nan.toFixed()", "NaN");
     79
    3680var successfullyParsed = true;
  • trunk/LayoutTests/fast/js/resources/number-toprecision.js

    r26581 r29020  
    44    '.');
    55
    6 shouldBe("(0.999).toPrecision(1)", "'1'");
    7 shouldBe("(0.999).toPrecision(2)", "'1.0'");
    8 shouldBe("(0.999).toPrecision(3)", "'0.999'");
     6shouldBeEqualToString("(0.999).toPrecision(1)", "1");
     7shouldBeEqualToString("(0.999).toPrecision(2)", "1.0");
     8shouldBeEqualToString("(0.999).toPrecision(3)", "0.999");
    99
     10var posInf = 1/0;
     11var negInf = -1/0;
     12var nan = 0/0;
     13
     14shouldBeEqualToString("(0.0).toPrecision(4)", "0.000");
     15shouldBeEqualToString("(-0.0).toPrecision(4)", "0.000");
     16shouldBeEqualToString("(0.0).toPrecision()", "0");
     17shouldBeEqualToString("(-0.0).toPrecision()", "0");
     18shouldBeEqualToString("(1234.567).toPrecision()", "1234.567");
     19shouldThrow("(1234.567).toPrecision(0)");
     20shouldThrow("(1234.567).toPrecision(null)"); // just like 0
     21shouldThrow("(1234.567).toPrecision(false)"); // just like 0
     22shouldThrow("(1234.567).toPrecision('foo')"); // just like 0
     23shouldThrow("(1234.567).toPrecision(-1)");
     24shouldBeEqualToString("(1234.567).toPrecision(1)", "1e+3");
     25shouldBeEqualToString("(1234.567).toPrecision(true)", "1e+3"); // just like 1
     26shouldBeEqualToString("(1234.567).toPrecision('1')", "1e+3"); // just like 1
     27shouldBeEqualToString("(1234.567).toPrecision(2)", "1.2e+3");
     28shouldBeEqualToString("(1234.567).toPrecision(5)", "1234.6");
     29shouldBeEqualToString("(1234.567).toPrecision(21)", "1234.56700000000000728");
     30// SpiderMonkey allows precision values 1 to 100, we only allow 1 to 21 currently
     31shouldBeEqualToString("(1234.567).toPrecision(22)", "1234.567000000000007276");
     32shouldBeEqualToString("(1234.567).toPrecision(100)", "1234.567000000000007275957614183425903320312500000000000000000000000000000000000000000000000000000000");
     33shouldThrow("(1234.567).toPrecision(101)");
     34
     35shouldThrow("(1234.567).toPrecision(posInf)");
     36shouldThrow("(1234.567).toPrecision(negInf)");
     37shouldThrow("(1234.567).toPrecision(nan)"); // nan is treated like 0
     38
     39shouldBeEqualToString("posInf.toPrecision()", "Infinity");
     40shouldBeEqualToString("negInf.toPrecision()", "-Infinity");
     41shouldBeEqualToString("nan.toPrecision()", "NaN");
    1042
    1143var successfullyParsed = true;
Note: See TracChangeset for help on using the changeset viewer.