资讯专栏INFORMATION COLUMN

[ JS 基础 ] JS 浮点数四则运算精度丢失问题 (3)

hoohack / 1841人阅读

摘要:基于这个问题运动基础问题,我想应该也有一部分人没有认真对待过中浮点数的四则运算出现的问题。解决方案引自解决方案为了解决浮点数运算不准确的问题,在运算前我们把参加运算的数先升级的的次方到整数,等运算完后再降级的的次方。

基于这个问题: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运算的这样的一个特性,避免不必要的错误!

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/85567.html

相关文章

  • 关于 JavaScript 浮点运算精度解决方案

    摘要:原因至于问题产生的原因,或者关于问题的更详细的描述,大家请看下面几个文章浮点运算浮点值运算舍入误差基础浮点数四则运算精度丢失问题解决方案这里主要讨论一下解决方案的问题,上面几篇文章的解决思路,都是重写加法减法乘法和除法运算。 问题背景 在 chrome 浏览器中调出开发者工具,在控制台窗口输入下面的表达式: 0.1 + 0.2 // 期望:0.3,结果:0.300...

    jsyzchen 评论0 收藏0
  • 由parseInt 引发的问题---想到浮点运算精度丢失---看透js number 的 encod

    摘要:如题先陈述下问题背景偶尔测测自己写的计算器,随便输入玩嘛,然后发生下面诡异的事情当我从一个输入到十个的时候,过程显示都是正确的,像这样继续输入一个的时候,然后就这个样子了什么原因呢看了下自己的代码,代码重要部分长这样的这里用了一下强制转化为 如题 先陈述下问题背景 偶尔测测自己写的计算器,随便输入玩嘛,然后发生下面诡异的事情:当我从一个 1 输入到十个 1 的时候,过程显示都是正确的...

    hightopo 评论0 收藏0
  • JS 的整型你懂了吗?

    摘要:浮点数并不是能够精确表示范围内的所有数的,虽然浮点型的范围看上去很大。但其实浮点数在保存数字的时候做了规格化处理,以进制为例小数点前只需要保留位数对于二进制来说,小数点前保留一位,规格化后始终是节省了,这个并不需要保存。 JS 中的最大安全整数是多少? JS 中所有的数字类型,实际存储都是通过 8 字节 double 浮点型 表示的。浮点数并不是能够精确表示范围内的所有数的, 虽然 ...

    yuanxin 评论0 收藏0
  • JS中如何理解浮点数?

    摘要:本文通过介绍的二进制存储标准来理解浮点数运算精度问题,和理解对象的等属性值是如何取值的,最后介绍了一些常用的浮点数精度运算解决方案。浮点数精度运算解决方案关于浮点数运算精度丢失的问题,不同场景可以有不同的解决方案。 本文由云+社区发表 相信大家在平常的 JavaScript 开发中,都有遇到过浮点数运算精度误差的问题,比如 console.log(0.1+0.2===0.3)// fa...

    bang590 评论0 收藏0
  • 「干货」细说 Javascript 中的浮点精度丢失问题(内附好课推荐)

    摘要:前言最近,朋友问了我这样一个问题在中的运算结果,为什么是这样的虽然我告诉他说,这是由于浮点数精度问题导致的。由于可以用阶码移动小数点,因此称为浮点数。它的实现遵循标准,使用位精度来表示浮点数。 showImg(https://segmentfault.com/img/remote/1460000018981071); 前言 最近,朋友 L 问了我这样一个问题:在 chrome 中的运算...

    senntyou 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<