JS数字存储-指数位-尾数位-最大安全数字

  • Post author:
  • Post category:其他




JS数字存储



存储标准

JavaScript中的数字的存储标准是IEEE754浮点数标准。代码中使用的无论是整数还是小数,都是同一种数据类型——64位双精度浮点型。



64位存储划分

64位分别是1位符号位,11位指数位,52位尾数位。


符号位
计算机只能识别0和1,(-1)^x, x代表计算机存储的符号位,所以可得出0代表正,1代表负。


指数位
11位指数位理论上存储的最大值是11111111111(11个1),所代表的数字就是2^11-1 = 2047。而指数也有正负之分,所以取0-2047一个中间数1023作为分界,0-1022为负,1024-2047为正,因此指数范围[-1023, 1024],可以表示一个数字的范围


尾数位
首先将数字转换为科学记数法,科学记数法小数点之前一直是1,所以不用占位,小数部分即为尾数位,表示该数字的精度。


实际值计算公式
V = (-1)^S * 2^(E-1023) * M
S:符号位存值
E:指数位存值
M:尾数位存值


举例:存储8.8125


十转换转换二进制
整数位: 8 转化为 1000
	方法:(依次除以2,位数为除以2的次数,值为余数部分,直到商为1)
		 8 除以 2 等于 4 余数为 0,所以第一位为 04 除以 2 等于 2 余数为 0,所以第二位为 02 除以 2 等于 1 余数为 0,所以第三位为 01 除以 2 等于 0 余数为 1,所以第四位为 1
小数位:0.8125转化为0.1101
方法:(小数部分依次乘2,位数为乘2的次数,值为整数部分,直到积不含小数)
	 0.81252 等于 1.625,所以第一位为10.6252 等于 1.25, 所以第二位为10.252 等于 0.5, 所以第三位为00.52 等于 1, 所以第四位为1
8.125 转化为二进制位 1000.1101


转化为科学记数法
1000.1101 = 1.0001101 * 2^3


代入公式求值

很明显此值为正,所以S = 0;

指数位E – 1023 = 3,所以E = 1026转化为二进制为:10000000010

尾数位为:0001101



最终结果
0 10000000010 0001101000000000000000000000000000000000000000000000



存储的最大安全整数

我们都应该或多或少知道js有个最大安全整数,这个值是2^53-1,为 9007199254740991,在这个范围(-2^53-1, 2^53-1)之内,所有的整数都有唯一的浮点数表示,这就叫安全整数。



JS所能表示的最大数

由上面的指数位和位数位,我们应该很容易得出来结论,JS所能表示的最大数应该是:
0111111111111111111111111111111111111111111111111111111111111111(1个0,63个1),这个数字肯定远远大于最大安全整数。



不知你是否有相同的疑问,最大安全整数范围怎么来的?为什么超过这个范围会不安全?



那我们现在就根据最大安全整数找寻下为什么

	先记录下最大安全整数:9007199254740991
	2^53 - 1 = 11111111111111111111111111111111111111111111111111111 (531),转换为科学记数法,1.1111111111111111111111111111111111111111111111111111再存储发现数字不会发生变化,因为尾数正好是52位,恰好可以完美存储。
	2^53 = 100000000000000000000000000000000000000000000000000000 (530),转换成科学记数法,因为后面都是0,存储起来看着也没啥问题
	2^53 + 1 = 100000000000000000000000000000000000000000000000000001 (中间520),这时候转换为科学记数法为1.00000000000000000000000000000000000000000000000000001 * 2^53,尾数为为小数点后面数位,此时为53位,而js只能存储52位,所以会发生近似取值,01进,所以存储的尾数为0000000000000000000000000000000000000000000000000001510)取出在换成科学记数法1.0000000000000000000000000000000000000000000000000001 * 2^53
	接下来我们将原始值和经过计算机存储的值拿出来进行比较:
	原始:100000000000000000000000000000000000000000000000000001
	存储:100000000000000000000000000000000000000000000000000010
	没存储的值 = 2^53 + 1
	存储过的值 = 2^53 + 2
	这样经过计算机存储,值就不再一一对应。
	自己可以测试
	Math.pow(2, 53) = 9007199254740992
	Math.pow(2, 53) - 1 = 9007199254740991
	Math.pow(2, 53) +1 = 9007199254740992
	Math.pow(2, 53) + 2 = 9007199254740994
至于Math.pow(2, 53) +1的值为什么不等于Math.pow(2, 53) + 2 而是等于Math.pow(2, 53),和上述计算结果不一致,这个我没搞明白,欢迎知道的在下方评论!



版权声明:本文为lx199509原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。