index.iife.js 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. var NP = (function (exports) {
  2. 'use strict';
  3. /**
  4. * @desc 解决浮动运算问题,避免小数点后产生多位数和计算精度损失。
  5. *
  6. * 问题示例:2.3 + 2.4 = 4.699999999999999,1.0 - 0.9 = 0.09999999999999998
  7. */
  8. /**
  9. * Correct the given number to specifying significant digits.
  10. *
  11. * @param num The input number
  12. * @param precision An integer specifying the number of significant digits
  13. *
  14. * @example strip(0.09999999999999998) === 0.1 // true
  15. */
  16. function strip(num, precision) {
  17. if (precision === void 0) { precision = 15; }
  18. return +parseFloat(Number(num).toPrecision(precision));
  19. }
  20. /**
  21. * Return digits length of a number.
  22. *
  23. * @param num The input number
  24. */
  25. function digitLength(num) {
  26. // Get digit length of e
  27. var eSplit = num.toString().split(/[eE]/);
  28. var len = (eSplit[0].split('.')[1] || '').length - +(eSplit[1] || 0);
  29. return len > 0 ? len : 0;
  30. }
  31. /**
  32. * Convert the given number to integer, support scientific notation.
  33. * The number will be scale up if it is decimal.
  34. *
  35. * @param num The input number
  36. */
  37. function float2Fixed(num) {
  38. if (num.toString().indexOf('e') === -1) {
  39. return Number(num.toString().replace('.', ''));
  40. }
  41. var dLen = digitLength(num);
  42. return dLen > 0 ? strip(Number(num) * Math.pow(10, dLen)) : Number(num);
  43. }
  44. /**
  45. * Log a warning if the given number is out of bounds.
  46. *
  47. * @param num The input number
  48. */
  49. function checkBoundary(num) {
  50. if (_boundaryCheckingState) {
  51. if (num > Number.MAX_SAFE_INTEGER || num < Number.MIN_SAFE_INTEGER) {
  52. console.warn(num + " is beyond boundary when transfer to integer, the results may not be accurate");
  53. }
  54. }
  55. }
  56. /**
  57. * Create an operation to support rest params.
  58. *
  59. * @param operation The original operation
  60. */
  61. function createOperation(operation) {
  62. return function () {
  63. var nums = [];
  64. for (var _i = 0; _i < arguments.length; _i++) {
  65. nums[_i] = arguments[_i];
  66. }
  67. var first = nums[0], others = nums.slice(1);
  68. return others.reduce(function (prev, next) { return operation(prev, next); }, first);
  69. };
  70. }
  71. /**
  72. * Accurate multiplication.
  73. *
  74. * @param nums The numbers to multiply
  75. */
  76. var times = createOperation(function (num1, num2) {
  77. var num1Changed = float2Fixed(num1);
  78. var num2Changed = float2Fixed(num2);
  79. var baseNum = digitLength(num1) + digitLength(num2);
  80. var leftValue = num1Changed * num2Changed;
  81. checkBoundary(leftValue);
  82. return leftValue / Math.pow(10, baseNum);
  83. });
  84. /**
  85. * Accurate addition.
  86. *
  87. * @param nums The numbers to add
  88. */
  89. var plus = createOperation(function (num1, num2) {
  90. // 取最大的小数位
  91. var baseNum = Math.pow(10, Math.max(digitLength(num1), digitLength(num2)));
  92. // 把小数都转为整数然后再计算
  93. return (times(num1, baseNum) + times(num2, baseNum)) / baseNum;
  94. });
  95. /**
  96. * Accurate subtraction.
  97. *
  98. * @param nums The numbers to subtract
  99. */
  100. var minus = createOperation(function (num1, num2) {
  101. var baseNum = Math.pow(10, Math.max(digitLength(num1), digitLength(num2)));
  102. return (times(num1, baseNum) - times(num2, baseNum)) / baseNum;
  103. });
  104. /**
  105. * Accurate division.
  106. *
  107. * @param nums The numbers to divide
  108. */
  109. var divide = createOperation(function (num1, num2) {
  110. var num1Changed = float2Fixed(num1);
  111. var num2Changed = float2Fixed(num2);
  112. checkBoundary(num1Changed);
  113. checkBoundary(num2Changed);
  114. // fix: 类似 10 ** -4 为 0.00009999999999999999,strip 修正
  115. return times(num1Changed / num2Changed, strip(Math.pow(10, digitLength(num2) - digitLength(num1))));
  116. });
  117. /**
  118. * Accurate rounding method.
  119. *
  120. * @param num The number to round
  121. * @param decimal An integer specifying the decimal digits
  122. */
  123. function round(num, decimal) {
  124. var base = Math.pow(10, decimal);
  125. var result = divide(Math.round(Math.abs(times(num, base))), base);
  126. if (num < 0 && result !== 0) {
  127. result = times(result, -1);
  128. }
  129. return result;
  130. }
  131. var _boundaryCheckingState = true;
  132. /**
  133. * Whether to check the bounds of number, default is enabled.
  134. *
  135. * @param flag The value to indicate whether is enabled
  136. */
  137. function enableBoundaryChecking(flag) {
  138. if (flag === void 0) { flag = true; }
  139. _boundaryCheckingState = flag;
  140. }
  141. var index = {
  142. strip: strip,
  143. plus: plus,
  144. minus: minus,
  145. times: times,
  146. divide: divide,
  147. round: round,
  148. digitLength: digitLength,
  149. float2Fixed: float2Fixed,
  150. enableBoundaryChecking: enableBoundaryChecking,
  151. };
  152. exports.strip = strip;
  153. exports.plus = plus;
  154. exports.minus = minus;
  155. exports.times = times;
  156. exports.divide = divide;
  157. exports.round = round;
  158. exports.digitLength = digitLength;
  159. exports.float2Fixed = float2Fixed;
  160. exports.enableBoundaryChecking = enableBoundaryChecking;
  161. exports['default'] = index;
  162. return exports;
  163. }({}));