Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Day1 - JS 整数是怎么表示的? #3

Open
su37josephxia opened this issue Dec 21, 2021 · 19 comments
Open

Day1 - JS 整数是怎么表示的? #3

su37josephxia opened this issue Dec 21, 2021 · 19 comments

Comments

@su37josephxia
Copy link
Owner

su37josephxia commented Dec 21, 2021

@su37josephxia
Copy link
Owner Author

su37josephxia commented Dec 23, 2021

知识讲解

系统 + 全面

万能的Number

JavaScript 内部,所有数字都是以64位浮点数形式储存,即使整数也是如此。所以,1与1.0是相同的,是同一个数。

做一个实验

typeof 1 // number
typeof 1.0 // number
1 === 1.0

Number类型的表示范围

浮点数的结构

根据国际标准 IEEE 754,JavaScript 浮点数的64个二进制位。

image-20220101175727812

  • 第一部分(蓝色):用来存储符号位(sign),第1位:符号位,0表示正数,1表示负数
  • 第二部分(绿色):用来存储指数(exponent),第2位到第12位(共11位):指数部分
  • 第三部分(红色):用来存储小数(fraction),第13位到第64位(共52位):小数部分(即有效数字)

fraction决定了整数安全表示范围

也就是

(-1)^s * f * 2^e

  • 符号部分 -1 or 1

  • f的范围为1<=f<2 使用52位表示

  • 指数有正有负,指数位长度为11比特,所以能表示的数字范围为0~2047

所以很明显最大位应该由f决定,也就是说所有的52位用作表示整数部分。

52位为什么可以表示53位小数

因为小数部分只需要表示尾数就可以,整数部分可定等于一

52位太多不好理解,假设我们以3位(bit)数

0.10 (二进制) 可以表示为 1.00 * 2^-1

0.01 (二进制) 可以表示为 1.00 * 2^-2

这样的话由于整数部分一定等于1,所以可以把整数部分省略。

也就是说3位数可以表示做小数表示的时候可以表示4位小数

为什么不是指数部分决定的

0.1123 * 2^1024

当然这里面有人会问为什么不是指数部分决定呢。上面这个数的范围是不是比我们的讨论的数据范围更大呢。

其实并不是这样,因为实用指数表示并不能表示连续的数字。所以这个方案不可取。

整数的表示范围

Math.pow(2,53)  - 1 // 最大 
Number.MAX_SAFE_INTEGER // 常数表示
- (Math.pow(2,53)  - 1) // 最大 
Number.MIN_SAFE_INTEGER // 常数表示

面试攻略

精炼 + 系统 + 自洽

  • 基本概念:JavaScript 内部,所有数字都是以64位浮点数形式储存。
  • 整数表示范围不用直接分析

点评

  • 这道题属于基本概念题,但是如何用二进制表示浮点数很容易能够看出来,逻辑非常复杂。很容易看出应聘这的基本功,和理性思维能力。
    • 初级: 知道Number
    • 中级: 说出表示范围推导过程
    • 高级: 推导过程分析合理且可以和其他语言对比。

@BambooSword
Copy link

BambooSword commented Dec 23, 2021

有了第一题的回答,大家都明白 IEEE 754 中规定有 11位的指数位,52位的小数位。
所以如何让这52位小数位变成整数是关键。
我们知道在10进制中如果想把n位小数变成整数就乘 10^n, 所以在二进制也是一样,当11位的指数位表示的数值为52时,我们就可以表示成整数了。
可能有些小伙伴会问,如果是这样为啥最大的安全整数不是2^52 -1 吗,为什么是2^53-1呢?
因为在科学计数法的尾数部分是大于1的,我们肯定不能以0为尾数部分的开头,所以这个尾部的1是被省略掉的。我们的52位是小数位,所以最大的安全整数时2^53-1而不是2^52-1.
但是还有一个问题没有被解决,就是既然科学计数法中的尾部1是被默认设置了的。我们就没有指数位为52是我们没办法表示0.
关于0,IEEE 754有专门的规定,规定指数位为0,小数位为0,则表示为0.而JS表示的浮点数有sign位,所以这就解释了JS中有两种0的表示方式。
以上就是关于JS整数是如何表示的简单解释。

