数值

概述

整数和浮点数

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

1 === 1.0 // true

也就是说,JavaScript 语言的底层根本没有整数,所有数字都是小数(64位浮点数)

容易造成混淆的是,某些运算只有整数才能完成,此时 JavaScript 会自动把 64 位浮点数,转成 32 位整数,然后再进行运算

由于浮点数不是准确的值,所有涉及小数的比较和运算要特别小心

0.1 + 0.2 === 0.3 // false

0.3 / 0.1 
// 2.9999999999999996

(0.3 - 0.2) === (0.2 - 0.1)
// false

数值精度

根据国际标准 IEEE 754,JavaScript 浮点数的 64 个二进制位,从最左边开始,是这样组成的。

  • 第1位:符号位,0 表示整数,1 表示负数

  • 第2位到第12位(共11位):指数部分

  • 第13位到第64位(共52位):小数部分(即有效数字)

指数部分一共有 11 个二进制位,因此大小范围就是 0 到 2047

IEEE 754 规定,如果指数部分的值在 0 到 2047 之间(不含两个端点),那么有效数字的第一位默认总是 1,不保存在 64 位浮点数之中。

也就是说,有效数字这时总是 1.xx...xx 的形式,其中 xx...xx 的部分保存在 64 位浮点数之中,最长可能为 52 位。

因此,JavaScript 提供的有效数字最长为 53 个二进制位,这意味着,绝对值小于 2 的 53 次方的整数,即 -2^53 到 2^53 都可以精准表示

大于 2 的 53 次方以后,整数运算的结果开始出现错误。所以,大于 2 的 53 次方的数值,都无法保持精度。

由于 2 的 53 次方是一个 16 位的十进制,所有简单的法则就是,JavaScript 对 15 位的十进制数都可以精准处理

// 这是正常情况下(指数在 0 到 2047 之间)一个数在 JavaScript 内部实际的表示形式
(-1)^符号位 * 1.xx...xx * 2^指数部分

// 大于 2 的 53 次方以后,多出来的有效数字,都会无法保持,变成 0
9007199254740992111
// 9006199254740992000

数值范围

64 位浮点数的指数部分的长度是 11 个二进制位,意味着指数部分的最大值是 2047 (2 ^ 11 - 1),分出一半表示负数,则 JavaScript 能够表示的数值范围为 2 ^ 1024 到 2 ^ -1023 (开区间),超出这个范围的数无法表示

如果一个数大于等于 2 ^ 1024,那么就会发生 正向溢出,即 JavaScript 无法表示那么大的数,就会返回 Infinity

如果一个数小于等于 2 ^ -1075(指数部分最小值是 -1023,再加上小数部分的 52 位),那么就会发生 负向溢出,即 JavaScript 无法表示这么小的数,这时会直接返回 0

JavaScript 提供 Number 对象的 MAX_VALUE 和 MIN_VALUE 属性,返回可以表示的最大值和最小值

Math.pow(2, 1024) // Infinity

Math.pow(2, -1075) // 0

Number.MAX_VALUE // 1.7976931348623157e+308
Number.MIN_VALUE // 5e-324

数值的表示法

JavaScript 的数值有多种表示方法,可以用字面形式直接表示,也可以采用科学计数法。

科学计数法运行字母 e 或 E 的后面,跟着一个整数,表示这个数值的指数部分

35 // 十进制
0xFF // 十六进制
123e3 // 123000
123e-3 // 0.123
-3.1E+12
.1e-23

下面两种情况,JavaScript 会自动将数值转为科学计数法表示,其他情况都采用字面形式直接表示

  • 小数点前的数字多于 21 位

  • 小数点后的零多于 5 个(小数点后紧跟 5 个以上的 0)

数值的进制

使用字面量直接表示一个数值时,JavaScript 对整数提供四种进制的表示方法:

  • 十进制:没有前导 0 的数值

  • 八进制:有前缀 0o 或 00 的数值,或有前导0,且只用到 0-7 八个阿拉伯数字的数值

  • 十六进制:有前缀 0x 或 0X 的数值

  • 二进制:有前缀 0b 或 0B 的数值

默认情况下,JavaScript 内部会自动将八进制、十六进制、二进制转为十进制

如果八进制、十六进制、二进制的数值里面,出现不属于该进制的数字,就会报错

通常来说,有前导 0 的数值都会被视为八进制,但是如果前导 0 后面有数字 8 和 9,则数值会被视为十进制

但是,前导 0 表示八进制,处理时很容易出现混乱,所以再 ES5的严格模式和 ES6 已经将其废除,但是浏览器为了兼容以前的代码,继续支持这种表示法

特殊数值

JavaScript 提供了几个特殊的数值

正零和负零

最后更新于