为什么JS中0.1+0.2 != 0.3

简介: 原文:为什么JS中0.1+0.2 != 0.3  为什么JS中0.1+0.2 != 0.3   在我曾经的一篇《 javascript入门教程 (2) 》中,讲到JS中数字运算时,我们提到过一个叫做 数字运算中的精度缺失的问题,当时我们只是简单说了下,并未对其原因做了解。
原文: 为什么JS中0.1+0.2 != 0.3

 

为什么JS中0.1+0.2 != 0.3

 

在我曾经的一篇《 javascript入门教程 (2) 》中,讲到JS中数字运算时,我们提到过一个叫做 数字运算中的精度缺失的问题,当时我们只是简单说了下,并未对其原因做了解。这篇文章,我就带着大家了解下 JS运算中精度的缺失问题

首先我们先来看一个例子

console.log(0.1 + 0.2)  // 结果是0.30000000000000004,而不是3

这里0.1 + 0.2 != 0.3 这个就是我们要解决的问题了。

要弄清这个问题的原因,首先我们需要了解下在计算机中数字是如何存储和运算的。在计算机中,数字无论是定点数还是浮点数都是以多位二进制的方式进行存储的。在JS中数字采用的IEEE 754的双精度标准进行存储,我们可以无需知道他的存储形式,只需要简单的理解成就是存储一个数值所使用的二进制位数比较多而已,这样得到的数会更加精确。

这里为了简单直观,我们使用定点数来说明问题。在定点数中,如果我们以8位二进制来存储数字。

 

对于整数来说,十进制的35会被存储为: 00100011 其代表 2^5 + 2^1 + 2^0
对于纯小数来说,十进制的0.375会被存储为: 0.011 其代表 1/2^2 + 1/2^3 = 1/4 + 1/8 = 0.375

而对于像0.1这样的数值用二进制表示你就会发现无法整除,最后算下来会是 0.000110011....由于存储空间有限,最后计算机会舍弃后面的数值,所以我们最后就只能得到一个近似值。在JS中采用的IEEE 754的双精度标准也是一样的道理,我们且不管这个标准下的存储方式跟定点数存储有何不同,单单在这一点上他们都是相同的,也就是存储空间有限,当出现这种无法整除的小数的时候就会取一个近似值,在js中如果这个近似值足够近似,那么js就会认为他就是那个值。(比较拗口,举个例子)

console.log(0.1000000000000001)  
// 0.1000000000000001 (中间14个0,会打印出它本身)

console.log(0.10000000000000001)  
// 0.1 (中间15个0,js会认为这两个值足够接近,所以会显示0.1)

    所以我们现在应该可以理解,就是说由于0.1转换成二进制时是无限循环的,所以在计算机中0.1只能存储成一个近似值。另外说一句,除了那些能表示成 x/2^n 的数可以被精确表示以外,其余小数都是以近似值得方式存在的。
    在0.1 + 0.2这个式子中,0.1和0.2都是近似表示的,在他们相加的时候,两个近似值进行了计算,导致最后得到的值是0.30000000000000004,此时对于JS来说,其不够近似于0.3,于是就出现了0.1 + 0.2 != 0.3 这个现象。
    当然,也并非所有的近似值相加都得不到正确的结果。有时两个近似值进行计算的时候,得到的值是在JS的近似范围内的,于是就可以得到正确答案。至于哪些值计算后能得到正确结果,哪些不能,我们也不需要去记。最好的方法就是我们想办法规避掉这类小数计算时的精度问题就好了,那么最常用的方法就是将浮点数转化成整数计算。因为整数都是可以精确表示的。


方法也很简单,举个例子:

对于0.1 + 0.02 我们需要转化成 ( 10 + 2 ) / 1e2
对于0.1 * 0.02 我们则转化成 1 * 2 / 1e3

按照这个思路,写个简单的方法就好了。

 

 

另外就是如果你在学习前端的过程中有任何问题想要咨询,欢迎关注 LearnInPro的公众号,在上面随时向我提问哦。

 

目录
相关文章
|
7月前
|
数据可视化 JavaScript 前端开发
Turf.js介绍
Turf.js介绍
543 0
|
7月前
|
JavaScript 前端开发
js详解1
js详解1
45 2
|
4月前
|
自然语言处理 JavaScript
js之this
js之this
32 1
|
6月前
|
JavaScript 安全 前端开发
JS神奇的或0(|0)
可以看到明显的带或0运算与不带或0运算的结果无论是位数还是符号位都有不同。 那这中间到底发生了什么? 这里找一个数字为例:117063531626496 要想验证这个问题,思路如下: 1,对比变更前后的数字的二进制格式 2,找到是否有数字表示的安全边界 首先按照思路1,我们看一下这个数字和这个数字或0后的二进制格式分别是什么:
|
7月前
|
JavaScript
js的一些理解
js的一些理解
42 1
|
7月前
|
JavaScript 前端开发
初识JS
这篇内容介绍了JavaScript的基础知识,包括DOM和BOM(相当于内置模块和第三方模块)、变量的声明(var、let、const的特点和区别)、数组操作(如push、pop、splice等)、字典操作以及DOM操作示例。变量部分强调了var的变量提升和块级作用域问题,let和const的块级作用域和不可重复声明,以及const用于创建不可变的常量。在实际应用中,展示了如何动态改变HTML元素内容和创建新元素的示例。
|
7月前
|
存储 JavaScript 前端开发
js的一些小技巧
js的一些小技巧
|
JavaScript
js实现全选反选
js实现全选反选
|
JavaScript
js超实用的小技巧(1)
js超实用的小技巧(1)
|
JSON API 数据格式
一起来学 next.js - getServerSideProps 篇
getServerSideProps 是 next.js 中的一项特色功能,可以让我们在给页面设置一些初始的 props 参数。