关于JS小数运算的精度误差问题

引言
这里呢,笔者先说说为啥要聊聊这个看起来似乎不太重要的问题吧,其实这还是得从笔者今天在一个技术群里遇到得一个疑问说起。笔者在偶然的刷群消息的时候,一个问题瞬间引起了笔者的注意:
0.1 + 0.2 === 3
吗?这个时候可能就会有人说,这还用问吗,肯定是对的啊。好吧,emmmmm.....,其实答案是否定的,下面就让笔者来聊聊这里面的坑吧。
0.1 + 0.2 为啥不等于 0.3 呢?

js
内部储存的一个问题了。在计算机领域当中呢,数字无论是定点数还是浮点数,都是以二进制的形式储存的。而在我们的js
当中,数字是采用IEEE754
的双精度标准进行储存,当然呢,这里我们也不用纠结这个内部到底是怎么储存的,我们可以单纯的理解为只是储存一个数字用到的二进制位数比较多而已,这样能更精确的表示数字。
举个栗子
对于整数来说,十进制的
35
会被存储为:00100011
其代表2^5 + 2^1 + 2^0
对于小数来说,十进制的
0.375
会被存储为:0.011
其代表1/2^2 + 1/2^3 = 1/4 + 1/8 = 0.375
这里就会有人问了,这个二进制小数是怎么转换的呢
十进制小数二进制表示法
这个方法其实很好理解:
文字描述该过程如下:将该数字乘以2,取出整数部分作为二进制表示的第1位;然后再将小数部分乘以2,将得到的整数部分作为二进制表示的第2位;以此类推,知道小数部分为0。
特殊情况: 小数部分出现循环,无法停止,则用有限的二进制位无法准确表示一个小数,这也是在编程语言中表示小数会出现误差的原因
说一大段不如一个例子来的明确
/*就比如一个十进制小数0.6转为二进制*/
0.6 * 2 = 1.2 ------------ 1
0.2 * 2 = 0.4 ------------ 0
0.4 * 2 = 0.8 ------------ 0
0.8 * 2 = 1.6 ------------ 1
0.6 * 2 = 1.2 ------------ 1
很清晰的发现死循环了,那怎么办呢,这就该用到我们上面说的特殊情况了。看到这,大家也应该明白为什么js
中会出现精度缺失的情况了。
二进制小数怎么转十进制呢
其实方法和普通的二进制转十进制差不多,话不多说,看栗子。
还是拿0.6
来说事,它的二进制表示为
1001 1001 1001 1001 ...
转换一下就是
0.6 = 1 * 2^-1 + 0 * 2^-2 + 0 * 2^-3 + 1 * 2^-4 + ...
看完笔者的这篇文章,相信大家应该会有种恍然大悟的感觉,好吧,不瞒大家说,笔者当时也是这个表情。

转载自:https://juejin.cn/post/6844903885329399815