PS:我昨天向群里的小伙伴安利了我之前写的文章,由于当时没玩掘金,所以只是写完后复制到掘金上,今天发现有很多排版问题,同时也有些知识点不明确和错误的地方,我又进行了重新排版,感兴趣的可以去看看,欢迎留言讨论https://juejin.cn/post/6844903581993140237

@chunhuigao
Copy link

在JavaScript中数字为双精度浮点类型遵循 IEEE754 标准
介于±2^−1023和±2^+1024之间的数字,或约为±10−308到±10+308,数字精度为53位。整数数值仅在±(2^53 - 1)的范围内可以表示准确

默认十进制数,数字添加0b表示二进制数,0开头且所有数字小于8表示表示八进制数;0x开始表示16进制数

这就是我理解的JavaScript整数表示方法

扩展

什么是双精度浮点型?
浮点型可以理解为【科学计数法】,双精度是相对于单精度,单精度完全保证的有效数字最高位是7位,双精度完全保证的有效数字最高是15位;有啥区别呢?双精度提供了更高的数值精度;

@bianzheCN
Copy link

bianzheCN commented Dec 23, 2021

参考

https://javascript.ruanyifeng.com/grammar/number.html#toc1

答案

(考察 JS 怎么表示数字)。

在 JavaScript 内部,所有数字都是以 64 位浮点数存储,从左边开始:
1 位符号位:0 正数,1 负数,
11 位表示指数(0 到 2047),
52 位表示小数(有效数字)。

由于有效数字第 1 位总是 1,不保存在浮点数里,所以 JS 提供的有效数字最长为 53 个二进制位。
因此只有绝对值小于 2 的 53 次方 (Math.pow(2, 53) - 1)的数字才能精确表示。

@rachern
Copy link

rachern commented Dec 23, 2021

JS整数是使用Number类型来表示的,Number类型使用IEEE 754格式表示整数和浮点数
整数一般用十进制表示,也可以用八进制或十六进制字面量表示
对于八进制字面量,第一个数字必须是0,然后是相应的八进制数字
要创建十六进制字面量,必须让真正的数值前缀 0x(区分大小写),然后是十六进制数字

JS遵循 IEEE 754规范,采用双精度存储,占用64bit
1 位用来表示符号位
11 位用来表示指数
52 位表示尾数
尾数位最大是 52 位,因此 js 中能精准表示的最大整数是 Math.pow(2, 53)

@MMmaXingXing
Copy link

一般来说64位整形数字的最大安全值范围是2^63-1,JS中的数字类型,实际上是通过8字节double浮点型表示的,浮点数并不能够精确表示范围内的所有数字,正常的浮点数类型遵循IEEE754规范,按照浮点数的运行规范,1位符号位,11位指数位,剩下的是52位数字位,因此js中的数字类型的表示最大安全范围是2^53 - 1 位数。

可以使用 Number.MAX_SAFE_INTEGER来表示 即
Math.pow(2, 53) - 1

@jiafei-cat
Copy link

jiafei-cat commented Dec 23, 2021

JS如何表示整数

首先在js中使用number数据类型表示整数 (64位存储 8 字节)


