摘要:例如指数实际值为,在单精度浮点数中的指数域编码值为,即采用指数的实际值加上固定的偏移值的办法表示浮点数的指数,好处是可以用长度为个比特的无符号整数来表示所有的指数取值,这使得两个浮点数的指数大小的比较更为容易。
自己整理、设计的,转载请注明原帖。先从这个demo看起:http://alvarto.github.io/Visu...
数轴 说明关于Number.MAX_VALUE和Number.MIN_VALUE:这个结果为了好看被我四舍五入了……
关于±0:紫云飞:JavaScript中的两个0
关于数组的最大索引:紫云飞:JavaScript:数组能越界?
关于JavaScript可以精确表示到个位的最大整数:阮一峰:JavaScript数值
关于Number表示的内存模型参考国际标准IEEE 754,我画了一张图帮助理解:
注,这里的字符是从左到右排的,和wiki之类的资料顺序相反。wiki资料考虑的是比较的顺序(符号-指数位-有效数字),而我这里考虑到的是阅读顺序(从0到63位,从左到右)。
中间的指数位是如何同时表示正负指数值的呢,和“符号位+有效数字位”的常规表示方法不同,指数是使用偏移法来做的:
IEEE 754:指数偏移值
指数偏移值(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) | |
f(i,j,k) = (-1)k · 2-1023+j · i |
前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) | |
f(i,j,k) = (-1)k · 2-1023+j · i |
非规格化值是这样表示的:
最小正数的内存模型
验证:
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...
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/87479.html
摘要:问题引入接触过事件循环的同学大都会纠结一个点,就是在中和执行顺序的随机性。当队列被执行完,或者执行的回调数量达到上限后,事件循环才会进入下一个阶段。嵌套的在下一个事件循环的阶段执行回调输出嵌套的。 问题引入 接触过事件循环的同学大都会纠结一个点,就是在Node中setTimeout和setImmediate执行顺序的随机性。 比如说下面这段代码: setTimeout(() => { ...
摘要:将大的先放在后面,再下一次可以把相同大的放在上一次的之前,顺序改变。 之前介绍的排序算法: 【算法】插入排序——希尔排序+直接插入排序_Rinne’s blog-C...
摘要:实际上这个情形中存在幂定律实际上绝大多数的计算机算法的运行时间满足幂定律。基于研究得知,原则上我们能够获得算法,程序或者操作的性能的精确数学模型。 前言 上一篇:并查集下一篇:栈和队列 在算法性能上我们常常面临的挑战是我们的程序能否求解实际中的大型输入:--为什么程序运行的慢?--为什么程序耗尽了内存? 没有理解算法的性能特征会导致客户端的性能很差,为了避免这种情况的出线,需要具备算法...
我们在学习javascript时,经常会听到万物皆对象,但是呢,其实万物皆对象的对象也有区别。分为普通对象和函数对象。1.对象分为函数对象和普通对象 通过new Function()创建的对象都是函数对象,其他的都是普通对象。showImg(https://segmentfault.com/img/bVbtWre?w=526&h=252); 2.构造函数而提到new关键字,我们不得不提到构造...
阅读 1851·2019-08-29 16:44
阅读 2154·2019-08-29 16:30
阅读 765·2019-08-29 15:12
阅读 3508·2019-08-26 10:48
阅读 2645·2019-08-23 18:33
阅读 3759·2019-08-23 17:01
阅读 1918·2019-08-23 15:54
阅读 1285·2019-08-23 15:05