我们平常编程中遇见的数字其实都非常局限,比如处理金额的时候,一般就是0到几百万或者几亿之间,再或者我们会使用Infinity之类的抽象数字,其实在js中,数字还有很多特殊的数值,如果你不知道它们的存在,就有可能会坑到你,今天就让我们一起来看看js的各种极限数字。

基础知识

js中的数字是用双精度浮点数表示的,具体如下:

background Layer 1 ... ... 11位 52位数 1位 1位的是符号位 11位的是指数位,(需要移位1023,阶码范围1-2046,指数范围-1022到1023) 52位的是小数位 比如数字10,二进制为1010,浮点数表示为1.010*2^3 ....都是0..... 11位 52位数 1位 0 0 0 0 1 0 0 0 其中010存在小数位 2^3中的3+1023=1026,所以指数位为10000000010 0 1 0 0 1 0 0 比如数字8.25,二进制为1000.01,浮点数表示为1.00001*2^3 ....都是0..... 11位 52位数 1位 0 0 0 0 1 0 0 0 其中00001存在小数位 2^3中的3+1023=1026,所以指数位为10000000010 0 1 0 0 0 0 0 *小数的二进制为该数字*2的整数部分,到最终为1止 0 1 *.25*2=0.5取0 *.5*2=1取1 *恢复的时候*2^-n *这里就是0*2^-1+1*2^-2

如上所说,js浮点的一般表示为M*2^N,其中1<=M<2,如M=1.***,其中的***就存在52位小数位中;N+1023的二进制则是这11位的指数。

不过这里有些特殊情况。

background Layer 1 ... ... 11位 52位数 1位 当11位是0的时候,如果52位也是0,就表示正负0 当11位是2047的时候,如果52位也是0,就表示正负无穷大 当11位是2047的时候,如果52位不是0,则不是数字(NAN) 非规范浮点数 当11位是0的时候,如果52位不是0,52位前面跟的可以不是1

Number.MAX_SAFE_INTEGER

Number.MAX_SAFE_INTEGER是最大安全的数字,这是什么意思呢?根据刚才讲到的双精度浮点型我们可以看到,小数区表示的是1后面的二进制,指数区表示的是小数点需要向右移动几位。

我们注意到,指数区最大为2046-1023=1023,也就是说它最大可以向右移动1023次,而右边的小数区最多只有52位,那比如说,一个数字的二进制小数区有53位,那么它的最后一位肯定会被截掉,这样就会导致数字不准确。

因此,如果不想有数字被截掉,那么它的小数区的内容就不能大于52,因此,如果小数区内全为1,则是能保证不被截取的最大数字:

background Layer 1 1.1111111.....1111*2^52 52位 111111111.....11111 53位 最大值为2^53-1

因此Number.MAX_SAFE_INTEGER的值为2^53-1。

最喜欢迷惑人的一道关于Number.MAX_SAFE_INTEGER的题目如下:

大家猜测一下会输出几个ok?

其实这是一个死循环,因为Math.pow(2,53)==Math.pow(2,53)+1,只要这个数字加1了,1就会被砍掉,恢复成Math.pow(2,53),会导致Math.pow(2,53)+1+1==Math.pow(2,53)!=Math.pow(2,53)+2,很奇葩吧,因此要想获取确切的数字,这个数值一定不能大于Math.pow(2,53)-1。

22位数字问题

当一个数字大于或者等于22位的时候就会出现科学计数法,如1111111111111111111111,那么实际输出为1.1111111111111111e+21。

这样会导致一个什么问题呢?就是用parseInt方法去转换的时候,会变成1,parseInt(1111111111111111111111)==1。

同理,在小数位大于或者等于7位的时候,也会变成科学计数法,parseFloat(0.0000005)==5e-7。

Number.MAX_VALUE

这个是双精度浮点数可以表达的最大数值,数值为1.79*10^308,这个数值是怎么算出来的呢?

