index.umd.js 5.0 KB

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