最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • JavaScript数值Number类型解析:0.1+0.2为什么不等于0.3?

    正文概述 掘金(Kevin_)   2021-07-08   459

    从一道面试题"0.1+0.2 === 0.3",看JavaScript数值Number类型解析

    分析(原来JS的Number是Double)

    0.1 + 0.2 // 0.30000000000000004;
    0.1+0.2 === 0.3 // false
    

    从代码的运行结果来看,显然0.1+0.2是不等于0.3的那么导致这种结果的原因是什么呢?

    JavaScript权威指南第六版-第3章类型”说明,在JavaScript当中对于数字Number类型的表示采用的是 “IEEE 754 标准
    定义的双精度64位格式” 和其他编程语言(如C,Java)不同,JavaScript不区分整数值和浮点数值,所有数值在JavaScript
    中均用双精度浮点数值表示(相当于C,Java中的double),所以在进行数字运算的时候要特别注意精度缺失问题。
    

    IEEE 754标准

    简单介绍“IEEE 754”规范,IEEE 754”采用双精度存储(double-precision 64-bit format IEEE 754 values)占用64 bit

    JavaScript数值Number类型解析:0.1+0.2为什么不等于0.3?

    意义:

    • s(sign) 1位用来表示符号位(正负数)
    • e(exponent) 11位用来表示指数
    • m(mantissa) 52位用来表示尾数

    JavaScript中数字的存储机制

    (s) * (m) * (2^e)

    那么浮点数在运算时又为什么会造成精度缺失呢?

    0.1 >> 0.0001 1001 1001 1001...无限循环
    0.2 >> 0.0011 0011 0011 0011...无限循环
    

    由于存储空间的有限,于是只能模仿十进制进行四舍五入了,但是二进制只有 0 和 1 两个,于是变为 0 舍 1 入。这即是计算机中部分浮点数运算时出现误差,丢失精度的根本原因。

    大整数的精度丢失

    大整数的精度丢失和浮点数本质上是一样的,尾数位最大是 52 位,因此 JS 中能精准表示的最大整数是 Math.pow(2, 53),十进制即 9007199254740992。

    大于 9007199254740992 的可能会丢失精度

    9007199254740992 + 1
    // 丢失 9007199254740992
    9007199254740992 + 2
    // 未丢失 9007199254740994
    9007199254740992 + 3
    // 丢失 9007199254740996
    9007199254740992 + 4
    // 未丢失 9007199254740996
    

    回到问题

    那么为什么0.1+0.2不等于0.3呢?

    • 因为 计算机 的存储原理,造成计算机在存储浮点数时,存储的不是准确数值,存储的是一个近似数值,显示时,显示为一个浮点数值效果;
    • 当浮点数直接参与计算或者参与比较时,实际参与预算或者比较的数值,也是近似值;
    • 就造成了计算或者比较时,一定会存在误差,这个误差在特殊情况下会表现出误差的结果;

    ps:JavaScript中规定,即使使用科学计数法,数据类型也是浮点数类型,浮点数的误差/浮点数的精确丢失

    模拟计算

    先将 0.1 和 0.2 转化成二进制,对于十进制转二进制,整数部分除二取余,倒序排列,小数部分乘二取整,顺序排列

    0.1 转化为二进制0.0 0011 0011 0011 0011 0011 0011 … (0011循环)

    0.2 转化为二进制0.0011 0011 0011 0011 0011 0011 0011 … (0011循环)

    然后根据IEEE 754标准 (s) * (m) * (2^e)来表示

    // 0.1
    e = -4;
    m = 1.1001100110011001100110011001100110011001100110011010 (52位)
    
    // 0.2
    e = -3;
    m = 1.1001100110011001100110011001100110011001100110011010 (52位)
    
    //这里的m指的是小数点后的52位,e为m的指数,小数点前的整数部分就是隐藏位s来表示符号
    //如果发现指数e不一致时,一般采用右移,因为即使右边溢出了,损失的精度远远小于左移时的溢出
    //转化之后进行求和
    
    e = -3; m = 0.1100110011001100110011001100110011001100110011001101 (52位)
    +
    e = -3; m = 1.1001100110011001100110011001100110011001100110011010 (52位)
    // 得到
    e = -3; m = 10.0110011001100110011001100110011001100110011001100111 (52位)
    // 保留一位整数
    e = -2; m = 1.00110011001100110011001100110011001100110011001100111 (53位)
    // 发现超过了52位,于是要做四舍五入,因为无法区分哪个更接近,于是规则是保留偶数的一个,得到最终的二进制数
    m=1.0011001100110011001100110011001100110011001100110100 (52位)
    // 然后得到最终的二进制数
    1.0011001100110011001100110011001100110011001100110100 * 2^-2 = 0.010011001100110011001100110011001100110011001100110100
    // 现在转化为十进制,二进制小数转化为十进制的方法是小数点后 第一位 *2 ^ -1,第二位 *2 ^ -2,以此类推
    // 可以利用等比数列求和公式,最终求得十进制数为0.30000000000000004
    

    结论

    所以0.1 + 0.2 的最终结果是0.30000000000000004


    起源地下载网 » JavaScript数值Number类型解析:0.1+0.2为什么不等于0.3?

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元