You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

100 lines
2.9 KiB

2 years ago
'use strict';
var $ = require('../internals/export');
var uncurryThis = require('../internals/function-uncurry-this');
var toIntegerOrInfinity = require('../internals/to-integer-or-infinity');
var thisNumberValue = require('../internals/this-number-value');
var $repeat = require('../internals/string-repeat');
var log10 = require('../internals/math-log10');
var fails = require('../internals/fails');
var $RangeError = RangeError;
var $String = String;
var $isFinite = isFinite;
var abs = Math.abs;
var floor = Math.floor;
var pow = Math.pow;
var round = Math.round;
var un$ToExponential = uncurryThis(1.0.toExponential);
var repeat = uncurryThis($repeat);
var stringSlice = uncurryThis(''.slice);
// Edge 17-
var ROUNDS_PROPERLY = un$ToExponential(-6.9e-11, 4) === '-6.9000e-11'
// IE11- && Edge 14-
&& un$ToExponential(1.255, 2) === '1.25e+0'
// FF86-, V8 ~ Chrome 49-50
&& un$ToExponential(12345, 3) === '1.235e+4'
// FF86-, V8 ~ Chrome 49-50
&& un$ToExponential(25, 0) === '3e+1';
// IE8-
var THROWS_ON_INFINITY_FRACTION = fails(function () {
un$ToExponential(1, Infinity);
}) && fails(function () {
un$ToExponential(1, -Infinity);
});
// Safari <11 && FF <50
var PROPER_NON_FINITE_THIS_CHECK = !fails(function () {
un$ToExponential(Infinity, Infinity);
}) && !fails(function () {
un$ToExponential(NaN, Infinity);
});
var FORCED = !ROUNDS_PROPERLY || !THROWS_ON_INFINITY_FRACTION || !PROPER_NON_FINITE_THIS_CHECK;
// `Number.prototype.toExponential` method
// https://tc39.es/ecma262/#sec-number.prototype.toexponential
$({ target: 'Number', proto: true, forced: FORCED }, {
toExponential: function toExponential(fractionDigits) {
var x = thisNumberValue(this);
if (fractionDigits === undefined) return un$ToExponential(x);
var f = toIntegerOrInfinity(fractionDigits);
if (!$isFinite(x)) return String(x);
// TODO: ES2018 increased the maximum number of fraction digits to 100, need to improve the implementation
if (f < 0 || f > 20) throw $RangeError('Incorrect fraction digits');
if (ROUNDS_PROPERLY) return un$ToExponential(x, f);
var s = '';
var m = '';
var e = 0;
var c = '';
var d = '';
if (x < 0) {
s = '-';
x = -x;
}
if (x === 0) {
e = 0;
m = repeat('0', f + 1);
} else {
// this block is based on https://gist.github.com/SheetJSDev/1100ad56b9f856c95299ed0e068eea08
// TODO: improve accuracy with big fraction digits
var l = log10(x);
e = floor(l);
var n = 0;
var w = pow(10, e - f);
n = round(x / w);
if (2 * x >= (2 * n + 1) * w) {
n += 1;
}
if (n >= pow(10, f + 1)) {
n /= 10;
e += 1;
}
m = $String(n);
}
if (f !== 0) {
m = stringSlice(m, 0, 1) + '.' + stringSlice(m, 1);
}
if (e === 0) {
c = '+';
d = '0';
} else {
c = e > 0 ? '+' : '-';
d = $String(abs(e));
}
m += 'e' + c + d;
return s + m;
}
});