103 lines
3.0 KiB
JavaScript
103 lines
3.0 KiB
JavaScript
|
'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 nativeToExponential = uncurryThis(1.0.toExponential);
|
||
|
var repeat = uncurryThis($repeat);
|
||
|
var stringSlice = uncurryThis(''.slice);
|
||
|
|
||
|
// Edge 17-
|
||
|
var ROUNDS_PROPERLY = nativeToExponential(-6.9e-11, 4) === '-6.9000e-11'
|
||
|
// IE11- && Edge 14-
|
||
|
&& nativeToExponential(1.255, 2) === '1.25e+0'
|
||
|
// FF86-, V8 ~ Chrome 49-50
|
||
|
&& nativeToExponential(12345, 3) === '1.235e+4'
|
||
|
// FF86-, V8 ~ Chrome 49-50
|
||
|
&& nativeToExponential(25, 0) === '3e+1';
|
||
|
|
||
|
// IE8-
|
||
|
var throwsOnInfinityFraction = function () {
|
||
|
return fails(function () {
|
||
|
nativeToExponential(1, Infinity);
|
||
|
}) && fails(function () {
|
||
|
nativeToExponential(1, -Infinity);
|
||
|
});
|
||
|
};
|
||
|
|
||
|
// Safari <11 && FF <50
|
||
|
var properNonFiniteThisCheck = function () {
|
||
|
return !fails(function () {
|
||
|
nativeToExponential(Infinity, Infinity);
|
||
|
nativeToExponential(NaN, Infinity);
|
||
|
});
|
||
|
};
|
||
|
|
||
|
var FORCED = !ROUNDS_PROPERLY || !throwsOnInfinityFraction() || !properNonFiniteThisCheck();
|
||
|
|
||
|
// `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 nativeToExponential(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 nativeToExponential(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;
|
||
|
}
|
||
|
});
|