[ JS 基本 ] JS 浮点数四则运算精度丧失题目 (3)

基于这个题目:javascript活动基本题目 ,我想应当也有一部份人没有认真对待过js中浮点数的四则运算涌现的题目。

1.题目形貌

示例代码:
    var x  = 0.3 - 0.2; //30美分减去20美分
    var y =  0.2 - 0.1; //20美分减去10美分
    x == y;             // =>false,两值不相称
    x == 0.1;           // =>false,实在值为:0.09999999999999998
    y == 0.1;           // =>true
    这个题目并不只是在Javascript中才会涌现,任何运用二进制浮点数的编程言语都邑有这个题目,只不过在 C++/C#/Java 这些言语中已封装好了方法来防止精度的题目,而 JavaScript 是一门弱范例的言语,从设想思想上就没有对浮点数有个严厉的数据范例,所以精度偏差的题目就显得分外凸起。

2.发生缘由

Javascript采纳了IEEE-745浮点数示意法(险些一切的编程言语都采纳),这是一种二进制示意法,能够正确地示意分数,比方1/2,1/8,1/1024。遗憾的是,我们经常使用的分数(特别是在金融的盘算方面)都是十进制分数1/10,1/100等。二进制浮点数示意法并不能正确的示意相似0.1如许 的简朴的数字,上诉代码的中的x和y的值异常靠近终究的正确值,这类盘算结果能够胜任大多数的盘算使命:这个题目也只要在比较两个值是不是相称时才会涌现。
javascript的将来版本也许会支撑十进制数字范例以防止这些舍入题目,在这之前,你更情愿运用大整数举行主要的金融盘算,比方,要运用整数‘分’而不是运用小数‘元’举行货比单元的运算———以上整顿自《Javascript威望指南P37》

3. 0.1+0.2的盘算

起首,我们要站在盘算机的角度思索 0.1 + 0.2 这个看似小儿科的题目。我们晓得,能被盘算机读懂的是二进制,而不是十进制,所以我们先把 0.1 和 0.2 转换成二进制看看:
0.1 => 0.0001 1001 1001 1001…(无穷轮回)
0.2 => 0.0011 0011 0011 0011…(无穷轮回)
双精度浮点数的小数部份最多支撑 52 位,所以二者相加今后获得这么一串 0.0100110011001100110011001100110011001100110011001100 因浮点数小数位的限定而截断的二进制数字,这时候,我们再把它转换为十进制,就成了 0.30000000000000004。

4.处理方案 (引自:处理方案

为了处理浮点数运算不正确的题目,在运算前我们把列入运算的数先晋级(10的X的次方)到整数,等运算完后再降级(0.1的X的次方)。

  //加法   
    Number.prototype.add = function(arg){   
        var r1,r2,m;   
        try{r1=this.toString().split(".")[1].length}catch(e){r1=0}   
        try{r2=arg.toString().split(".")[1].length}catch(e){r2=0}   
        m=Math.pow(10,Math.max(r1,r2))   
        return (this*m+arg*m)/m   
    }  
    //减法   
Number.prototype.sub = function (arg){   
    return this.add(-arg);   
}   

//乘法   
Number.prototype.mul = function (arg)   
{   
    var m=0,s1=this.toString(),s2=arg.toString();   
    try{m+=s1.split(".")[1].length}catch(e){}   
    try{m+=s2.split(".")[1].length}catch(e){}   
    return Number(s1.replace(".",""))*Number(s2.replace(".",""))/Math.pow(10,m)   
}   

//除法   
Number.prototype.div = function (arg){   
    var t1=0,t2=0,r1,r2;   
    try{t1=this.toString().split(".")[1].length}catch(e){}   
    try{t2=arg.toString().split(".")[1].length}catch(e){}   
    with(Math){   
        r1=Number(this.toString().replace(".",""))   
        r2=Number(arg.toString().replace(".",""))   
        return (r1/r2)*pow(10,t2-t1);   
    }   
}

ok,就是如许了,人人今后在本身的代码中碰到浮点数要想起js运算的如许的一个特征,防止不必要的毛病!

    原文作者:kraaas
    原文地址: https://segmentfault.com/a/1190000002613722
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