logologo

表达式求值并处理精度问题

Jun 13, 2022 · 5min

起因是公司项目中需要用到公式计算,直接使用的eval进行处理,精度问题无可避免。在安装了皮佬的babel-plugin-arithmetic插件后,依然没有得到解决,原因是执行eval函数并不会走babel编译。

要做的事情

function formula(params) {}
formula(`0.1 + 0.2`) // 0.3

实现一个函数,输入字符串公式,返回的结果,且无精度问题

实现

function formula(list) {
  const result = calc(list, 0, list.length - 1);
  console.log(`计算的结果值等于${result}`);
}

function calc(s, l, r) {
  let op = -1,
    pri = 1000 - 1,
    cur_pri,
    temp = 0,
    i = l;

  while (i <= r) {
    cur_pri = 1000;
    switch (s[i]) {
      case '+':
      case '-':
        cur_pri = 1 + temp;
        break;
      case '*':
      case '/':
        cur_pri = 2 + temp;
        break;
      case '(':
        temp += 100;
        break;
      case ')':
        temp -= 100;
        break;
    }
    if (cur_pri <= pri) {
      pri = cur_pri;
      op = i;
    }
    i++;
  }

  if (op === -1) {
    let num = 0;
    let val = s.slice(l, r + 1).trim();
    if (/^[+-]?(0|([1-9]\d*))(\.\d+)?$/.test(val)) {
      return parseFloat(val);
    }
    for (let i = l; i <= r; i++) {
      if (s[i] < '0' || s[i] > '9') continue;
      num = num * 10 + (s[i] - '0');
    }
    return num;
  }

  let a = calc(s, l, op - 1);
  let b = calc(s, op + 1, r);
  switch (s[op]) {
    case '+':
      return accAdd(a, b);
    case '-':
      return accSub(a, b);
    case '*':
      return accMul(a, b);
    case '/':
      return accDiv(a, b);
  }
  return 0;
}

最后计算的四个函数直接拿了babel-plugin-arithmetic中的源码,程序员拷代码的事能叫抄吗?

2022 © yanghuanrong