js number类型是遵循IEEE754标准的64位双精度浮点数。
标准中指明1位符号位11位指数位52位尾数, 取值范围取决于指数位,计算精度取决于尾数
所以最大数为2 ^ 1024 - 1(2^11 = 2048, +-指数/2 = 1024), 最大安全数为2^53-1

  • 那么这里为什么需要减一而且不是52呢?
  • IEEE754规定,在计算机内部保存有效数字时,默认第一位总是1, 所以舍去,只保留后面的部分。比如保存1.01,只存01,等读取的时候再把第一位1加上去。所以52位有效数字实际可以存储53位。
  • 那么为什么超过最大安全数计算就不再准确了?
  • 在安全数范围中,双精度数和整数一一对应, 也就是说, 整数都有唯一的浮点数表示, 但是象2^53+1和2^53存储一样,这样就不再一一对应。
  • 为什么超过最大安全数的两个数会存储的一样呢?
  • 因为在指数位是53的情况下,尾数在乘以2的53次幂后, 相当于小数点向后移动了53位。此时, 小数点不是在尾数最后一位的后面, 而是在其后面的后面, 所以它们存储的一样

@jj56313751
Copy link

jj56313751 commented Dec 23, 2021

js的底层根本没有整数,都是用二进制64位浮点数表示
根据国际标准IEEE754,64位二进制从左开始

  • 第1位:符号位,0正数,1负数
  • 第2位到12位(11位):指数部分,0-2047,正负各一半,因此数值范围在2^-1023~2^1024
  • 第13位到第64位(52位):小数部分,控制精度,有效数字第一位总是1,只保留后面的小数位,因此有53个二进制位有效数,-2^53~2^53范围内的数都可以精确表示

@xyz-fish
Copy link

xyz-fish commented Dec 23, 2021

JS整数是怎么表示的

通过Number类型表示

JS Number 类型是双精度的IEEE754 64位浮点类型

1位是符号位

11位是指数位

52位是尾数位

IEEE754规定有效数字第一位总是1,也即是说有效数字总是1.xxx的形式.xxxx是52位尾数位

所以js中有效的数字是52个二进制位 所以我们的安全数值田-Math.pow(2, 53) - 1 到 Math.pow(2, 53) - 1

在我们代码中表示整数方式:

  • 字面量 常见的十进制,
  • 0开始的8进制(0-7)
  • 0x开始的16进制(0-9A-F)
  • 2进制 0b开头 ,

但转化或运算后都已十进制显示

表达方式

  • 还有可以通过new Number的形式
  • 还有一些 parseInt(), Math.floor()的等等一些方法

一些较大的值或转成科学计数法的方式:e前面的数值乘以10的指数幂

@liangle
Copy link

liangle commented Dec 23, 2021

在JS里我们用 Number 来表示整数,Number,Double Float,浮点数是采用科学计数法来表示的,由符号位、有效位数、指数位三部分组成

有效位数决定了这个数的精度,指数位表示浮点数表示的范围,这里的位是指二进制,0或1表示,浮点数可以表示很大的数,在表示最大数的时候,可能不是每个整数都能表示了,数越大能表示的数就越稀疏

双精度浮点数是64位组成:
符号位1位:不参与计算的,0表示正数1表示负数
指数位11位:有个基准值,10000000000
有效位数52位:有效数字隐藏了个1,因为以0开头没有意义
数字 = 符号位 + 精度位*2^指数次方

@yaoqq632319345
Copy link

在 JS中,所有数字都是以 双精度64 位浮点数存储,
其中包括1位符号位,11位指数位,52位小数位,
用来控制精度的是52位小数位,浮点数在内存中是按科学计数法来存储的,其整数部分始终是一个隐含着的1
所以JS中可以明确表示精度的数字范围在正负2的53次方,而不是52次方

@zhenyuWang
Copy link

zhenyuWang commented Dec 23, 2021

JavaScript 中使用 Number 类型表示整数,而且遵循 IEEE 754 格式。

Number 类型

JavaScriptNumber 类型使用 IEEE 754 格式表示整数和浮点值。

IEEE 754 中双精度浮点数使用 64 bit 来进行存储:
第一位存储符号表示正负号 0 正 1 负
2-12位存储指数表示次方数
13-64位存储尾数表示精确度

