number-precision.js 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. var NP = (function (exports) {
  2. 'use strict';
  3. /**
  4. * @desc 解决浮动运算问题,避免小数点后产生多位数和计算精度损失。
  5. * 问题示例:2.3 + 2.4 = 4.699999999999999,1.0 - 0.9 = 0.09999999999999998
  6. */
  7. /**
  8. * 把错误的数据转正
  9. * strip(0.09999999999999998)=0.1
  10. */
  11. function strip(num, precision) {
  12. if (precision === void 0) { precision = 12; }
  13. return +parseFloat(num.toPrecision(precision));
  14. }
  15. /**
  16. * Return digits length of a number
  17. * @param {*number} num Input number
  18. */
  19. function digitLength(num) {
  20. // Get digit length of e
  21. var eSplit = num.toString().split(/[eE]/);
  22. var len = (eSplit[0].split('.')[1] || '').length - (+(eSplit[1] || 0));
  23. return len > 0 ? len : 0;
  24. }
  25. /**
  26. * 把小数转成整数,支持科学计数法。如果是小数则放大成整数
  27. * @param {*number} num 输入数
  28. */
  29. function float2Fixed(num) {
  30. if (num.toString().indexOf('e') === -1) {
  31. return Number(num.toString().replace('.', ''));
  32. }
  33. var dLen = digitLength(num);
  34. return dLen > 0 ? strip(num * Math.pow(10, dLen)) : num;
  35. }
  36. /**
  37. * 检测数字是否越界,如果越界给出提示
  38. * @param {*number} num 输入数
  39. */
  40. function checkBoundary(num) {
  41. if (_boundaryCheckingState) {
  42. if (num > Number.MAX_SAFE_INTEGER || num < Number.MIN_SAFE_INTEGER) {
  43. console.warn(num + " is beyond boundary when transfer to integer, the results may not be accurate");
  44. }
  45. }
  46. }
  47. /**
  48. * 精确乘法
  49. */
  50. function times(num1, num2) {
  51. var others = [];
  52. for (var _i = 2; _i < arguments.length; _i++) {
  53. others[_i - 2] = arguments[_i];
  54. }
  55. if (others.length > 0) {
  56. return times.apply(void 0, [times(num1, num2), others[0]].concat(others.slice(1)));
  57. }
  58. var num1Changed = float2Fixed(num1);
  59. var num2Changed = float2Fixed(num2);
  60. var baseNum = digitLength(num1) + digitLength(num2);
  61. var leftValue = num1Changed * num2Changed;
  62. checkBoundary(leftValue);
  63. return leftValue / Math.pow(10, baseNum);
  64. }
  65. /**
  66. * 精确加法
  67. */
  68. function plus(num1, num2) {
  69. var others = [];
  70. for (var _i = 2; _i < arguments.length; _i++) {
  71. others[_i - 2] = arguments[_i];
  72. }
  73. if (others.length > 0) {
  74. return plus.apply(void 0, [plus(num1, num2), others[0]].concat(others.slice(1)));
  75. }
  76. var baseNum = Math.pow(10, Math.max(digitLength(num1), digitLength(num2)));
  77. return (times(num1, baseNum) + times(num2, baseNum)) / baseNum;
  78. }
  79. /**
  80. * 精确减法
  81. */
  82. function minus(num1, num2) {
  83. var others = [];
  84. for (var _i = 2; _i < arguments.length; _i++) {
  85. others[_i - 2] = arguments[_i];
  86. }
  87. if (others.length > 0) {
  88. return minus.apply(void 0, [minus(num1, num2), others[0]].concat(others.slice(1)));
  89. }
  90. var baseNum = Math.pow(10, Math.max(digitLength(num1), digitLength(num2)));
  91. return (times(num1, baseNum) - times(num2, baseNum)) / baseNum;
  92. }
  93. /**
  94. * 精确除法
  95. */
  96. function divide(num1, num2) {
  97. var others = [];
  98. for (var _i = 2; _i < arguments.length; _i++) {
  99. others[_i - 2] = arguments[_i];
  100. }
  101. if (others.length > 0) {
  102. return divide.apply(void 0, [divide(num1, num2), others[0]].concat(others.slice(1)));
  103. }
  104. var num1Changed = float2Fixed(num1);
  105. var num2Changed = float2Fixed(num2);
  106. checkBoundary(num1Changed);
  107. checkBoundary(num2Changed);
  108. return times((num1Changed / num2Changed), Math.pow(10, digitLength(num2) - digitLength(num1)));
  109. }
  110. /**
  111. * 四舍五入
  112. */
  113. function round(num, ratio) {
  114. var base = Math.pow(10, ratio);
  115. return divide(Math.round(times(num, base)), base);
  116. }
  117. var _boundaryCheckingState = true;
  118. /**
  119. * 是否进行边界检查,默认开启
  120. * @param flag 标记开关,true 为开启,false 为关闭,默认为 true
  121. */
  122. function enableBoundaryChecking(flag) {
  123. if (flag === void 0) { flag = true; }
  124. _boundaryCheckingState = flag;
  125. }
  126. var index = { strip: strip, plus: plus, minus: minus, times: times, divide: divide, round: round, digitLength: digitLength, float2Fixed: float2Fixed, enableBoundaryChecking: enableBoundaryChecking };
  127. exports.strip = strip;
  128. exports.plus = plus;
  129. exports.minus = minus;
  130. exports.times = times;
  131. exports.divide = divide;
  132. exports.round = round;
  133. exports.digitLength = digitLength;
  134. exports.float2Fixed = float2Fixed;
  135. exports.enableBoundaryChecking = enableBoundaryChecking;
  136. exports['default'] = index;
  137. return exports;
  138. }({}));