Avoiding problems with JavaScript's weird decimal calculations

后端 未结 6 669
我寻月下人不归
我寻月下人不归 2020-11-29 05:13

I just read on MDN that one of the quirks of JS\'s handling of numbers due to everything being \"double-precision 64-bit format IEEE 754 values\" is that when you d

6条回答
  •  [愿得一人]
    2020-11-29 05:32

    There are libraries that seek to solve this problem but if you don't want to include one of those (or can't for some reason, like working inside a GTM variable) then you can use this little function I wrote:

    Usage:

    var a = 194.1193;
    var b = 159;
    a - b; // returns 35.11930000000001
    doDecimalSafeMath(a, '-', b); // returns 35.1193
    

    Here's the function:

    function doDecimalSafeMath(a, operation, b, precision) {
        function decimalLength(numStr) {
            var pieces = numStr.toString().split(".");
            if(!pieces[1]) return 0;
            return pieces[1].length;
        }
    
        // Figure out what we need to multiply by to make everything a whole number
        precision = precision || Math.pow(10, Math.max(decimalLength(a), decimalLength(b)));
    
        a = a*precision;
        b = b*precision;
    
        // Figure out which operation to perform.
        var operator;
        switch(operation.toLowerCase()) {
            case '-':
                operator = function(a,b) { return a - b; }
            break;
            case '+':
                operator = function(a,b) { return a + b; }
            break;
            case '*':
            case 'x':
                precision = precision*precision;
                operator = function(a,b) { return a * b; }
            break;
            case '÷':
            case '/':
                precision = 1;
                operator = function(a,b) { return a / b; }
            break;
    
            // Let us pass in a function to perform other operations.
            default:
                operator = operation;
        }
    
        var result = operator(a,b);
    
        // Remove our multiplier to put the decimal back.
        return result/precision;
    }
    

提交回复
热议问题