浮点数在计算机中的存储方式:
浮点数会被转成对应的二进制数,并用科学计数法表示,
然后把这个数值通过 IEEE 754 标准表示成真正会在计算机中存储的值。

扩展

因为内存的限制,Number 类型并不能表示这个世界上的所有数值,当然也包括所有整数。
JavaScript 中所能表示的最大安全整数 Math.pow(2, 53)-1,最小安全整数为 -Math.pow(2, 53)-1
为什么最大安全整数是 Math.pow(2, 53)-1 呢?

  1. 首先解释位数的问题,因为 IEEE 754 规定尾数第一位隐含为1,不写,所以虽然尾数有52位,但是可以表达53位数。
  2. 关于安全,安全 的意思是说能够one-by-one表示的整数,也就是说在(-2^53, 2^53)范围内,双精度数表示和整数是一对一的,反过来说,在这个范围以内,所有的整数都有唯一的浮点数表示,这叫做安全整数。

那为什么要 -1 呢?
是因为安全的意思是整数和浮点数一一对应,而
2^53-1是这样存的:
符号位:0 指数:52 尾数:1.111111....111 (小数点后一共52个1)
2^53是这样存的:
符号位:0 指数:53 尾数:1.000000...000 (小数点后一共52个0)
2^53+1是这样存的:
符号位:0 指数:53 尾数:1.000000...000 (小数点后一共52个0)
可以看到因为 2^53 已经是 64 bit 双精度浮点数可以表示的最大值了, 2^53 与 2^53+1 转成 64 bit 双精度浮点数后的结果是相同的,此时发生了精度丢失,所以 2^53 不是安全整数。

JavaScript 中如果数值超出了可以表示的范围会怎样呢?

如果计算得到的值超出了 JavaScript 可以表示的范围,那么这个数值会被自动转换为一个特殊的 Infinity(无穷)值。任何无法表示的负数以 -Infinity (负无穷大)表示,任何无法表示的正数以 Infinity(正无穷大)表示。

要确定一个值是不是有限大(即介于 JavaScript 能表示的最小值和最大值之间),可以使用 isFinite() 函数,如下所示:

