es.number.to-exponential.js 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. 'use strict';
  2. var $ = require('../internals/export');
  3. var global = require('../internals/global');
  4. var uncurryThis = require('../internals/function-uncurry-this');
  5. var toIntegerOrInfinity = require('../internals/to-integer-or-infinity');
  6. var thisNumberValue = require('../internals/this-number-value');
  7. var $repeat = require('../internals/string-repeat');
  8. var log10 = require('../internals/math-log10');
  9. var fails = require('../internals/fails');
  10. var RangeError = global.RangeError;
  11. var String = global.String;
  12. var isFinite = global.isFinite;
  13. var abs = Math.abs;
  14. var floor = Math.floor;
  15. var pow = Math.pow;
  16. var round = Math.round;
  17. var un$ToExponential = uncurryThis(1.0.toExponential);
  18. var repeat = uncurryThis($repeat);
  19. var stringSlice = uncurryThis(''.slice);
  20. // Edge 17-
  21. var ROUNDS_PROPERLY = un$ToExponential(-6.9e-11, 4) === '-6.9000e-11'
  22. // IE11- && Edge 14-
  23. && un$ToExponential(1.255, 2) === '1.25e+0'
  24. // FF86-, V8 ~ Chrome 49-50
  25. && un$ToExponential(12345, 3) === '1.235e+4'
  26. // FF86-, V8 ~ Chrome 49-50
  27. && un$ToExponential(25, 0) === '3e+1';
  28. // IE8-
  29. var THROWS_ON_INFINITY_FRACTION = fails(function () {
  30. un$ToExponential(1, Infinity);
  31. }) && fails(function () {
  32. un$ToExponential(1, -Infinity);
  33. });
  34. // Safari <11 && FF <50
  35. var PROPER_NON_FINITE_THIS_CHECK = !fails(function () {
  36. un$ToExponential(Infinity, Infinity);
  37. }) && !fails(function () {
  38. un$ToExponential(NaN, Infinity);
  39. });
  40. var FORCED = !ROUNDS_PROPERLY || !THROWS_ON_INFINITY_FRACTION || !PROPER_NON_FINITE_THIS_CHECK;
  41. // `Number.prototype.toExponential` method
  42. // https://tc39.es/ecma262/#sec-number.prototype.toexponential
  43. $({ target: 'Number', proto: true, forced: FORCED }, {
  44. toExponential: function toExponential(fractionDigits) {
  45. var x = thisNumberValue(this);
  46. if (fractionDigits === undefined) return un$ToExponential(x);
  47. var f = toIntegerOrInfinity(fractionDigits);
  48. if (!isFinite(x)) return String(x);
  49. // TODO: ES2018 increased the maximum number of fraction digits to 100, need to improve the implementation
  50. if (f < 0 || f > 20) throw RangeError('Incorrect fraction digits');
  51. if (ROUNDS_PROPERLY) return un$ToExponential(x, f);
  52. var s = '';
  53. var m = '';
  54. var e = 0;
  55. var c = '';
  56. var d = '';
  57. if (x < 0) {
  58. s = '-';
  59. x = -x;
  60. }
  61. if (x === 0) {
  62. e = 0;
  63. m = repeat('0', f + 1);
  64. } else {
  65. // this block is based on https://gist.github.com/SheetJSDev/1100ad56b9f856c95299ed0e068eea08
  66. // TODO: improve accuracy with big fraction digits
  67. var l = log10(x);
  68. e = floor(l);
  69. var n = 0;
  70. var w = pow(10, e - f);
  71. n = round(x / w);
  72. if (2 * x >= (2 * n + 1) * w) {
  73. n += 1;
  74. }
  75. if (n >= pow(10, f + 1)) {
  76. n /= 10;
  77. e += 1;
  78. }
  79. m = String(n);
  80. }
  81. if (f !== 0) {
  82. m = stringSlice(m, 0, 1) + '.' + stringSlice(m, 1);
  83. }
  84. if (e === 0) {
  85. c = '+';
  86. d = '0';
  87. } else {
  88. c = e > 0 ? '+' : '-';
  89. d = String(abs(e));
  90. }
  91. m += 'e' + c + d;
  92. return s + m;
  93. }
  94. });