Commit 11256376 authored by Daniel Ehrenberg's avatar Daniel Ehrenberg Committed by Commit Bot

[builtins] Increase precision limits for toFixed, etc

This patch implements a recent spec change [1] which increases the
bounds of precision for toFixed, toExponential and toPrecision.
The bounds are a compromise between SpiderMonkey and the other
engines.

[1] https://github.com/tc39/ecma262/pull/857

Bug: v8:6539
Cq-Include-Trybots: master.tryserver.v8:v8_linux_noi18n_rel_ng
Change-Id: I877aa35e08f3dcda63f5f9181fdecf3c227f2c35
Reviewed-on: https://chromium-review.googlesource.com/553378
Commit-Queue: Daniel Ehrenberg <littledan@chromium.org>
Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#46793}
parent a224eff4
......@@ -44,7 +44,8 @@ BUILTIN(NumberPrototypeToExponential) {
return (value_number < 0.0) ? isolate->heap()->minus_Infinity_string()
: isolate->heap()->Infinity_string();
}
if (fraction_digits_number < 0.0 || fraction_digits_number > 20.0) {
if (fraction_digits_number < 0.0 ||
fraction_digits_number > kMaxFractionDigits) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewRangeError(MessageTemplate::kNumberFormatRange,
isolate->factory()->NewStringFromAsciiChecked(
......@@ -84,7 +85,8 @@ BUILTIN(NumberPrototypeToFixed) {
double const fraction_digits_number = fraction_digits->Number();
// Check if the {fraction_digits} are in the supported range.
if (fraction_digits_number < 0.0 || fraction_digits_number > 20.0) {
if (fraction_digits_number < 0.0 ||
fraction_digits_number > kMaxFractionDigits) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewRangeError(MessageTemplate::kNumberFormatRange,
isolate->factory()->NewStringFromAsciiChecked(
......@@ -158,7 +160,7 @@ BUILTIN(NumberPrototypeToPrecision) {
return (value_number < 0.0) ? isolate->heap()->minus_Infinity_string()
: isolate->heap()->Infinity_string();
}
if (precision_number < 1.0 || precision_number > 21.0) {
if (precision_number < 1.0 || precision_number > kMaxFractionDigits) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewRangeError(MessageTemplate::kToPrecisionFormatRange));
}
......
......@@ -201,9 +201,8 @@ const char* IntToCString(int n, Vector<char> buffer) {
char* DoubleToFixedCString(double value, int f) {
const int kMaxDigitsBeforePoint = 21;
const double kFirstNonFixed = 1e21;
const int kMaxDigitsAfterPoint = 20;
DCHECK(f >= 0);
DCHECK(f <= kMaxDigitsAfterPoint);
DCHECK(f <= kMaxFractionDigits);
bool negative = false;
double abs_value = value;
......@@ -215,7 +214,7 @@ char* DoubleToFixedCString(double value, int f) {
// If abs_value has more than kMaxDigitsBeforePoint digits before the point
// use the non-fixed conversion routine.
if (abs_value >= kFirstNonFixed) {
char arr[100];
char arr[kMaxFractionDigits];
Vector<char> buffer(arr, arraysize(arr));
return StrDup(DoubleToCString(value, buffer));
}
......@@ -225,7 +224,7 @@ char* DoubleToFixedCString(double value, int f) {
int sign;
// Add space for the '\0' byte.
const int kDecimalRepCapacity =
kMaxDigitsBeforePoint + kMaxDigitsAfterPoint + 1;
kMaxDigitsBeforePoint + kMaxFractionDigits + 1;
char decimal_rep[kDecimalRepCapacity];
int decimal_rep_length;
DoubleToAscii(value, DTOA_FIXED, f,
......@@ -302,9 +301,8 @@ static char* CreateExponentialRepresentation(char* decimal_rep,
char* DoubleToExponentialCString(double value, int f) {
const int kMaxDigitsAfterPoint = 20;
// f might be -1 to signal that f was undefined in JavaScript.
DCHECK(f >= -1 && f <= kMaxDigitsAfterPoint);
DCHECK(f >= -1 && f <= kMaxFractionDigits);
bool negative = false;
if (value < 0) {
......@@ -318,10 +316,10 @@ char* DoubleToExponentialCString(double value, int f) {
// f corresponds to the digits after the point. There is always one digit
// before the point. The number of requested_digits equals hence f + 1.
// And we have to add one character for the null-terminator.
const int kV8DtoaBufferCapacity = kMaxDigitsAfterPoint + 1 + 1;
const int kV8DtoaBufferCapacity = kMaxFractionDigits + 1 + 1;
// Make sure that the buffer is big enough, even if we fall back to the
// shortest representation (which happens when f equals -1).
DCHECK(kBase10MaximalLength <= kMaxDigitsAfterPoint + 1);
DCHECK(kBase10MaximalLength <= kMaxFractionDigits + 1);
char decimal_rep[kV8DtoaBufferCapacity];
int decimal_rep_length;
......@@ -348,8 +346,7 @@ char* DoubleToExponentialCString(double value, int f) {
char* DoubleToPrecisionCString(double value, int p) {
const int kMinimalDigits = 1;
const int kMaximalDigits = 21;
DCHECK(p >= kMinimalDigits && p <= kMaximalDigits);
DCHECK(p >= kMinimalDigits && p <= kMaxFractionDigits);
USE(kMinimalDigits);
bool negative = false;
......@@ -362,7 +359,7 @@ char* DoubleToPrecisionCString(double value, int p) {
int decimal_point;
int sign;
// Add one for the terminating null character.
const int kV8DtoaBufferCapacity = kMaximalDigits + 1;
const int kV8DtoaBufferCapacity = kMaxFractionDigits + 1;
char decimal_rep[kV8DtoaBufferCapacity];
int decimal_rep_length;
......
......@@ -26,6 +26,9 @@ class UnicodeCache;
// we don't need to preserve all the digits.
const int kMaxSignificantDigits = 772;
// The limit for the the fractionDigits/precision for toFixed, toPrecision
// and toExponential.
const int kMaxFractionDigits = 100;
inline bool isDigit(int x, int radix) {
return (x >= '0' && x <= '9' && x < '0' + radix)
......
......@@ -527,10 +527,11 @@ class ErrorUtils : public AllStatic {
T(LetInLexicalBinding, "let is disallowed as a lexically bound name") \
T(LocaleMatcher, "Illegal value for localeMatcher:%") \
T(NormalizationForm, "The normalization form should be one of %.") \
T(NumberFormatRange, "% argument must be between 0 and 20") \
T(NumberFormatRange, "% argument must be between 0 and 100") \
T(PropertyValueOutOfRange, "% value is out of range.") \
T(StackOverflow, "Maximum call stack size exceeded") \
T(ToPrecisionFormatRange, "toPrecision() argument must be between 1 and 21") \
T(ToPrecisionFormatRange, \
"toPrecision() argument must be between 1 and 100") \
T(ToRadixFormatRange, "toString() radix argument must be between 2 and 36") \
T(TypedArraySetNegativeOffset, "Start offset is negative") \
T(TypedArraySetSourceTooLarge, "Source is too large") \
......
......@@ -426,12 +426,12 @@ test(function() {
// kNumberFormatRange
test(function() {
Number(1).toFixed(100);
}, "toFixed() digits argument must be between 0 and 20", RangeError);
Number(1).toFixed(101);
}, "toFixed() digits argument must be between 0 and 100", RangeError);
test(function() {
Number(1).toExponential(100);
}, "toExponential() argument must be between 0 and 20", RangeError);
Number(1).toExponential(101);
}, "toExponential() argument must be between 0 and 100", RangeError);
// kStackOverflow
test(function() {
......@@ -441,8 +441,8 @@ test(function() {
// kToPrecisionFormatRange
test(function() {
Number(1).toPrecision(100);
}, "toPrecision() argument must be between 1 and 21", RangeError);
Number(1).toPrecision(101);
}, "toPrecision() argument must be between 1 and 100", RangeError);
// kToPrecisionFormatRange
test(function() {
......
......@@ -301,9 +301,6 @@
# returned via the indirect 'arguments' property accessor.
'js1_4/Functions/function-001': [FAIL_OK],
# toPrecision argument restricted to range 1..21 in JSC/V8 and ECMA-262
'js1_5/Regress/regress-452346': [FAIL_OK],
# Fail because it calls builtins as functions and do not expect the
# builtin to have undefined as the receiver.
'ecma/String/15.5.4.6-2': [FAIL_OK],
......
......@@ -506,11 +506,6 @@
'built-ins/Array/prototype/splice/create-species-length-exceeding-integer-limit': [FAIL],
'built-ins/Array/prototype/splice/throws-if-integer-limit-exceeded': [SKIP],
# https://bugs.chromium.org/p/v8/issues/detail?id=6539
'built-ins/Number/prototype/toFixed/range': [FAIL],
'built-ins/Number/prototype/toPrecision/range': [FAIL],
'built-ins/Number/prototype/toExponential/range': [FAIL],
# https://bugs.chromium.org/p/v8/issues/detail?id=5855
'language/expressions/async-generator/named-yield-promise-reject-next': [FAIL],
'language/expressions/async-generator/named-yield-promise-reject-next-catch': [FAIL],
......
......@@ -86,11 +86,11 @@ PASS Number(-Math.pow(10,21)).toFixed(20) is "-1e+21"
PASS toFixedOrException(2,-1).indexOf('Range') >= 0 is true
PASS Number(2).toFixed(0) is "2"
PASS Number(2).toFixed(20) is "2.00000000000000000000"
PASS toFixedOrException(2,21).indexOf('Range') >= 0 is true
FAIL toFixedOrException(2,21).indexOf('Range') >= 0 should be true. Was false.
PASS toFixedOrException(-2,-1).indexOf('Range') >= 0 is true
PASS Number(-2).toFixed(0) is "-2"
PASS Number(-2).toFixed(20) is "-2.00000000000000000000"
PASS toFixedOrException(-2,21).indexOf('Range') >= 0 is true
FAIL toFixedOrException(-2,21).indexOf('Range') >= 0 should be true. Was false.
PASS Number(NaN).toExponential() is "NaN"
PASS Number(Infinity).toExponential() is "Infinity"
PASS Number(-Infinity).toExponential() is "-Infinity"
......@@ -120,7 +120,7 @@ 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
FAIL try { Number(123.456).toExponential(21) } catch (e) { String(e).indexOf('Range') >= 0; } should be true (of type boolean). Was 1.234560000000000030695e+2 (of type string).
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
PASS Number(-123.456).toExponential(0) is "-1e+2"
......@@ -144,7 +144,7 @@ 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
FAIL try { Number(-123.456).toExponential(21) } catch (e) { String(e).indexOf('Range') >= 0; } should be true (of type boolean). Was -1.234560000000000030695e+2 (of type string).
PASS Number(.000123456).toExponential() is "1.23456e-4"
PASS try { Number(.000123456).toExponential(-1) } catch (e) { String(e).indexOf('Range') >= 0; } is true
PASS Number(.000123456).toExponential(0) is "1e-4"
......@@ -168,7 +168,7 @@ 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
FAIL try { Number(.000123456).toExponential(21) } catch (e) { String(e).indexOf('Range') >= 0; } should be true (of type boolean). Was 1.234560000000000051876e-4 (of type string).
PASS Number(-.000123456).toExponential() is "-1.23456e-4"
PASS try { Number(-.000123456).toExponential(-1) } catch (e) { String(e).indexOf('Range') >= 0; } is true
PASS Number(-.000123456).toExponential(0) is "-1e-4"
......@@ -192,7 +192,7 @@ 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
FAIL try { Number(-.000123456).toExponential(21) } catch (e) { String(e).indexOf('Range') >= 0; } should be true (of type boolean). Was -1.234560000000000051876e-4 (of type string).
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
PASS Number(123.4567890123456789012).toExponential(0) is "1e+2"
......@@ -216,7 +216,7 @@ PASS Number(123.4567890123456789012).toExponential(17) is "1.23456789012345681e+
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
FAIL try { Number(123.4567890123456789012).toExponential(21) } catch (e) { String(e).indexOf('Range') >= 0; } should be true (of type boolean). Was 1.234567890123456805895e+2 (of type string).
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
PASS Number(-123.4567890123456789012).toExponential(0) is "-1e+2"
......@@ -240,7 +240,7 @@ PASS Number(-123.4567890123456789012).toExponential(17) is "-1.23456789012345681
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
FAIL try { Number(-123.4567890123456789012).toExponential(21) } catch (e) { String(e).indexOf('Range') >= 0; } should be true (of type boolean). Was -1.234567890123456805895e+2 (of type string).
PASS Number(.0000000000000000000001).toExponential() is "1e-22"
PASS Number(.0000000000000000000012).toExponential() is "1.2e-21"
PASS Number(.0000000000000000000123).toExponential() is "1.23e-20"
......@@ -331,7 +331,7 @@ PASS try { Number(1).toPrecision(-1); } catch (e) { String(e).indexOf('Range') >
PASS try { Number(1).toPrecision(0); } catch (e) { String(e).indexOf('Range') >= 0; } is true
PASS try { Number(1).toPrecision(1); } catch (e) { String(e); } is "1"
PASS try { Number(1).toPrecision(21); } catch (e) { String(e); } is "1.00000000000000000000"
PASS try { Number(1).toPrecision(22); } catch (e) { String(e).indexOf('Range') >= 0; } is true
FAIL try { Number(1).toPrecision(22); } catch (e) { String(e).indexOf('Range') >= 0; } should be true (of type boolean). Was 1.000000000000000000000 (of type string).
PASS Number(NaN).toPrecision() is "NaN"
PASS Number(NaN).toPrecision(1) is "NaN"
PASS Number(Infinity).toPrecision() is "Infinity"
......
......@@ -65,16 +65,16 @@ 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"
PASS (1234.567).toFixed(20) is "1234.56700000000000727596"
PASS (1234.567).toFixed(21) threw exception RangeError: toFixed() digits argument must be between 0 and 20.
PASS (1234.567).toFixed(100) threw exception RangeError: toFixed() digits argument must be between 0 and 20.
PASS (1234.567).toFixed(101) threw exception RangeError: toFixed() digits argument must be between 0 and 20.
PASS (1234.567).toFixed(-1) threw exception RangeError: toFixed() digits argument must be between 0 and 20.
PASS (1234.567).toFixed(-4) threw exception RangeError: toFixed() digits argument must be between 0 and 20.
PASS (1234.567).toFixed(-5) threw exception RangeError: toFixed() digits argument must be between 0 and 20.
PASS (1234.567).toFixed(-20) threw exception RangeError: toFixed() digits argument must be between 0 and 20.
PASS (1234.567).toFixed(-21) threw exception RangeError: toFixed() digits argument must be between 0 and 20.
PASS (1234.567).toFixed(posInf) threw exception RangeError: toFixed() digits argument must be between 0 and 20.
PASS (1234.567).toFixed(negInf) threw exception RangeError: toFixed() digits argument must be between 0 and 20.
FAIL (1234.567).toFixed(21) should throw an exception. Was 1234.567000000000007275958.
FAIL (1234.567).toFixed(100) should throw an exception. Was 1234.5670000000000072759576141834259033203125000000000000000000000000000000000000000000000000000000000000.
PASS (1234.567).toFixed(101) threw exception RangeError: toFixed() digits argument must be between 0 and 100.
PASS (1234.567).toFixed(-1) threw exception RangeError: toFixed() digits argument must be between 0 and 100.
PASS (1234.567).toFixed(-4) threw exception RangeError: toFixed() digits argument must be between 0 and 100.
PASS (1234.567).toFixed(-5) threw exception RangeError: toFixed() digits argument must be between 0 and 100.
PASS (1234.567).toFixed(-20) threw exception RangeError: toFixed() digits argument must be between 0 and 100.
PASS (1234.567).toFixed(-21) threw exception RangeError: toFixed() digits argument must be between 0 and 100.
PASS (1234.567).toFixed(posInf) threw exception RangeError: toFixed() digits argument must be between 0 and 100.
PASS (1234.567).toFixed(negInf) threw exception RangeError: toFixed() digits argument must be between 0 and 100.
PASS posInf.toFixed() is "Infinity"
PASS negInf.toFixed() is "-Infinity"
PASS nan.toFixed() is "NaN"
......
......@@ -34,11 +34,11 @@ PASS (-0.0).toPrecision(4) is "0.000"
PASS (0.0).toPrecision() is "0"
PASS (-0.0).toPrecision() is "0"
PASS (1234.567).toPrecision() is "1234.567"
PASS (1234.567).toPrecision(0) threw exception RangeError: toPrecision() argument must be between 1 and 21.
PASS (1234.567).toPrecision(null) threw exception RangeError: toPrecision() argument must be between 1 and 21.
PASS (1234.567).toPrecision(false) threw exception RangeError: toPrecision() argument must be between 1 and 21.
PASS (1234.567).toPrecision('foo') threw exception RangeError: toPrecision() argument must be between 1 and 21.
PASS (1234.567).toPrecision(-1) threw exception RangeError: toPrecision() argument must be between 1 and 21.
PASS (1234.567).toPrecision(0) threw exception RangeError: toPrecision() argument must be between 1 and 100.
PASS (1234.567).toPrecision(null) threw exception RangeError: toPrecision() argument must be between 1 and 100.
PASS (1234.567).toPrecision(false) threw exception RangeError: toPrecision() argument must be between 1 and 100.
PASS (1234.567).toPrecision('foo') threw exception RangeError: toPrecision() argument must be between 1 and 100.
PASS (1234.567).toPrecision(-1) threw exception RangeError: toPrecision() argument must be between 1 and 100.
PASS (1234.567).toPrecision(1) is "1e+3"
PASS (1234.567).toPrecision(true) is "1e+3"
PASS (1234.567).toPrecision('1') is "1e+3"
......@@ -46,12 +46,12 @@ 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"
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.
PASS (1234.567).toPrecision(posInf) threw exception RangeError: toPrecision() argument must be between 1 and 21.
PASS (1234.567).toPrecision(negInf) threw exception RangeError: toPrecision() argument must be between 1 and 21.
PASS (1234.567).toPrecision(nan) threw exception RangeError: toPrecision() argument must be between 1 and 21.
FAIL (1234.567).toPrecision(22) should throw an exception. Was 1234.567000000000007276.
FAIL (1234.567).toPrecision(100) should throw an exception. Was 1234.567000000000007275957614183425903320312500000000000000000000000000000000000000000000000000000000.
PASS (1234.567).toPrecision(101) threw exception RangeError: toPrecision() argument must be between 1 and 100.
PASS (1234.567).toPrecision(posInf) threw exception RangeError: toPrecision() argument must be between 1 and 100.
PASS (1234.567).toPrecision(negInf) threw exception RangeError: toPrecision() argument must be between 1 and 100.
PASS (1234.567).toPrecision(nan) threw exception RangeError: toPrecision() argument must be between 1 and 100.
PASS posInf.toPrecision() is "Infinity"
PASS negInf.toPrecision() is "-Infinity"
PASS nan.toPrecision() is "NaN"
......
......@@ -40,12 +40,12 @@ 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"
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.
PASS (123.456).toExponential(-1) threw exception RangeError: toExponential() argument must be between 0 and 20.
PASS (1234.567).toExponential(posInf) threw exception RangeError: toExponential() argument must be between 0 and 20.
PASS (1234.567).toExponential(negInf) threw exception RangeError: toExponential() argument must be between 0 and 20.
FAIL (123.456).toExponential(21) should throw an exception. Was 1.234560000000000030695e+2.
FAIL (123.456).toExponential(100) should throw an exception. Was 1.2345600000000000306954461848363280296325683593750000000000000000000000000000000000000000000000000000e+2.
PASS (123.456).toExponential(101) threw exception RangeError: toExponential() argument must be between 0 and 100.
PASS (123.456).toExponential(-1) threw exception RangeError: toExponential() argument must be between 0 and 100.
PASS (1234.567).toExponential(posInf) threw exception RangeError: toExponential() argument must be between 0 and 100.
PASS (1234.567).toExponential(negInf) threw exception RangeError: toExponential() argument must be between 0 and 100.
PASS posInf.toExponential() is "Infinity"
PASS negInf.toExponential() is "-Infinity"
PASS nan.toExponential() is "NaN"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment