检查十进制浮点数

时间:2014-07-23 05:54:50

标签: javascript

通常我们希望0.1+0.2===0.3为真。但它不是javascript会产生的结果。由于javascript显示十进制浮点数,但内部存储二进制浮点数。所以这会返回false。

如果我们使用chrome开发人员工具控制台,我们会得到以下结果:

0.1+0.2;//0.30000000000000004

0.1+1-1;//0.10000000000000009


0.1 + 0.2 === 0.3 ;// returns false but we expect to be true.
0.1+1-1===0.1;//returns false

由于舍入错误,作为最佳实践,我们不应直接比较非整数。相反,考虑舍入误差的上限。这样的上限称为机器epsilon。

这是epsilon方法:

var eps = Math.pow(2,-53);
function checkEq(x,y){
    return Math.abs(x - y) <  eps;
}

现在,如果我们检查它会返回true。

checkEq(0.1+0.2,0.3);// returns true
checkEq(0.1+1-1,0.1);//returns true

没关系。但如果我检查一下:

checkEq(0.3+0.6,0.9);// returns false

哪个不合适,而不是我们所期望的。

那么,我们该怎么做才能返回正确的结果?


我试图解决的问题是:

var lx,ly,lxi,lyi;
function isFloating(x){
   return x.toString().indexOf('.');
}
function checkEq(x,y){
   lxi = x.toString().length - x.toString().indexOf('.') - 1;
   lyi = y.toString().length - y.toString().indexOf('.') - 1;
   lx = isFloating(x) > -1 ? lxi : 0;
   ly = isFloating(y) > -1 ? lyi : 0;
   return x.toFixed(lx) - y.toFixed(ly)===0;
}

现在,修好了。如果我像这样检查它会很好:

checkEq(0.3,0.3); //returns true

但是以下内容返回false

checkEq(0.3+0.6,0.9)

首先,它的值存储在binaray浮点数中,然后在计算后返回十进制浮点数。

现在,我如何为checkEq(0.3+0.6,0.9) 0.3.toFixed(lx) and 0.6.toFixed(lx)中的每个输入设置toFixed()方法,然后只添加:

    var lx,ly,lxi,lyi;
    function isFloating(x){
    return x.toString().indexOf('.');
    }
    function checkEq(x,y){
    x = x.toString().split(/\+ | \- | \/ | \ | \\ */);
    y = x.toString().split(/\+ | \- | \/ | \ | \\*/);

    for(var i=0;i<x.length,y.length;i++){
    //here too I may be wrong...
       lxi = x[i].toString().length - x[i].toString().indexOf('.') - 1;
       lyi = y[i].toString().length - y[i].toString().indexOf('.') - 1;
    // particularly after this would wrong...
       lx = isFloating(x[i]) > -1 ? lxi : 0; 
       ly = isFloating(y[i]) > -1 ? lyi : 0;

    //And, here I'm stucked too badly...
    //take splitted operators to calculate:
    //Ex- '0.3 + 1 - 1' 
    // Number('0.3').toFixed(1) + Number('1').toFixed(0) - Number('1').toFixed(0)
    //But careful, we may not know how many input will be there....


    }

//return x.toFixed(lx) - y.toFixed(ly)===0;
}

其他答案也欢迎,但非常感谢帮助我使用我的代码。

3 个答案:

答案 0 :(得分:0)

也许您应该尝试一些现有的JS Math库,例如bignumber.js,它支持任意精度算术。从头开始实施所有内容将非常耗时且乏味。

实施例

0.3+0.6    //0.8999999999999999
x = new BigNumber('0.3')    // "0.3"
y = new BigNumber('0.6')    // "0.6"
z = new BigNumber('0.9')    // "0.9"
z.equals(x.plus(y))    // true

答案 1 :(得分:0)

我认为你应该为epsilon增加一点价值。

您还可以查看math.js:math.js的比较函数也检查近似相等。比较解释如下:

http://mathjs.org/docs/datatypes/numbers.html#comparison

所以你可以这样做:

math.equal(0.1 + 0.2, 0.3); // true
math.equal(0.3 + 0.6, 0.9); // true

更好的是,math.js支持bignumbers(see docs),所以你可以这样做:

math.equal(math.bignumber(0.1) + math.bignumber(0.2), math.bignumber(0.3);

或使用表达式解析器:

math.config({number: 'bignumber'});

math.eval('0.1 + 0.2');        // returns BigNumber 0.3, not 0.30000000000000004
math.eval('0.1 + 0.2 == 0.3'); // returns true

答案 2 :(得分:0)

不等函数,例如平等(但也有地板和ceil)受到舍入误差的严重影响,并且考虑到epsilon可能在某些情况下有效,但也可能给出错误的答案(例如abs(x-y) < eps可能会返回是的,而x和y的确切值确实不同);你应该做一个错误分析,以确保它是正常的。没有通用的方法来解决浮点问题:这取决于您的应用程序。如果您的输入是十进制数,并且您只使用加法,减法和乘法,如果精度足够大,则可以使用十进制浮点算法,以便可以准确表示所有数据。您还可以使用合理算术,例如big-rational(未尝试)。