您的位置 首页 java

JavaScript浮点数的精度问题深究

JavaScript 浮点数 的精度问题

javascript浮点数的精度问题是老生常谈了,但往往只知道0.1 + 0.2 != 0.3,究其原因,只能说出javascript精度问题,知其然而不知其所以然。 比如我,知道小数运算会有精度问题,但不知道 整数运算同样会出现精度问题

82234342434234235339 + 23338435345455243948
// 结果
105572777779689490000
 

究其原因,网上看了些文章,但好多细节略过了,让我这种没有预备知识的看的 一脸懵逼 。比如十进制0.1转换成 二进制 咋转的?干,没说

javascript中的 Number

在javascript中,数值类型都是Number,无论是整数还是浮点数。Number采用的是 IEEE 754标准的64 位双精度浮点数 。往往解释js精度问题基本上就只能说道这了,但我还是不明白为什么呀?

IEEE 754标准的64 位双精度浮点数

js采用的这种浮点数,一个数字由64位组成,你可以理解成: 00000011101…0001011001这么一串

那我们数字得有正负吧?这个这种浮点数它用 第0位来表示正负 。0表示正数,1表示负数

接下来 第1位~第11位用来表示指数 第12位~第63位表示 有效数字 。如下图

小数的精度问题

我们先来看0.1+0.2的运算过程是怎样的。

  • 0.1和0.2转为二进制表示
  • 将两个二进制数相加
  • 将结果转为十进制

关于十进制小数如何转成二进制可以看这篇文章,很简单的。 当你把0.1转为二进制的时候你会发现,这货居然无穷的。(实际输出可以直接在控制台尝试:(0.1).toString(2))

但是我们刚刚说了,js采用的这种浮点数表示法,有效数字只有52位,也就是0.1转成二进制以后最终只能保留小数点后52位,如下:

0.1 -> 0.0001100110011001100110011001100110011001100110011001
0.2 -> 0.0011001100110011001100110011001100110011001100110011
 

只要你试过,你就会开心的发现,0.1~0.9,除了0.5以外,都是无穷的,nice。

如果你不想自己计算两个二进制数相加,可以用我写的twoBigIntSum方法将两个位数相加

那么0.1 + 0.2最终得到的就是

0.0100110011001100110011001100110011001100110011001100

把它转为十进制是0.30000000000000004,开不开心,意不意外。

整数精度问题

最让我诧异的是整数居然也会有精度问题,看两个例子:

19571992547450991 === 19571992547450990 // true
输入:82234342434234235339 -> 输出:82234342434234240000
 

道理和小数的精度问题是一样的,有效数只有52位,也就是整数的安全范围是-2^53 – 1~2^53 – 1(52位都为1),超出这个范围的整数精度就会出现问题。javascript中也提供了Number.MAX_SAFE_INTEGER接口,返回在安全范围内的最大整数。

是不是很刺激?

回到我们开头的问题:

82234342434234235339 + 23338435345455243948
// 结果
105572777779689490000
 

这是为什么呢?

就是因为这两个数超出了安全范围

82234342434234235339 --实际上等于--> 82234342434234240000
23338435345455243948 --实际上等于--> 23338435345455243000
将两数相加又出现精度问题,所以最后加和得到
105572777779689490000
 

文章来源:智云一二三科技

文章标题:JavaScript浮点数的精度问题深究

文章地址:https://www.zhihuclub.com/178522.shtml

关于作者: 智云科技

热门文章

网站地图