background Layer 1 ....都是1..... 11位 52位数 1位 0 1 1 1 1 1 1 1 1 1 1 0 1 1 1 我们逆着推,此时需要移动的位数为2046-1023=1023 还原后的表达式为: 1.1111...1111*2^1023 52位数 11111...111100000...00000 53位数 971位数 11111...1111111111111 11111...11111111 减去 1024位数 971位数 2^1024-1-(2^971-1) 2^971*(2^53-1) 11位最大为2046,如果为2047则是正无穷了。所以上面是可以显示的最大数值,那么是多少呢?

上面给出了推理过程,最后的结果是2^791*(2^53-1),超过这个数字,就无法表示了。

Number.MAX_VALUE和Infinite之间到底差多少?

其实很多人就纳闷了,既然Number.MAX_VALUE是最大可以表示的数字,那么是否Number.MAX_VALUE+1是否就等于Infinite了呢?

答案是否定的哈,虽然Number.MAX_VALUE是最大可以表示的数字不假,但是想让它到Infinite还是要有一段路要走的,那么它们之间到底差多少呢?

background Layer 1 ....都是1..... 11位 52位数 1位 0 1 1 1 1 1 1 1 1 1 1 0 1 1 1 js规定,只要数字大于上面那个数字的就可以视为Infinite 它和Number.MAX_VALUE的差别是: 11111...111100000...00000 53位数 971位数 1 11111...111110000...00000 54位数 970位数 Number.MAX_VALUE Infite Infite比Number.MAX_VALUE多了一个2^970 因此Number.MAX_VALUE+Math.pow(2,970)==Infinite

其实Infinite和Number.MAX_VALUE差了2^970那么多,当然了,因为这个范围的数值早就超过了Number.MAX_SAFE_INTEGER,因此,2^970附近有很多值都和2^970相同,所以不一定就是2^970才可以,2^970-100或者2^970-200都可以,这里我们只是算出了这个值而已,但不一定就是这个值。

Number.MIN_VALUE

注意,这是一个正值,一个无限接近0的数,其数值为5*10^-324,这个是咋出来的呢?

background Layer 1 ....都是0..... 11位 52位数 1位 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 正规的最小值 开始我们说过了,11位的范围是1-2046,当为1的时候,需要移动1-1023=-1022位 因此,最小的是 ......都是0..... 11位 52位数 1位 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 非正规的最小值 这里有个非正规情况,当11为0的时候,52位的前缀可以不是1,可以为0 因此,最小的值的二进制是: 1 0.00...0001*2^-1023 当11位为0的时候,需要移动0-1023=-1023位 51位 十精制内容为: 2^-51*2^-1023 2^-1074 1*2^-1022

这里需要注意上面的非正规浮点数表示法,因为我们之前讲过M=1.****,但是在非正规浮点数表示法里,M=0.*****,这是为了可以表示更小的数字。很明显,js采用的是下面非正规的值,因为它更小。

Number.EPSILON

这个数字是js中能够表现的最小误差值,如果小于这个数值,基本可以认为相等了。

我们试想在js中误差最小的相减是什么?

background Layer 1 ....都是1..... 11位 52位数 1位 0 0 0 0 1 0 0 0 1 0 0 0 1 1 1 数字1 ....都是1..... 11位 52位数 1位 0 0 0 0 1 0 0 0 1 0 0 0 1 1 1 数字2 0 数字1-数字2: 0.000....00001 数字1和数字2的1位和11位以及52位的前51位都是一样的,只有52位的最后一个不同。 51 之前我们说到小数的二进制还原成十进制的方法为:小数点后一位*2^-1+小数点后两位*2^-2.... 因此这个数的十进制为: 2^-52

最后

最后我将上面讲到的所有的极端数值统一梳理一遍,看看它们从前到后的顺序。

background Layer 1 -Infinite(Number.Negative_INFINITEY) Number.MIN_SAFE_INTEGER 0 Number.MIN_VALUE Infinite(Number.POSITIVE_INFINITEY) Number.MAX_VALUE Number.MAX_SAFE_INTEGER

其他文章

0
我要评论

评论

返回
×

我要评论

回复:

昵称:(昵称不超过20个字)

图片:

提交
还可以输入500个字