关于javascript:我想用-JS-实现-01-02-输出-03

38次阅读

共计 2312 个字符,预计需要花费 6 分钟才能阅读完成。

起因

昨天被人问到了一个问题:

因为 JS 精度问题 0.1 + 0.2 == 0.30000000000000004,能够不能够得出一个正确的值。0.1 + 0.2 == 0.3

这简略,变成整数,而后再除回去。或者取整,保留小数。

  • ((0.1 + 0.2) * 10).toFixed()/10
  • (0.1 * 10 + 0.2 * 10)/10

而后又被问了,如果我是 两位小数呢?三位呢? 让我说你就没悟性啊!同样情理你加就完事了。而后他急了,他说三十位呢?

这样问题就变了,变成了 JS 是否能存下这样一个数字

我一想,这不就是 大数计算 吗,我刷过。为了简略我找了个库 bignumber 来实现这部分逻辑
new BigNumber(0.1).plus(0.2) 简略的一批。

然而这里我本人 发现了问题:须要依照特定的写法 ,这不合理。我又想到,我之前刷过 计算器,外面给你输出一个 '1+2+3*4' 而后让你输入计算结果(尽管有偷懒的 eval 计划,然而架不住有题解呀)

说整就整,一查:🐶郁闷

  • 题一,只反对加减
  • 题二,反对括号,不反对乘除
  • 题三,逐步变态。基本就不是数学。是一套本人的逻辑。
  • 题四,加密,须要开会员。

没方法,白嫖失败 (tongxin),本人写又太费时间,看看题解 get 了一个关键词 逆波兰式,能够解决计算优先级。

表达式 转换为 逆波兰式

这就不得不吐槽,网上的垃圾资源了

  • 竟然不反对小数
  • 竟然只反对个位
  • 输入后果也是有问题的
  • 竟然搜寻后果在第一屏
  • 竟然前一页都是同一篇文章

好在整数计算是没问题的,本人入手饥寒交迫。咱们把获取到数字哪里在做一个 while 以保障残缺。

    function calculator(str) {let n = 0, charStack = [], numStack = [], reducerStr =  [], leftIndex = -1
        const op = {
            '+' : 1,
            '-' : 1,
            '*' : 2,
            '/' : 2,
            '(' : 3,
            ')' : 3
        }
        while(n < str.length) {const byte = str[n]
            // 数字
            // if(/\d/.test(byte)) {if(/[\d\.]+/.test(byte)) {// reducerStr.push(byte)
                let result = byte;
                let _str = str[n+1]
                while(/[\d\.]+/.test(_str)){
                    result+=_str;
                    n++;
                    _str = str[n+1]
                }
                reducerStr.push(result)
            } else if(/\(|\)/.test(byte)) {
                // 左括号入栈
                if(byte === '(') {charStack.push(byte)
                    leftIndex = n
                    // console.log('左括号', byte)
                // 右括号出栈
                } else {let nowChar = charStack.pop()
                    while(nowChar && nowChar !== '(') {reducerStr.push(nowChar)
                    nowChar = charStack.pop()}
                }
                // 符号
            } else {
                // 字符栈顶元素
                let nowChar = charStack[charStack.length - 1]
                while(nowChar && op[byte] < op[nowChar] && nowChar !== '(') {charStack.pop()
                    reducerStr.push(nowChar)
                    nowChar = charStack[charStack.length - 1]
                }
                charStack.push(byte)
            }
            n++
        }
        while(charStack.length) {reducerStr.push(charStack.pop())
        }
        return reducerStr
    }

解析逆波兰式计算结果

这个也要吐槽,应该是个题解,他把小数取整了 凸(艹皿艹)

把取整干掉。而后把计算地位换成咱们的库。

    var evalRPN = function(tokens) {const stack = [];
        const n = tokens.length;
        for (let i = 0; i < n; i++) {const token = tokens[i];
            if (isNumber(token)) {stack.push((token));
                // stack.push(parseInt(token));
            } else {const num2 = stack.pop();
                const num1 = stack.pop();
                if (token === '+') {stack.push(new BigNumber(num1).plus(num2));
                } else if (token === '-') {stack.push(new BigNumber(num1).minus(num2));
                } else if (token === '*') {stack.push(new BigNumber(num1).times(num2));
                } else if (token === '/') {stack.push(new BigNumber(num1).dividedBy(num2));
                    // stack.push(num1 / num2 > 0 ? Math.floor(num1 / num2) : Math.ceil(num1 / num2));
                }
            }
        }
        return stack.pop();};

    const isNumber = (token) => {return !('+' === token || '-' === token || '*' === token || '/' === token);
    }

便捷测试

这里当然是上 vue 了,加上计算属性,咔咔好用。

相干资源

  1. 前端 BUG 录 – 迷信计数法是什么?这里有一些精度相干的材料,能够点进去看看
  2. 测试地址:http://jsrun.net/9f9Kp/edit

正文完
 0