JS中数字运算时,有一个叫做 数字运算中的精度缺失的问题,这篇文章,就带着大家了解下JS运算中精度的缺失问题。
首先我们先来看一个例子:
![img_d2bb1683d09bda99f19abc63898dc741.png](https://yqfile.alicdn.com/img_d2bb1683d09bda99f19abc63898dc741.png?x-oss-process=image/resize,w_1400/format,webp)
这里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就会认为他就是那个值。
比较拗口,举个例子:
![img_5b37484a7eb140000d129000ef2ed1fb.png](https://yqfile.alicdn.com/img_5b37484a7eb140000d129000ef2ed1fb.png?x-oss-process=image/resize,w_1400/format,webp)
所以我们现在应该可以理解,就是说由于0.1转换成二进制时是shenzhen.offcn.com无限循环的,所以在计算机中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的近似范围内的,于是就可以得到正确答案。至于哪些值计算后能得到正确结果,哪些不能,我们也不需要去记。
最好的方法就是我们想办法规避掉这类小数计算时的精度问题就好了,那么最常用的方法就是将浮点数转化成整数计算。因为整数都是可以精确表示的。
方法也很简单,举个例子:
![img_2a400c7c9b37e05558f77fa98128bc83.png](https://yqfile.alicdn.com/img_2a400c7c9b37e05558f77fa98128bc83.png?x-oss-process=image/resize,w_1400/format,webp)