Skip to content

Commit ee33785

Browse files
committed
[MERGE #3742 @xiaoyinl] Never use exponential if radix not 10 (Fix #3739, #3740)
Merge pull request #3742 from xiaoyinl:never_use_exp Other engines (SpiderMonkey, JSC and V8) never use exponential display for num.toString(radix) if radix is not 10, no matter how large num is. This PR updates the code and the test cases to match that behavior. This PR fixes #3739 and fixes #3740. See also: #2751, #3635. /cc @dilijev @littledan @bterlson
2 parents 112d0d6 + 4c8fc73 commit ee33785

File tree

3 files changed

+48
-117
lines changed

3 files changed

+48
-117
lines changed

lib/Common/Common/NumberUtilities_strtod.cpp

-117
Original file line numberDiff line numberDiff line change
@@ -2528,123 +2528,6 @@ BOOL Js::NumberUtilities::FNonZeroFiniteDblToStr(double dbl, _In_range_(2, 36) i
25282528
maxOutDigits = g_rgcchSig[radix];
25292529
__analysis_assume(maxOutDigits > 0);
25302530

2531-
if (dbl < 1e-21 || dbl > 1e+21)
2532-
{
2533-
// Use exponential notation. Get the exponent and normalize.
2534-
if (cbitDigit != 0)
2535-
{
2536-
// Power of 2. These computations are exact.
2537-
wExp = wExp2 / cbitDigit;
2538-
wExp2 = wExp * cbitDigit;
2539-
2540-
// Avoid overflow and underflow.
2541-
if (wExp2 > 0)
2542-
{
2543-
wExp2 -= cbitDigit;
2544-
dbl /= radix;
2545-
}
2546-
else
2547-
{
2548-
wExp2 += cbitDigit;
2549-
dbl *= radix;
2550-
}
2551-
2552-
Js::NumberUtilities::LuHiDbl(valueT) = (uint32)(0x03FF + wExp2) << 20;
2553-
Js::NumberUtilities::LuLoDbl(valueT) = 0;
2554-
}
2555-
else
2556-
{
2557-
wExp = (int)floor(log(dbl) / log((double)radix) + 1.0);
2558-
valueT = pow((double)radix, wExp);
2559-
if (!Js::NumberUtilities::IsFinite(valueT))
2560-
{
2561-
valueT = pow((double)radix, --wExp);
2562-
}
2563-
else if (0 == valueT)
2564-
{
2565-
valueT = pow((double)radix, ++wExp);
2566-
}
2567-
}
2568-
dbl = dbl / valueT;
2569-
2570-
while (dbl < 1)
2571-
{
2572-
dbl *= radix;
2573-
wExp--;
2574-
}
2575-
AssertMsg(1 <= dbl && dbl < radix, "malformed computation in radix toString()");
2576-
2577-
// First digit.
2578-
wDig = (int)dbl;
2579-
if (len < 2)
2580-
{
2581-
return FALSE; //We run out of buffer size.
2582-
}
2583-
len--;
2584-
*ppsz++ = ToDigit(wDig);
2585-
maxOutDigits--;
2586-
dbl -= wDig;
2587-
2588-
// Radix point and remaining digits.
2589-
if (0 != dbl)
2590-
{
2591-
if (len < maxOutDigits + 2)
2592-
{
2593-
return FALSE; //We run out of buffer size.
2594-
}
2595-
len -= maxOutDigits + 1;
2596-
*ppsz++ = '.';
2597-
while (dbl != 0 && maxOutDigits-- > 0)
2598-
{
2599-
dbl *= radix;
2600-
wDig = (int)dbl;
2601-
if (wDig >= radix)
2602-
{
2603-
wDig = radix - 1;
2604-
}
2605-
*ppsz++ = ToDigit(wDig);
2606-
dbl -= wDig;
2607-
}
2608-
}
2609-
2610-
// Exponent.
2611-
if (len < 9) // NOTE: may actually need less room
2612-
{
2613-
return FALSE; //We run out of buffer size.
2614-
}
2615-
*ppsz++ = '(';
2616-
*ppsz++ = 'e';
2617-
if (wExp < 0)
2618-
{
2619-
*ppsz++ = '-';
2620-
wExp = -wExp;
2621-
}
2622-
else
2623-
{
2624-
*ppsz++ = '+';
2625-
}
2626-
if (wExp >= 10)
2627-
{
2628-
if (wExp >= 100)
2629-
{
2630-
if (wExp >= 1000)
2631-
{
2632-
*ppsz++ = (char16)('0' + wExp / 1000);
2633-
wExp %= 1000;
2634-
}
2635-
*ppsz++ = (char16)('0' + wExp / 100);
2636-
wExp %= 100;
2637-
}
2638-
*ppsz++ = (char16)('0' + wExp / 10);
2639-
wExp %= 10;
2640-
}
2641-
*ppsz++ = (char16)('0' + wExp);
2642-
*ppsz++ = ')';
2643-
*ppsz = 0;
2644-
2645-
return TRUE;
2646-
}
2647-
26482531
// Output the integer portion.
26492532
if (1 <= dbl)
26502533
{

test/Number/toString.js

+2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ runTest('new Number(-444123)');
88
runTest('new Number("444" + "123.789123456789875436")');
99
runTest('new Number(-444123.78963636363636363636)');
1010
runTest('new Number(0)');
11+
runTest('0.9999999999999999e21');
1112
runTest('1e21');
13+
runTest('1.0000000000000001e21');
1214

1315
function runTest(numberToTestAsString)
1416
{

test/Number/toString_3.baseline

+46
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,29 @@ n.toPrecision(2): 0.0
113113
n.toPrecision(5): 0.0000
114114
n.toPrecision(20): 0.0000000000000000000
115115

116+
Test: 0.9999999999999999e21
117+
n.toString(): 999999999999999900000
118+
n.toString(10): 999999999999999900000
119+
n.toString(8): 154327115334273647400000
120+
n.toString(2): 1101100011010111001001101011011100010111011110100111100000000000000000
121+
n.toString(16): 3635c9adc5de9e0000
122+
n.toString(25): 11l259oooooofl0h
123+
n.toFixed(): 999999999999999900000
124+
n.toFixed(0): 999999999999999900000
125+
n.toFixed(2): 999999999999999900000.00
126+
n.toFixed(5): 999999999999999900000.00000
127+
n.toFixed(20): 999999999999999900000.00000000000000000000
128+
RangeError: The number of fractional digits is out of range
129+
RangeError: The number of fractional digits is out of range
130+
n.toExponential(): 9.999999999999999e+20
131+
n.toExponential(undefined): 9.999999999999999e+20
132+
n.toExponential(2): 1.00e+21
133+
n.toExponential(5): 1.00000e+21
134+
n.toPrecision(): 999999999999999900000
135+
n.toPrecision(2): 1.0e+21
136+
n.toPrecision(5): 1.0000e+21
137+
n.toPrecision(20): 9.9999999999999990000e+20
138+
116139
Test: 1e21
117140
n.toString(): 1e+21
118141
n.toString(10): 1e+21
@@ -136,3 +159,26 @@ n.toPrecision(2): 1.0e+21
136159
n.toPrecision(5): 1.0000e+21
137160
n.toPrecision(20): 1.0000000000000000000e+21
138161

162+
Test: 1.0000000000000001e21
163+
n.toString(): 1.0000000000000001e+21
164+
n.toString(10): 1.0000000000000001e+21
165+
n.toString(8): 154327115334273650400000
166+
n.toString(2): 1101100011010111001001101011011100010111011110101000100000000000000000
167+
n.toString(16): 3635c9adc5dea20000
168+
n.toString(25): 11l25a0000007fbb
169+
n.toFixed(): 1.0000000000000001e+21
170+
n.toFixed(0): 1.0000000000000001e+21
171+
n.toFixed(2): 1.0000000000000001e+21
172+
n.toFixed(5): 1.0000000000000001e+21
173+
n.toFixed(20): 1.0000000000000001e+21
174+
RangeError: The number of fractional digits is out of range
175+
RangeError: The number of fractional digits is out of range
176+
n.toExponential(): 1.0000000000000001e+21
177+
n.toExponential(undefined): 1.0000000000000001e+21
178+
n.toExponential(2): 1.00e+21
179+
n.toExponential(5): 1.00000e+21
180+
n.toPrecision(): 1.0000000000000001e+21
181+
n.toPrecision(2): 1.0e+21
182+
n.toPrecision(5): 1.0000e+21
183+
n.toPrecision(20): 1.0000000000000001000e+21
184+

0 commit comments

Comments
 (0)