const result = Number.MAX_VALUE+Number.MAX_VALUE;
console.log(isFinite(result); // false

@zcma11
Copy link

zcma11 commented Dec 23, 2021

js中整数用Number类型表示,然后存为双精度浮点数,1位符号位表示正负,11位指数位表示范围,52位有效数字表示精度。因为有效数字只有52位,所以超过了52位就会表示不准确。然后就出现了安全整数的概念,就是在-2的53次方到2的53次方之间,每一个整数都有唯一一个浮点数和它一一对应。在这个区间之外则无法保证。也就无法保证准确性了。之所以是53次方是因为根据规范默认有效数字开头是1,然后把腾出了一个空间多记了一个数,所以是2的53次方。

+0 和 -0 是因为符号位占了一位,所以其他为0时就出现了+0和-0。

@bianxuerui
Copy link

在 Javascript 中数字只有一种类型,即双精度,64 位二进制,符合 IEEE754 格式的值。
所有的数字都是用 64 位来表示,
其中 1 位是符号位,11 位是指数位,52 位表示小数位就是有效的数字
因为有效数字的默认第 1 位终是 1 那么就不用浪费 1 位去保存它了,只需要在执行数学运算的时候,把这个 1 补回来即可;
所以 js 提供的有效数字位是 53 个二进制位,
最后绝对值小于 2 的 53 次方的整数就能被精准的表示。

@Limeijuan
Copy link

  • js中的Number 类型按 IEEE 754(浮点数运算标准) 来表示整 数和浮点值(双精度值)。

  • 双精度二进制小数,使用64个比特位存储。

  • 1位,S(符号位),0表示正,1表示负;

  • 11位,E(指数)

  • 52位,M(小数位),任意有效数字

  • JS 中能精准表示的最大整数是 Math.pow(2, 53),十进制即 9007199254740992。

  • 双精度浮点数有效数字16位

  • 最基本的数值字面量格式是十进制整数,除了十进制,整数也可以用八进制(以 8 为基数)或十六进制(以 16 为基数)字面量表示。

  • 使用八进制(前缀0o)和十六进制(前缀0x)格式创建的数值在所有数学操作中都被视为十进制数值

  • 因为存储浮点值使用的内存空间是存储整数值的两倍,所以 ECMAScript 总是想方设法把值转换为 整数。在小数点后面没有数字的情况下,数值就会变成整数。

1 similar comment
@Limeijuan
Copy link

  • js中的Number 类型按 IEEE 754(浮点数运算标准) 来表示整 数和浮点值(双精度值)。

  • 双精度二进制小数,使用64个比特位存储。

  • 1位,S(符号位),0表示正,1表示负;

  • 11位,E(指数)

  • 52位,M(小数位),任意有效数字

  • JS 中能精准表示的最大整数是 Math.pow(2, 53),十进制即 9007199254740992。

  • 双精度浮点数有效数字16位

  • 最基本的数值字面量格式是十进制整数,除了十进制,整数也可以用八进制(以 8 为基数)或十六进制(以 16 为基数)字面量表示。

  • 使用八进制(前缀0o)和十六进制(前缀0x)格式创建的数值在所有数学操作中都被视为十进制数值

  • 因为存储浮点值使用的内存空间是存储整数值的两倍,所以 ECMAScript 总是想方设法把值转换为 整数。在小数点后面没有数字的情况下,数值就会变成整数。

@JanusJiang1
Copy link

在js中 通过 Number 类型来表示整数,以双精浮点数的方式在计算机中储存和运算,遵循 IEEE754 标准,它通过 64 位来表示一个数字。

  • 1位,S(符号位),0表示正,1表示负;
  • 11位,E(指数)数字的指数
  • 52位,M(小数位),任意有效数字
    因为有效数字的默认第 1 位终是 1 那么就不用浪费 1 位去保存它了,所以实际有效数字位是 53 位

所以,js十进制表示的最大安全数字是 Math.pow(2, 53) - 1 。

@crazyyoung1020
Copy link

crazyyoung1020 commented Dec 23, 2021

首先,得知道,js是使用IEEE 754格式的双精度浮点数。1bit表示符号位,11bit表示指数位,52bit表示尾数位。

  • 符号位,0表示整数,1表示负数。
  • 指数位,由于有11位,可以表示0~2^11-1的指数即0~2047,由于指数有正负,偏移一个1024,即得-1024~1023,这里规定去掉0和2047两个边界值不予使用,那么少两个数,偏移量也少1,即表示的指数范围为-1023~1022。
  • 尾数位,由于科学计数法都为1开头,那么1可以默认不存储,则52bit其实可以表示长度为53位的二进制科学计数的系数。

讲到这里,js可表示最大数,应为1.1111---111*2^1022(小数点后52个1),是一个很大的数,但是尾数精度实际只有52,超出的部分都丢失掉了,所以最大的整数应该是1.111---111*2^52(小数点后52个1),这样可以保证数的每一位都有记录下来,答案就是2^53-1。

@rhythm022
Copy link

JS中的Number类型其实就是双精度浮点数,它是按IEEE754标准实现的,在这个标准中是用科学计数法来表示一个数的。

那么具体而言的话,双精度浮点数,它其中的一位是用来表示这个数正负的,11位是用来表示科学计数法中的指数,用52位来表示科学计数法中的有效数字。

因此的话,在JS中安全的最大整数就是Math.pow(2, 53)-1,这是因为有效数字有效数位是53位。

Ps: 最小安全整数为 -Math.pow(2, 53)-1

@su37josephxia su37josephxia changed the title JS 整数是怎么表示的? Day1 - JS 整数是怎么表示的? Jan 20, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests