| 1 | 'use strict';
|
|---|
| 2 | var $ = require('../internals/export');
|
|---|
| 3 | var uncurryThis = require('../internals/function-uncurry-this');
|
|---|
| 4 | var toIntegerOrInfinity = require('../internals/to-integer-or-infinity');
|
|---|
| 5 | var thisNumberValue = require('../internals/this-number-value');
|
|---|
| 6 | var $repeat = require('../internals/string-repeat');
|
|---|
| 7 | var log10 = require('../internals/math-log10');
|
|---|
| 8 | var fails = require('../internals/fails');
|
|---|
| 9 |
|
|---|
| 10 | var $RangeError = RangeError;
|
|---|
| 11 | var $String = String;
|
|---|
| 12 | var $isFinite = isFinite;
|
|---|
| 13 | var abs = Math.abs;
|
|---|
| 14 | var floor = Math.floor;
|
|---|
| 15 | var pow = Math.pow;
|
|---|
| 16 | var round = Math.round;
|
|---|
| 17 | var nativeToExponential = uncurryThis(1.1.toExponential);
|
|---|
| 18 | var repeat = uncurryThis($repeat);
|
|---|
| 19 | var stringSlice = uncurryThis(''.slice);
|
|---|
| 20 |
|
|---|
| 21 | var POW_10_308 = pow(10, 308);
|
|---|
| 22 |
|
|---|
| 23 | // Edge 17-
|
|---|
| 24 | var ROUNDS_PROPERLY = nativeToExponential(-6.9e-11, 4) === '-6.9000e-11'
|
|---|
| 25 | // IE11- && Edge 14-
|
|---|
| 26 | && nativeToExponential(1.255, 2) === '1.25e+0'
|
|---|
| 27 | // FF86-, V8 ~ Chrome 49-50
|
|---|
| 28 | && nativeToExponential(12345, 3) === '1.235e+4'
|
|---|
| 29 | // FF86-, V8 ~ Chrome 49-50
|
|---|
| 30 | && nativeToExponential(25, 0) === '3e+1';
|
|---|
| 31 |
|
|---|
| 32 | // IE8-
|
|---|
| 33 | var throwsOnInfinityFraction = function () {
|
|---|
| 34 | return fails(function () {
|
|---|
| 35 | nativeToExponential(1, Infinity);
|
|---|
| 36 | }) && fails(function () {
|
|---|
| 37 | nativeToExponential(1, -Infinity);
|
|---|
| 38 | });
|
|---|
| 39 | };
|
|---|
| 40 |
|
|---|
| 41 | // Safari <11 && FF <50
|
|---|
| 42 | var properNonFiniteThisCheck = function () {
|
|---|
| 43 | return !fails(function () {
|
|---|
| 44 | nativeToExponential(Infinity, Infinity);
|
|---|
| 45 | nativeToExponential(NaN, Infinity);
|
|---|
| 46 | });
|
|---|
| 47 | };
|
|---|
| 48 |
|
|---|
| 49 | var FORCED = !ROUNDS_PROPERLY || !throwsOnInfinityFraction() || !properNonFiniteThisCheck();
|
|---|
| 50 |
|
|---|
| 51 | // `Number.prototype.toExponential` method
|
|---|
| 52 | // https://tc39.es/ecma262/#sec-number.prototype.toexponential
|
|---|
| 53 | $({ target: 'Number', proto: true, forced: FORCED }, {
|
|---|
| 54 | toExponential: function toExponential(fractionDigits) {
|
|---|
| 55 | var x = thisNumberValue(this);
|
|---|
| 56 | if (fractionDigits === undefined) return nativeToExponential(x);
|
|---|
| 57 | var f = toIntegerOrInfinity(fractionDigits);
|
|---|
| 58 | if (!$isFinite(x)) return String(x);
|
|---|
| 59 | // TODO: ES2018 increased the maximum number of fraction digits to 100, need to improve the implementation
|
|---|
| 60 | if (f < 0 || f > 20) throw new $RangeError('Incorrect fraction digits');
|
|---|
| 61 | if (ROUNDS_PROPERLY) return nativeToExponential(x, f);
|
|---|
| 62 | var s = '';
|
|---|
| 63 | var m, e, c, d, l, n, xScaled;
|
|---|
| 64 | if (x < 0) {
|
|---|
| 65 | s = '-';
|
|---|
| 66 | x = -x;
|
|---|
| 67 | }
|
|---|
| 68 | if (x === 0) {
|
|---|
| 69 | e = 0;
|
|---|
| 70 | m = repeat('0', f + 1);
|
|---|
| 71 | } else {
|
|---|
| 72 | // TODO: improve accuracy with big fraction digits
|
|---|
| 73 | l = log10(x);
|
|---|
| 74 | e = floor(l);
|
|---|
| 75 | // compute x / pow(10, e - f) and round, avoiding underflow/overflow
|
|---|
| 76 | if (f - e >= 308) {
|
|---|
| 77 | // pow(10, e - f) would underflow to a subnormal or zero; split computation
|
|---|
| 78 | xScaled = x * POW_10_308 * pow(10, f - e - 308);
|
|---|
| 79 | } else {
|
|---|
| 80 | xScaled = x / pow(10, e - f);
|
|---|
| 81 | }
|
|---|
| 82 | n = round(xScaled);
|
|---|
| 83 | // correct tie-breaking: round half up
|
|---|
| 84 | // avoids `2 * x` overflow for values near MAX_VALUE
|
|---|
| 85 | if (xScaled - n >= 0.5) {
|
|---|
| 86 | n += 1;
|
|---|
| 87 | }
|
|---|
| 88 | if (n >= pow(10, f + 1)) {
|
|---|
| 89 | n /= 10;
|
|---|
| 90 | e += 1;
|
|---|
| 91 | }
|
|---|
| 92 | m = $String(n);
|
|---|
| 93 | }
|
|---|
| 94 | if (f !== 0) {
|
|---|
| 95 | m = stringSlice(m, 0, 1) + '.' + stringSlice(m, 1);
|
|---|
| 96 | }
|
|---|
| 97 | if (e === 0) {
|
|---|
| 98 | c = '+';
|
|---|
| 99 | d = '0';
|
|---|
| 100 | } else {
|
|---|
| 101 | c = e > 0 ? '+' : '-';
|
|---|
| 102 | d = $String(abs(e));
|
|---|
| 103 | }
|
|---|
| 104 | m += 'e' + c + d;
|
|---|
| 105 | return s + m;
|
|---|
| 106 | }
|
|---|
| 107 | });
|
|---|