资讯专栏INFORMATION COLUMN

关于js小数浮点数操作出现的精度问题的原因以及解决方法

Chiclaim / 1055人阅读

摘要:我们可以利用该函数限定返回数值的位数,从而达到提高精度的效果。

一、问题的引入

今天在看基础js文章的时候发现了一个浮点数的精度问题,当打印小数相加的时候有时候会出现数值不准确的情况,如果是在做一些需要数据精度要求较高的工作的时候稍有不慎就会出现问题

console.log(0.1+0.1) //0.2
console.log(0.1+0.2) //0.30000000000000004(精度最高保留到17位)

查阅资料之后,发现是因为像 0.1+0.2这样的操作对于计算机来说转换为二进制之后将是两个无限循环的数。而对于计算机而言是不允许有无限的,进行四舍五入之后双精度浮点数保留52位,结果为0.0100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100转为十进制就是0.30000000000000004

二、基本解决方法

【1】利用toFixed(digits)
toFixed函数在digits参数存在的情况下返回一个所给数值的定点数表示法的字符串(digits要在0-20之间,默认为0)。我们可以利用该函数限定返回数值的位数,从而达到提高精度的效果。

 var floatNum=0.1+0.2;
 console.log(floatNum);   //0.30000000000000004
 console.log(floatNum.toFixed(2)) //0.30
 
 console.log(1.35.toFixed(1)) //1.4
 console.log(1.33335.toFixed(4)); //1.3334 

在这里我们看上去是解决了问题,但是和直接进行相加一样有时候toFixed 也会有问题

    Chrome:
    console.log(1.55.toFixed(1));// 1.6
    console.log(1.555.toFixed(2));//1.55
    console.log(1.5555.toFixed(3));//1.556

关于这个问题,MDN上函数的描述为 “该数值在必要时进行四舍五入,另外在必要时会用 0 来填充小数部分,以便小数部分有指定的位数。”至于是怎么定义“必要”的,不同的浏览器会有不同的情况。

    IE:
    console.log(1.55.toFixed(1)); //1.6
    console.log(1.555.toFixed(2)); //1.56
    console.log(1.5555.toFixed(3)); //1.556

【2】重写toFixed函数

思路为放大原有的数据,利用整数的整除来避免精度丢失

    function toFixed(num, s) {
        if(typeof s==="undefined"){
            return parseInt(num)+"";
        }
        if(typeof s!=="number"){
            return "请正确输入保留位数(数字)";
        }
        var times = Math.pow(10, s);
        var newNum = num * times+0.5;//加0.5是为了实现四舍五入中"入"的那0.5
        newNum = parseInt(newNum) / times;
        return newNum + ""//toFixed返回的是字符类型的数据
    }
    console.log(toFixed(1.5)) //2
    console.log(toFixed(1.55,1)) //1.6
    console.log(toFixed(1.555,2))  //1.56
    console.log(toFixed(1.5555,3)) //1.556

【3】基础运算自实现

    function getDecimalLength(num){ //获取小数位长度
        let length=0;
        try{
            length =String(num).split(".")[1].length
        }catch(e){
            //TODO handle the exception
        }
        return length;
    }
    
    function getBeishu(num1,num2){  //获取放大倍数
        let num1DecimalLength=getDecimalLength(num1);
        let num2DecimalLength=getDecimalLength(num2);
        let longer=Math.max(num1DecimalLength,num2DecimalLength);
        return Math.pow(10,longer);
    }
    
    
    //加减乘除算法
    function add(num1,num2){
        let beishu=getBeishu(num1,num2);
        return (num1*beishu+num2*beishu)/beishu;
    }
    
    function sub(num1,num2){
        let beishu=getBeishu(num1,num);
        return (num1*beishu-num2*beishu)/beishu;
    }
    
    function mul(num1,num2){
        let num1DecLen=getDecimalLength(num1);
        let num2DecLen=getDecimalLength(num2);
        let num1toStr=String(num1);
        let num2toStr=String(num2);
        return Number(num1toStr.replace(".",""))*Number(num2toStr.replace(".",""))/Math.pow(10,num1DecLen+num2DecLen)
    }
    
    
    function dev(num1,num2){
        let num1DecLen=getDecimalLength(num1);
        let num2DecLen=getDecimalLength(num2);
        let num1toStr=String(num1);
        let num2toStr=String(num2);
        return Number(num1toStr.replace(".",""))/Number(num2toStr.replace(".",""))/Math.pow(10,num1DecLen-num2DecLen)
    }

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

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

相关文章

  • 「干货」细说 Javascript 中点数精度丢失问题(内附好课推荐)

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

    senntyou 评论0 收藏0
  • 该死IEEE-754点数,说「约」就「约」,你底线呢?以JS名义来好好查查你

    摘要:而的浮点数设置的偏移值是,因为指数域表现为一个非负数,位,所以,实际的,所以。这是因为它们在转为二进制时要舍入部分的不同可能造成的不同舍 IEEE 754 表示:你尽管抓狂、骂娘,但你能完全避开我,算我输。 一、IEEE-754浮点数捅出的那些娄子 首先我们还是来看几个简单的问题,能说出每一个问题的细节的话就可以跳过了,而如果只能泛泛说一句因为IEEE754浮点数精度问题,那么下文还是...

    gaosboy 评论0 收藏0
  • JS中如何理解点数

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

    bang590 评论0 收藏0
  • 为什么0.1+0.2不等于0.3

    摘要:又如,对于,结果其实并不是,但是最接近真实结果的数,比其它任何浮点数都更接近。许多语言也就直接显示结果为了,而不展示一个浮点数的真实结果了。小结本文主要介绍了浮点数计算问题,简单回答了为什么以及怎么办两个问题为什么不等于。 原文地址:为什么0.1+0.2不等于0.3 先看两个简单但诡异的代码: 0.1 + 0.2 > 0.3 // true 0.1 * 0.1 = 0.01000000...

    Profeel 评论0 收藏0
  • [ JS 基础 ] JS 点数四则运算精度丢失问题 (3)

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

    hoohack 评论0 收藏0

发表评论

0条评论

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