/**
 * 解决浮点数运算精度问题
 */

/**
 * @file 解决浮动运算问题，避免小数点后产生多位数和计算精度损失。
 * 问题示例：2.3 + 2.4 = 4.699999999999999，1.0 - 0.9 = 0.09999999999999998
 */
/**
 * 把错误的数据转正
 * strip(0.09999999999999998)=0.1
 */
function strip(num, precision) {
  if (precision === 0) {
    precision = 12;
  }
  return +parseFloat(num.toPrecision(precision));
}
/**
 * Return digits length of a number
 * @param {number} num Input number
 */
function digitLength(num) {
  // Get digit length of e
  let eSplit = num.toString().split(/[eE]/);
  let len = (eSplit[0].split('.')[1] || '').length - +(eSplit[1] || 0);
  return len > 0 ? len : 0;
}
/**
 * 把小数转成整数，支持科学计数法。如果是小数则放大成整数
 * @param {number} num 输入数
 */
function float2Fixed(num) {
  if (num.toString().indexOf('e') === -1) {
    return Number(num.toString().replace('.', ''));
  }
  let dLen = digitLength(num);
  return dLen > 0 ? num * Math.pow(10, dLen) : num;
}
/**
 * 精确乘法
 */
function times(num1, num2) {
  let others = [];
  for (let _i = 2; _i < arguments.length; _i++) {
    others[_i - 2] = arguments._i;
  }
  if (others.length > 0) {
    return times.apply(
      0,
      [times(num1, num2), others[0]].concat(others.slice(1)),
    );
  }
  let num1Changed = float2Fixed(num1);
  let num2Changed = float2Fixed(num2);
  let baseNum = digitLength(num1) + digitLength(num2);
  let leftValue = num1Changed * num2Changed;
  return leftValue / Math.pow(10, baseNum);
}
/**
 * 精确加法
 */
function plus(num1, num2) {
  let others = [];
  for (let _i = 2; _i < arguments.length; _i++) {
    others[_i - 2] = arguments._i;
  }
  if (others.length > 0) {
    return plus.apply(0, [plus(num1, num2), others[0]].concat(others.slice(1)));
  }
  let baseNum = Math.pow(10, Math.max(digitLength(num1), digitLength(num2)));
  return (times(num1, baseNum) + times(num2, baseNum)) / baseNum;
}
/**
 * 精确减法
 */
function minus(num1, num2) {
  let others = [];
  for (let _i = 2; _i < arguments.length; _i++) {
    others[_i - 2] = arguments._i;
  }
  if (others.length > 0) {
    return minus.apply(
      0,
      [minus(num1, num2), others[0]].concat(others.slice(1)),
    );
  }
  let baseNum = Math.pow(10, Math.max(digitLength(num1), digitLength(num2)));
  return (times(num1, baseNum) - times(num2, baseNum)) / baseNum;
}
/**
 * 精确除法
 */
function divide(num1, num2) {
  let others = [];
  for (let _i = 2; _i < arguments.length; _i++) {
    others[_i - 2] = arguments._i;
  }
  if (others.length > 0) {
    return divide.apply(
      0,
      [divide(num1, num2), others[0]].concat(others.slice(1)),
    );
  }
  let num1Changed = float2Fixed(num1);
  let num2Changed = float2Fixed(num2);
  return times(
    num1Changed / num2Changed,
    Math.pow(10, digitLength(num2) - digitLength(num1)),
  );
}
/**
 * 四舍五入
 */
function round(num, ratio) {
  let base = Math.pow(10, ratio);
  return divide(Math.round(times(num, base)), base);
}
export default {
  strip,
  plus,
  minus,
  times,
  divide,
  round,
  digitLength,
  float2Fixed,
};
