本身整理、设计的,转载请注明原帖。先从这个demo看起:http://alvarto.github.io/Visu...javascript
关于Number.MAX_VALUE
和Number.MIN_VALUE
:这个结果为了好看被我四舍五入了……html
关于±0:紫云飞:JavaScript中的两个0java
关于数组的最大索引:紫云飞:JavaScript:数组能越界?git
关于JavaScript能够精确表示到个位的最大整数:阮一峰:JavaScript数值github
参考国际标准IEEE 754,我画了一张图帮助理解:segmentfault
注,这里的字符是从左到右排的,和wiki之类的资料顺序相反。wiki资料考虑的是比较的顺序(符号-指数位-有效数字),而我这里考虑到的是阅读顺序(从0到63位,从左到右)。数组
中间的指数位是如何同时表示正负指数值的呢,和“符号位+有效数字位”的常规表示方法不一样,指数是使用偏移法来作的:编码
IEEE 754:指数偏移值spa
指数偏移值(exponent bias),是指浮点数表示法中的指数域的编码值为指数的实际值加上某个固定的值,IEEE 754标准规定该固定值为2^(e-1)-1
,其中的e为存储指数的比特的长度。
以单精度浮点数为例,它的指数域是8个比特,固定偏移值是28-1 - 1 = 128−1 = 127.单精度浮点数的指数部分实际取值是从128到-127。例如指数实际值为1710,在单精度浮点数中的指数域编码值为14410,即14410 = 1710 + 12710.
采用指数的实际值加上固定的偏移值的办法表示浮点数的指数,好处是能够用长度为e个比特的无符号整数来表示全部的指数取值,这使得两个浮点数的指数大小的比较更为容易。设计
所以,在JavaScript里面的指数位,是从1-2^(11-1),也就是从-1023开始,表示了(-1023,1024)这个区间。
实际指数值 | 存储的指数值 |
-1022 | 1 |
0 | 1023 |
1023 | 2046 |
Number保留了指数值0和2047用于表示一些特殊的值。总的表示表格以下:
X | Y | 表示的值 |
=0 | =0 | ±0 |
≠0 | =2047 | NaN |
=0 | =2047 | ±Infinity |
≠0 | =0 | 反规格化值(Denormalized):f(0.x , 1 , z) |
∈(0,2047) | 规格化值(Normalized):f(1.x , y , z) | |
<h3>f(i,j,k) = (-1)k · 2-1023+j · i</h3> |
前52位能表示的最大值是下面这个(下面是52位+1位默认的1):
parseInt("11111111111111111111111111111111111111111111111111111",2) -> 9007199254740991 //即2^53-1
而下一个值是:
parseInt("100000000000000000000000000000000000000000000000000000",2) -> 9007199254740992 //即2^53
根据内存模型,画一张图就能够知道:
从第2^53位开始,第一个进制被舍弃,这个时候,2^53+1==2^53,每两个值都会有一个值出现这种不精确的情形。再过N个值,会出现每4个值里面都有3个值不精确;再过M个值,会出现每2^K个值里有2^K-1个值不精确;以此类推……(小题目:这个N值是多少?)
验证:
Number.MAX_VALUE.toString(2) -> "1111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" var a = Number.MAX_VALUE.toString(2).split("") , b = [ a.filter(function(i){return i==0}).length , a.filter(function(i){return i==1}).length ] ; b -> [971, 53] Number.MAX_VALUE === (Math.pow(2,53)-1)*Math.pow(2,971) -> true
QED
还记得前面的表格吗:
X | Y | 表示的值 |
≠0 | =0 | 反规格化值(Denormalized):f(0.x , 1 , z) |
∈(0,2047) | 规格化值(Normalized):f(1.x , y , z) | |
<h3>f(i,j,k) = (-1)k · 2-1023+j · i</h3> |
非规格化值是这样表示的:
最小正数的内存模型
验证:
Number.MIN_VALUE.toString(2) -> "0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001" var a = Number.MIN_VALUE.toString(2).split(""); a.filter(function(i){return i==0}).length - 1 -> 1073 Number.MIN_VALUE === Math.pow(2,-1074) -> true
除了IEEE 754的维基页面,还有这篇文章,解释的很是清晰:"How numbers are encoded in JavaScript"
最后再推一次:输入表达式,返回对应Number值的内存模型的DEMO
http://alvarto.github.io/Visu...