JS 模拟计算机计算方式(含有防丢失精度方法)

JS 模拟计算机计算方式(含有防丢失精度方法)

输入公式字符串,自动计算出结果,支持加减乘除、括号、幂函数

export {
    compute,
    add,
    cut,
    multiple,
    divide,
}

/**
 * 计算公式 支持带括号,计算次方
 * @param str 字符串如:(100-587)*100+(1024*2+1)+0.05*3*100
 */
function compute(str) {
    let temp = '';
    let arr = [];
    if (str[0] === '-') {
        temp = '-';
        str = str.substring(1);
    }
    for (let i = 0; i < str.length; i++) {
        if (str[i] === '-' && isNaN(str[i - 1])) {
            temp += str[i];
            continue;
        }
        if (isNaN(str[i]) && str[i] !== '.') {
            if (temp) { arr.push(temp); }
            arr.push(str[i]);
            temp = '';
            continue;
        }
        temp += str[i];
    }
    if (temp) { arr.push(temp); }
    return computeByBrackets(arr);
}

/**
 * 计算带括号的式子
 * @param arr
 * @returns {number}
 */
function computeByBrackets(arr) {
    while(true) {
        let computeArr = [];
        let index = arr.indexOf('(');
        if (index === -1) { break; }
        let lastIndex = findLastIndex(arr, index, index);
        for (let i = index + 1; i < lastIndex; i++) {
            computeArr.push(arr[i]);
        }
        let result;
        if (computeArr.indexOf('(') !== -1) {
            result = computeByBrackets(computeArr);
        } else {
            result = computeResult(computeArr);
        }
        arr.splice(index, lastIndex - index + 1, result);
    }
    return computeResult(arr);
}

/**
 * 计算式子 如:2-32+5*2/2
 * @param arr
 * @returns {number}
 */
function computeResult(arr) {
    let index = 1;
    let result = 0;
    if (arr.length === 3) {
        return SingleCalc(arr[index], arr[index - 1], arr[index + 1]);
    }
    let power = arr.indexOf('^');
    if (power !== -1) {
        index = power;
        result = SingleCalc(arr[index], arr[index - 1], arr[index + 1]);
        arr.splice(index - 1, 3, result);
        return computeResult(arr);
    }
    let mult = arr.indexOf('*');
    let div = arr.indexOf('/');
    if (mult !== -1 && div !== -1) {
        index = mult < div ? mult : div;
        result = SingleCalc(arr[index], arr[index - 1], arr[index + 1]);
        arr.splice(index - 1, 3, result);
        return computeResult(arr);
    }
    if (mult !== -1) {
        index = mult;
        result = SingleCalc(arr[index], arr[index - 1], arr[index + 1]);
        arr.splice(index - 1, 3, result);
        return computeResult(arr);
    }
    if (div !== -1) {
        index = div;
        result = SingleCalc(arr[index], arr[index - 1], arr[index + 1]);
        arr.splice(index - 1, 3, result);
        return computeResult(arr);
    }
    result = SingleCalc(arr[index], arr[index - 1], arr[index + 1]);
    arr.splice(index - 1, 3, result);
    return computeResult(arr);
}

/**
 * 根据运算符号,计算加减乘除以及次方
 * @return {number}
 */
function SingleCalc(c,a,b){
    switch(c) {
        case '+': return add(a, b);
        case '-': return cut(a, b);
        case '*': return multiple(a, b);
        case '/': return divide(a, b);
        case '^': return Math.pow(Number(a), Number(b));
        default: return NaN;
    }
}

/**
 * 查找匹配括号
 * @param arr 传入的数组如:['(','3','+','2',')']
 * @param index '('的下标位置
 * @param lastIndex ')'的下标位置
 * @returns {number|undefined}
 */
function findLastIndex(arr, index, lastIndex) {
    let last = arr.indexOf(')', lastIndex + 1);
    let first = arr.indexOf('(', index + 1);
    if (first === -1 || first > last) { return last; }
    if (first < last) { return findLastIndex(arr, first, last); }
}

/**
 * 解决运算精度丢失问题  加法
 * @param arg1 加数
 * @param arg2 加数
 * @returns {number}
 */
function add(arg1, arg2) {
    let r1, r2, m, s1 = arg1.toString(), s2 = arg2.toString();
    let sArr = s1.split('.');
    r1 = sArr[1] ? sArr[1].length : 0;
    sArr = s2.split('.');
    r2 = sArr[1] ? sArr[1].length : 0;
    m = Math.pow(10, Math.max(r1, r2));
    return (arg1 * m + arg2 * m) / m;
}

/**
 * 解决运算精度丢失问题  减法
 * @param arg1 减数
 * @param arg2 被减数
 * @returns {number}
 */
function cut(arg1, arg2) {
    let r1, r2, m, n, s1 = arg1.toString(), s2 = arg2.toString();
    let sArr = s1.split('.');
    r1 = sArr[1] ? sArr[1].length : 0;
    sArr = s2.split('.');
    r2 = sArr[1] ? sArr[1].length : 0;
    m = Math.pow(10, Math.max(r1, r2));
    //last modify by deeka
    //动态控制精度长度
    n = (r1 >= r2) ? r1 : r2;
    let result = ((arg1 * m - arg2 * m) / m).toFixed(n);
    return Number(result);
}

/**
 * 解决运算精度丢失问题  乘法
 * @param arg1 乘数
 * @param arg2 乘数
 * @returns {number}
 */
function multiple(arg1, arg2) {
    if (!arg1 || !arg2) { return 0; }
    let m = 0, s1 = arg1.toString(), s2 = arg2.toString();
    let sArr = s1.split('.');
    m += sArr[1] ? sArr[1].length : 0;
    sArr = s2.split('.');
    m += sArr[1] ? sArr[1].length : 0;
    return Number(s1.replace(".", "")) * Number(s2.replace(".", "")) / Math.pow(10, m)
}

/**
 * 解决运算精度丢失问题  除法
 * @param arg1 除数
 * @param arg2 被除数
 * @returns {number}
 */
function divide(arg1, arg2) {
    let t1 = 0, t2 = 0, r1, r2, s1 = arg1.toString(), s2 = arg2.toString();
    //判断除法分母不能为0,占时返回0
    if (s2 === '0') {
        return 0;
    }
    let sArr = s1.split('.');
    t1 = sArr[1] ? sArr[1].length : 0;
    sArr = s2.split('.');
    t2 = sArr[1] ? sArr[1].length : 0;
    r1 = Number(s1.replace(".", ""));
    r2 = Number(s2.replace(".", ""));
    return (r1 / r2) * Math.pow(10, t2 - t1);
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值