资讯专栏INFORMATION COLUMN

图解:JavaScript中Number的一些表示上/下限

SillyMonkey / 1940人阅读

摘要:例如指数实际值为,在单精度浮点数中的指数域编码值为,即采用指数的实际值加上固定的偏移值的办法表示浮点数的指数,好处是可以用长度为个比特的无符号整数来表示所有的指数取值,这使得两个浮点数的指数大小的比较更为容易。

自己整理、设计的,转载请注明原帖。先从这个demo看起:http://alvarto.github.io/Visu...

数轴

说明

关于Number.MAX_VALUENumber.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

相关文章

  • 由setTimeout和setImmediate执行顺序随机性窥探Node事件循环机制

    摘要:问题引入接触过事件循环的同学大都会纠结一个点,就是在中和执行顺序的随机性。当队列被执行完,或者执行的回调数量达到上限后,事件循环才会进入下一个阶段。嵌套的在下一个事件循环的阶段执行回调输出嵌套的。 问题引入 接触过事件循环的同学大都会纠结一个点,就是在Node中setTimeout和setImmediate执行顺序的随机性。 比如说下面这段代码: setTimeout(() => { ...

    marek 评论0 收藏0
  • 【算法】计数排序 + 各个排序算法稳定性

    摘要:将大的先放在后面,再下一次可以把相同大的放在上一次的之前,顺序改变。 之前介绍的排序算法: 【算法】插入排序——希尔排序+直接插入排序_Rinne’s blog-C...

    不知名网友 评论0 收藏0
  • 算法分析 - Algorithms, Part I, week 1 ANALYSIS OF ALGO

    摘要:实际上这个情形中存在幂定律实际上绝大多数的计算机算法的运行时间满足幂定律。基于研究得知,原则上我们能够获得算法,程序或者操作的性能的精确数学模型。 前言 上一篇:并查集下一篇:栈和队列 在算法性能上我们常常面临的挑战是我们的程序能否求解实际中的大型输入:--为什么程序运行的慢?--为什么程序耗尽了内存? 没有理解算法的性能特征会导致客户端的性能很差,为了避免这种情况的出线,需要具备算法...

    Leo_chen 评论0 收藏0
  • 图解javascript原型&原型链

    我们在学习javascript时,经常会听到万物皆对象,但是呢,其实万物皆对象的对象也有区别。分为普通对象和函数对象。1.对象分为函数对象和普通对象    通过new Function()创建的对象都是函数对象,其他的都是普通对象。showImg(https://segmentfault.com/img/bVbtWre?w=526&h=252); 2.构造函数而提到new关键字,我们不得不提到构造...

    sutaking 评论0 收藏0
  • HTML5 新特性

    一、HTML5与HTML4 1.1 推出的理由和目标 H5的出现,对于Web来说意义重大。因为他的意图是想要把目前Web上存在的各种问题一并解决掉。 Web浏览器之间的兼容性很低 文档结构不够明确(增加了很多结构, 语义化的标签) Web应用程序的功能受到了限制 H5 的出现极大的解决了上面的问题 1.2 语法的改变 1.2.1 DOCTYPE声明 H5 DOCTYPE的声明是这样的: ...

    王伟廷 评论0 收藏0

发表评论

0条评论

SillyMonkey

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<