JS中的数字
和其他语言不同,JavaScript中只有一种数据类型Number,它遵循IEEE 754标准,是一种使用64位固定位来表示浮点数,就是常见的double双精度浮点数类型。
64位可以分为三个部分即符号位(sign)、指数位(exponent)和尾数位(mantissa)
- 符号位:第一位是表示正负的符号位,为0为正,为1为负
- 指数位:第2到到12位表示次方位,即2的多少次方
- 尾数位:13到64位为尾数
![]()
按照科学记数法的基本规范,应有,所以M的整数部分一定为1,因此可以省略整数部分的1以提高表示精度。例如3.5用科学记数法可以表示为,舍去1后M为11,由于指数位为11位且无符号,表示范围为0~2047,而科学记数法指数位可以为负,因此将[0,1022]表示为负数[1024,2047]表示为整数,因此指数部分需要减去1023来进行存储。
所以实际公式为
为什么会出现误差?
以0.1为例子,0.1使用二进制可以表示为0.0001100110011001100(1100)循环,也就是1.100110011001100x2^-4因为尾数存储位数有限,是不能精确的表示0.1的,再将存储的值转为10进制其值为0.100000000000000005551115123126
0.1 + 0.2 !== 0.3
由于浮点数精度原因,0.1和0.2均无法被准确表示
// 0.1 和 0.2 都转化成二进制后再进行运算
0.00011001100110011001100110011001100110011001100110011010 +
0.0011001100110011001100110011001100110011001100110011010 =
0.0100110011001100110011001100110011001100110011001100111
// 转成十进制正好是 0.30000000000000004
为什么Number.MAX_SAFE_INTEGER 是 9007199254740991
因为尾数部分算上隐含的1最多有53个1,53个1转化为10进制即为9007199254740991,大于这个值时尾数部分已经没有多余的位数可以表示数字了
不是无法精确表示0.1吗,为什么let x =0.1,输出x等于0.1?
由于使用52位字节码来表示尾数且省略了整数部分的1,因此尾数部分最多表示的数为也就是9007199254740992,与之相对应的10进制科学记数法尾数为9.007199254740992,长度为16位,也是JS所能表示的最大精度。而0.1的真实值在16位范围内为0.10000000000000,即0.1