99999999999999999999 === 100000000000000000000?

2020-02-21 00:26:16 +08:00
 jason19659

99999999999999999999 === 100000000000000000000

true

谁能解释下

5029 次点击
所在节点    程序员
22 条回复
cmdOptionKana
2020-02-21 00:33:56 +08:00
一个提示:Javascript 没有整数,只有浮点数
huihuimoe
2020-02-21 00:45:18 +08:00
@cmdOptionKana 有整数的,现在 bigint 已经在浏览器普及了。
只要在数字后加个 n 就可以
譬如 99999999999999999999n === 100000000000000000000n
> false
huihuimoe
2020-02-21 00:48:36 +08:00
至于楼主说的这个问题是编程经典问题,详细的内容可以搜索下 0.1+0.2 问题
https://medium.com/better-programming/99432310d476
Tink
2020-02-21 00:57:29 +08:00
老问题了,搜一下
luob
2020-02-21 01:06:54 +08:00
浮点数判断大小宜用减法
cmdOptionKana
2020-02-21 01:08:30 +08:00
@huihuimoe 这种整数其实是个 object 了,不是基础数据类型,比如这种整数用于 JSON.stringify() 是会报错的。
azh7138m
2020-02-21 01:14:09 +08:00
@cmdOptionKana 不是
它的类型就是 BigInt
报错是标准要求
https://tc39.es/proposal-bigint/#sec-serializejsonproperty
azh7138m
2020-02-21 01:18:29 +08:00
v8 用的 double 来存储 number
数字已经过了 MAX_SAFE_INTEGER
那其实就是楼上说的,这其实是个浮点数的比较(
huihuimoe
2020-02-21 01:44:44 +08:00
typeof 99999999999999999999 === typeof 0.1
> true
lxk11153
2020-02-21 02:04:10 +08:00
1. ECMAScript 将数字标准化为 64 位浮点值,也称为双精度浮点或 Float64。但是,这并不意味着 JavaScript 引擎总是以 Float64 的形式存储数字 —— 这么做会很低效。引擎会选择其它的内部表现形式,除非观测到的行为完全匹配 Float64。see: https://zhuanlan.zhihu.com/p/85836269

2. https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER

3. 0.1 +0.2===0.30000000000000004
https://segmentfault.com/a/1190000011902474
beginor
2020-02-21 03:18:19 +08:00
搭车问一下,如果 json 中包含这些数字该怎么处理比较好?除了转成字符串
tsohgdivil
2020-02-21 03:49:08 +08:00
Mutoo
2020-02-21 05:51:38 +08:00
kerr92
2020-02-21 07:51:48 +08:00
超出 [Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER],也就是 [-9007199254740991, 9007199254740991] 区间的数值,请用字符串或者 BigInt 表示。
lxk11153
2020-02-21 09:10:57 +08:00
@tsohgdivil #12 https://github.com/BonsaiDen/JavaScript-Garden
A collection of documentation about the most quirky parts of the JavaScript language.
ps: 里面的一些已在 es6 里改进,比如 for-of, let 等。see https://es6.ruanyifeng.com/
qiutianaimeili
2020-02-21 09:51:58 +08:00
mokevip
2020-02-21 10:00:20 +08:00
@tsohgdivil 当表情包收了(滑稽)
xiangyuecn
2020-02-21 10:04:31 +08:00
Number.MAX_SAFE_INTEGER=9007199254740991,这是 js 最大能精确表达的整数,你的那 n 个 9 的已经溢出了,js 不能准确表达这种大整数。据说现在有 BigInt,但是没用过。

ps:这个跟浮点数 0.1+0.2 这个问题没有一毛钱关系
drydiy
2020-02-21 10:21:25 +08:00
首先,目前 js 的数字类型有两种:Number、BigInt。其中 bigint 是后面加 n,不讨论,可以看下相关知识。
number 类型都是双精度浮点型。
1、2^53 - 1
双精度浮点数能保存最大的“安全整数” 2^53 - 1,9007199254740991 为以下:
parseInt("11111111111111111111111111111111111111111111111111111",2) // 9007199254740991
双精度浮点数二进制存储形式:
sign 位 exponent 位 franction 位 52 位 隐藏位 1
0 10000110011 11111111111111111111111111111111111111111111111111111 1
2、2^53
当存储 9007199254740992(2^53) 为:
parseInt("100000000000000000000000000000000000000000000000000000",2)
双精度浮点数二进制存储形式:
sign 位 exponent 位 franction 位 52 位 隐藏位 1
0 10000110100 0000000000000000000000000000000000000000000000000000 1
3、结论:
从第 2^53 位开始,超出位被舍弃,这个时候,2^53+1===2^53。再过 N 个值,会出现每 4 个值里面都有 3 个值不精确;再过 M 个值,会出现每 2^K 个值里有 2^K-1 个值不精确;以此类推……
额外:这里尾数是 52 位,但是最大安全整数是 2^53 - 1,这个 53 是因为用上了隐藏位。

顺便说下 0.1+0.2 !== 0.3 的提示:计算机存储小数也是通过二进制存储,导致 2 的 n 次幂无法精确表示所有小数。

最后,推荐下我总结的文章: https://www.yuque.com/dixdiydiz/qdjs/number
j137tt736CExzlfM
2020-02-21 16:13:57 +08:00
@tsohgdivil 请问你是怎么上传图片的,我记得 V2EX 没有图床啊

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/646244

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX