2

cause

A question was asked yesterday:

Because of the JS accuracy problem 0.1 + 0.2 == 0.30000000000000004 , is it possible to get a correct value? 0.1 + 0.2 == 0.3

It's simple, turn it into an integer, and then divide it back. Or round up and keep decimals.

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

Then I was asked again, what if I am two decimal places? What about the three? Let me say you have no savvy! In the same way, you add it and you are done. Then he was in a hurry, what about thirty people?

The question then changes, and it becomes JS can save such a number .

I think, it is not that large numbers computing it, I brush off. For simplicity, I found a library bignumber to implement this part of the logic
new BigNumber(0.1).plus(0.2) simple batch.

But here I myself: I need to follow a specific way of writing , which is unreasonable. I thought about it again, I used the calculator before, and it will give you the input of '1+2+3*4' and then let you output the calculation results (although there is a lazy 061ca538eed7fd solution, but it eval

Just say the whole thing, check it: 🐶 depressed

  • Question one, only supports addition and subtraction
  • Question two, support brackets, do not support multiplication and division
  • Question three, gradually perverted . It's not mathematics at all. It's a set of own logic.
  • Question four, encryption, you need to open a membership.

No way, failed (tongxin), writing by yourself is too time-consuming, look at the solution to get a keyword reverse Polish formula , can handle the calculation of priority.

The expression is converted to inverse Polish

This has to complain about the garbage resources on the Internet

  • actually does not support decimals
  • Actually only supports singles
  • The output is also problematic
  • The search results are on the first screen
  • Actually the previous page is the same article

Fortunately, the calculation of integers is no problem. We are doing a while where we get the number to ensure completeness.

    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
    }

Analyze the results of inverse Polish calculations

, it should be a problem solution, he rounded the decimal 161ca538eedb28 convex (艹艹) .

Round off. Then change the calculation location to our library.

    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 );
    }

Convenient testing

Here is of course the vue, plus the calculated attributes, it is easy to use.

image.png

related resources

  1. front-end BUG record-what is scientific notation? Here are some accuracy-related information, you can click in to see
  2. test address: http://jsrun.net/9f9Kp/edit

Reply to the comment section Lao Tie's plan, the plan is feasible.

image.png

Add another content related to accuracy.

Math.abs(0.1+0.2 - 0.3) < Number.EPSILON
Math.abs(0.1+0.2 - 0.3000000000000001) < Number.EPSILON
Math.abs(0.1+0.2 - 0.300000000000001) < Number.EPSILON
The value of the EPSILON attribute is close to 2.2204460492503130808472633361816E-16, or 2-52.

linong
29.2k 声望9.5k 粉丝

Read-Search-Ask