0%

JS Number类型的范围

之前踩到的一个坑。

js 中,不区分 int float 等等,只有一个 Number 类型。占 64 位(8 字节)。

数字类型采用 64 位浮点格式表示,我们可以利用 Number 对象的属性 Number.MAX_VALUE , Number.MIN_VALUE 来查看;JavaScript 中 Number 范围为正负 2 的 53 次方,也即从最小值-9007199254740992 到最大值+9007199254740992 之间的范围。−9007199254740992 and 9007199254740992 (即正负 2 的 53 次方)
image-20200302172949558

JavaScript 里的数字是采用 IEEE 754 标准的 64 位双精度浮点数。该规范定义了浮点数的格式,对于 64 位的浮点数在内存中的表示,最高的 1 位是符号位,接着的 11 位是指数,剩下的 52 位为有效数字,具体:

第 0 位:符号位, s 表示 ,0 表示正数,1 表示负数;
第 1 位到第 11 位:储存指数部分, e 表示 ;
第 12 位到第 63 位:储存小数部分(即有效数字),f 表示,
符号位决定了一个数的正负,指数部分决定了数值的大小,小数部分决定了数值的精度。 IEEE 754 规定,有效数字第一位默认总是 1,不保存在 64 位浮点数之中。也就是说,有效数字总是 1.xx…xx 的形式,其中 xx..xx 的部分保存在 64 位浮点数之中,最长可能为 52 位。因此,JavaScript 提供的有效数字最长为 53 个二进制位(64 位浮点的后 52 位+有效数字第一位的 1)。

即:由于有 11 位的指数位,可以表示很大的数值,但是超过 53 位大数的精度无法保证。

这样的规则会带来一些问题,比如浮点数的精度问题和大数问题。

浮点数精度问题

1
2
3
const float1 = 7.9;
const float2 = 0.8;
console.log(float1 - float2); //7.1000000000000005

发生的原因:
首先,十进制的 7.9 和 0.8 都会被转换成二进制,但由于浮点数用二进制表达时是无穷的。标准的 64 位双精度浮点数的小数部分最多支持 53 位二进制位,所以浮点数小数位的限制而截断的二进制数字,进行运算后,再转换为十进制,就会产生误差。
这种问题根本原因是在于:计算机都是 0 或 1 标识,对于某浮点准确值,是通过不断增加位数去逼近该值。浮点数实现这种方式就是移位运算,所以不管是在表示还是运算时,都会出现误差。
如何解决:
1 简单的方法使用 toFixed
parseFloat((数学表达式).toFixed(digits)); // toFixed() 精度参数须在 0 与 20 之间
// 运行

大数问题

1
aa=68406452651714150433  //显示出aa=68406452651714150000

js 的 number 类型有个最大值(安全值)。即 2 的 53 次方,为 9007199254740992。如果超过这个值,那么 js 会出现不精确的问题。这个值为 16 位。

如果再大一些,达到指数位也无法显示这么大的数,就会变成 infinity(由于符号标志位是单独的,所以区分正负)


网上找的说法:

JavaScript 能表示并进行精确算术运算的整数范围为:正负 2 的 53 次方,也即从最小值-9007199254740992 到最大值+9007199254740992 之间的范围;对于超过这个范围的整数,JavaScript 依旧可以进行运算,但却不保证运算结果的精度。值得注意的是,对于整数的位运算(比如移位等操作),JavaScript 仅支持 32 位整型数,也即从-2147483648 到+2147483647 之间的整数。