bigint操作数据时,如果使用BigInt()包住一个大于十六位的数字,例如BigInt(156454564564123435453456745645453),得到的结果却是156454564564123438394488632901632n,数字明显不一样了,但如果直接在数字后面加n,得到的结果又是一致的,这是为什么呢
bigint操作数据时,如果使用BigInt()包住一个大于十六位的数字,例如BigInt(156454564564123435453456745645453),得到的结果却是156454564564123438394488632901632n,数字明显不一样了,但如果直接在数字后面加n,得到的结果又是一致的,这是为什么呢
因为虽然看上去 156454564564123435453456745645453
是个 Number
,但是它的精度已经丢失了。JavaScript 能够准确表示的整数范围在-2^53到2^53之间(不含两个端点),
BigInt 是一种内置对象,它提供了一种方法来表示大于 2^53 - 1 的整数。这原本是 Javascript 中可以用 Number 表示的最大数字。BigInt 可以表示任意大的整数。
BigInt(156454564564123435453456745645453)
等价于BigInt(1.5645456456412344e+32)
加了 n 之后这个int就是 bigint
类型,无论多大精度都不会丢失
无论是什么语言,最终都是以机器码的形式运行的(不管是直接被转换为机器码,或者被转换为字节码在虚拟机这层抽象层上运行),所以我们就知道最终能执行什么样的操作受限于机器提供的指令集,以64位的cpu为例,一般它原生支持的数据类型就只有64位及以下的整数和64位及以下的浮点数,在javascript中为了减少对开发者的更多心智负担他几乎只有一种数据类型那就是64位的浮点数(其他语言中往往会根据数据的位数,数据是否表示为补码,是否为浮点数分出很多数据类型比如int, short, char, long, unsigned long, float, double等等,当然这不是一定的,如果为了优化javascript enging完全可以在运行时将其替换为其他更适合的类型)
如果你在控制台eval一下156454564564123435453456745645453
这个数字就会发现他的有效位刚好是17位而double(64位浮点数)的尾数部分又53位,如果以大约以3位二进制位表示一个十进制数位的话你就会发现 53 / 3 ≈ 17
所以这么大的数字是无法在当前计算机体系中原生支持的,而是只能用64位浮点数表达出他的近似值,除非用软件模拟,而向bigint这种软件模拟的数字就不会有这种影响,完全可以用一个很大的byte数组存储这个数字,并用软件模拟他的加减乘除.
一般精度丢失直接在语言进行静态编译的时候就会丢失,而不会等到运行的时候,比如就以你的例子为例,在编译器进行词法分析时156454564564123435453456745645453
会被转换为IntLiteral
,此时会将它转换为一个eval为一个64位浮点数并放入该词法单元的信息中在这里精度就已经丢失了,而156454564564123435453456745645453
会被转换为BigIntLiteral
它会被单独处理成软件模拟的数字
10 回答11.3k 阅读
5 回答4.9k 阅读✓ 已解决
4 回答3.2k 阅读✓ 已解决
2 回答2.8k 阅读✓ 已解决
3 回答2.4k 阅读✓ 已解决
3 回答2.2k 阅读✓ 已解决
2 回答2.7k 阅读✓ 已解决
用
BigInt()
来构造bigint
类型时,里面的参数应该尽量用字符串。当你在代码中使用
156454564564123435453456745645453
这个字面量的number
的时候,它在代码解析阶段就已经发生溢出
了。因此BigInt(156454564564123435453456745645453)
这段代码,实际是对一个已经发生溢出
的数字来构造bigint
,因此得到的结果也是一个已经溢出的数字。要避免这种情况发生,应该使用字符串作为参数,即
BigInt('156454564564123435453456745645453')