数字作为语言的基础十分重要,JS也一样。JS中的数字只有一种就是双精度浮点数。看ES文档的时候发现一个奇怪的问题,JS中可以表示的数字是有限的!于是产生了一系列的疑问:JS中到底有多少个数字?JS中的数字最小值是多少?最大值呢?JS精确度又是多少?下面一一来说说。
JS中到底有多少个数字?
文档的回答是:2的64次方减去2的53次方再加三。这是怎么计算的呢?继续往下看:后面的加3是三个特殊的数字正无穷,负无穷和NAN。剩下的还要去除两个特殊的数字正零和负零,剩下要从双精度浮点数的规范IEEE754讲起,规范规定了双精度浮点数是64位的,第1位为符号位表示正负,第2位到12位为指数位表示以2为基底的指数值,剩下的52位为小数位或分数位。所有的值可以分为10类的值,其中四种是NaN类型的,剩下的6种正负各四种以0为原点对称分布,以正数(符号位为0)为例:
1.指数位全0,分数位全0:表示正无穷;
2.指数位全0,分数位非全0并且以0为虚拟的分数首位(所以分数共53位):表示正非规范数值;
3.指数位非全0非全1,分数位任意值并且以1为虚拟的分数首位(所以分数共53位):表示正规范数值;
正数共有:1 + Math.pow(2,52) - 1 + (Math.pow(2, 11) - 1) * (Math.pow(2, 52)) = Math.pow(2, 63) - Math.pow(2, 52)
加上负数的所有共有:Math.pow(2, 64) - Math.pow(2, 53)
补充:当指数全1时为NaN值,但是ES规范规定NaN只有一个值,且任意两个NaN不做区分,且不相等。
JS中最大值和最小值?
此处的最大值和最小值是取绝对值的,且不包含极值0和正无穷。最大值好研究当然是分数位取最大值约为2,乘以指数位最大值Math.pow(2, 1023),也就是略小于Math.pow(2, 1024),因为此值包括更大的值会当做正无穷。最小值出现在上述的情况2中:分数位最后一位为1,指数位为最后一位为1偏移1023后得到-1022,所以相乘得到最小值:Math.pow(2,-1074) == 5e-324 。
补充:Math.pow(2,-1075)仍可得出此值,但已经没有太大意义,以为此值已经极小且精确度因为非零开始的分数位减少而降低。
JS精确度是多少?
通过第一个问题我们知道了基于二进制的双精度浮点数并不能全部映射到整个实数范围,实际上差的甚远。即便是8倍精度也无法穷尽所有实数只是精确度更高,适应范围更广。那么精确度是怎么消失的呢?我们通常说的实数都是十进制的,JS引擎里用的也是十进制的,但是存储却是二进制,但是二进制在转十进制时存在很多缺陷,分两种情况说:第一种是整数,正整数能精准表示的范围是0到Math.pow(2, 53),因为通过调节指数分数都可以变成一一对应的整数,但是超过这个范围时就存在问题了,因为已经到了分数能一一对应的最大值,例如:Math.pow(2, 53)到Math.pow(2, 54)这个区间的数字分数(二进制)每增加1,比如从0到1的改变会相当于十进制里的2个数字,且是偶数;Math.pow(2, 54)到Math.pow(2, 55)区间则是代表4个数字;依次类推指数增长。然后真正的JS引擎显示时却并非一定准确依赖这个规则。所以整数的精确度为小于Math.pow(2, 53),小于15位的十进制整数是准确的。之后越来越不准确,直到超过21位会用指数显示。小数精确度也存在丢失现象和整数不同的是平常用的小数都存在这种现象比如0.1,用分数表示是1/10,在可以表示的所有数里最接近的是:是一个分数位循环的分数0.000110011001100...(1100循环),所以只能用能表示的数里最接近0.1这个值得数表示,小数不准确的原因是无法跟实数一一对应,精确度大概是17位。
补充知识点:
js并非一种数字类型还有其他几种比如32位和16位以及整数,处于对整数精确度的需求有些浏览器实现了精确的十进制表示:biginteger。
js有两种表示法:固定数字表示和科学计数法表示,前者用于小数点后少于5个0或者长度小于21位,否则使用以10为基底的科学计数法。
网友评论