js-01JS 整数是怎么表示的,0.1 + 0.2 === 0.3吗,数字超过最大限制如何处理?

227 阅读3分钟

1、JS整数表示

初级水平: 根据国际标准 IEEE 754,JavaScript 内部,所有数字都是以64位(一个字节8位)浮点数形式储存,即使整数也是如此。所以有,1 === 1.0 (二进制存储最大值=2^n-1)

中级水平:理解存储方式 结果=(-1)^s * f * 2^e,f是连续的,e不连续

  • 符号位(sign),用第1位:符号位,0表示正数,1表示负数
  • 指数(exponent),用第2位到第12位(共11位):指数部分 分正负,e范围: 0--2047(2^11-1)
  • 尾数(fraction),用第13位到第64位(共52位):有效数字 f是一个小数,范围: [1,2)

进一步分析:fraction是一个小数,整数部分固定为1,所以52个二进制位只存储小数部分就可以了。所以加上整数部分1后,最大数 Number.MAX_SAFE_INTEGER = Math.pow(2,53)-1;最小值类似

2、0.1+0.2===0.3//false

精度丢失可能出现在进制转换和对阶运算中

JavaScript 使用 Number 类型来表示数字(整数或浮点数),遵循 IEEE 754 标准,通过 64 位来表示一个数字(1 + 11 + 52)

1 符号位,0 表示正数,1 表示负数 s
11 指数位(e)
52 尾数,小数部分(即有效数字)

最大安全数字:Number.MAX_SAFE_INTEGER = Math.pow(2, 53) - 1,转换成整数就是 16 位,所以 0.1 === 0.1,是因为通过 toPrecision(16) 去有效位之后,两者是相等的。
在两数相加时,会先转换成二进制,0.1 和 0.2 转换成二进制的时候尾数会发生无限循环,然后进行对阶运算,JS 引擎对二进制进行截断,所以造成精度丢失。

高逼格ES6
浮点数的运算精度丢失问题。
可以引入ES6中的机器精度Number.EPSILON判定是计算误差还是数据不同。
Number.EPSILON为JavaScript可以表示的最小精度2^(-52)。

2**、0.1+0.2===0.3//false

初级水平:0.1 + 0.2 不等于0.3 ,因为Number是浮点数,表示小数的时候有精度损失。

中级水平:二进制表示整数时,十进制转二进制是除2取余法,以5为例,最后结果是101

5 / 2 = 21
2 / 2 = 10
1 / 2 = 01

二进制表示小数时,十进制转二进制是乘2取整法,只不过是从2^-1开始,以0.75为例,结果为11

0.75 * 2 = 1.5 取整 1 剩下 0.5
0.5 * 2 = 1 取整  1 剩下 0 运算结束

0.1的时候就悲催了

0.1 * 2 = 0.2 取整 0 剩下 0.2
0.2 * 2 = 0.4 取整 0 剩下 0.4
0.4 * 2 = 0.8 取整 0 剩下 0.8
0.8 * 2 = 1.6 取整 1 剩下 0.6
0.6 * 2 = 1.2 取整 1 剩下 0.2
0.2 * 2 = 0.4 取整 0 剩下 0.4
0.4 * 2 = 0.8 取整 0 剩下 0.8
0.8 * 2 = 1.6 取整 1 剩下 0.6
0.6 * 2 = 1.2 取整 1 剩下 0.2

所以有限的52个bit是无法表示0.1这种数字的,唯一的方法就是截取。

3、数字超限

Number.MAX_SAFE_INTEGER = Math.pow(2,53)-1;

高精度算法High Accuracy Algorithm)是处理大数字的数学计算方法。在一般的科学计算中,会经常算到小数点后几百位或者更多,当然也可能是几千亿几百亿的大数字。一般这类数字我们统称为高精度数,高精度算法是用计算机对于超大数据的一种模拟加,减,乘,除,乘方阶乘开方等运算。对于非常庞大的数字无法在计算机中正常存储,于是,将这个数字拆开,拆成一位一位的,或者是四位四位的存储到一个数组中, 用一个数组去表示一个数字,这样这个数字就被称为是高精度数。高精度算法就是能处理高精度数各种运算的算法,但又因其特殊性,故从普通数的算法中分离,自成一家。