• 手机版

    扫码体验手机版

  • 微信公众号

    扫码关注公众号

游客您好
第三方账号登陆
  • 点击联系客服

    在线时间:8:00-16:00

    客服电话

    400-123-4567

    电子邮件

    1691000615@qq.com
  • 星点互联APP

    随时掌握企业动态

  • 扫描二维码

    关注星点微信公众号

Lv.4 学员组
5号会员,31活跃度,2019/01/10 加入学习
  • 10发帖
  • 10主题
  • 0关注
  • 0粉丝
非常流弊,不废话。。。。。
优秀讲师更多
课堂交流更多
开启左侧

[代码分享] js 中的 number 为何很怪异

[复制链接]
DeJay王健 发表于 2019-1-11 12:09:42 | 显示全部楼层 |阅读模式 打印 上一主题 下一主题
对于 JavaScript 开发者来说,或多或少都遇到过 js 在处理数字上的奇怪现象,比如:


  1. > 0.1 + 0.2
  2. 0.30000000000000004

  3. > 0.1 + 1 - 1
  4. 0.10000000000000009

  5. > 0.1 * 0.2
  6. 0.020000000000000004

  7. > Math.pow(2, 53)
  8. 9007199254740992

  9. > Math.pow(2, 53) + 1
  10. 9007199254740992

  11. > Math.pow(2, 53) + 3
  12. 9007199254740996
复制代码



如果想要弄明白为什么会出现这些奇怪现象,首先要弄清楚 JavaScript 是怎样编码数字的
1. JavaScript 是怎样编码数字的

JavaScript 中的数字,不管是整数、小数、分数,还是正数、负数,全部是浮点数,都是用 8 个字节(64 位)来存储的。
一个数字(如 120.12-999)在内存中占用 8 个字节(64 位),存储方式如下:

  • 0 - 51:分数部分(52 位)
  • 52 - 62:指数部分(11 位)
  • 63:符号位(1 位:0 表示这个数是正数,1 表示这个数是负数)
符号位很好理解,用于指明是正数还是负数,且只有 1 位、两种情况(0 表示正数,1 表示负数)。
其他两部分是分数部分和指数部分,用于计算一个数的绝对值。
1.1 绝对值计算公式


  1. 1: abs = 1.f * 2 ^ (e - 1023)             0 < e < 2047
  2. 2: abs = 0.f * 2 ^ (e - 1022)             e = 0, f > 0
  3. 3: abs = 0                                e = 0, f = 0
  4. 4: abs = NaN                              e = 2047, f > 0
  5. 5: abs = ∞ (infinity, 无穷大)              e = 2047, f = 0
复制代码


说明:

  • 这个公式是二进制的算法公式,结果用 abs 表示,分数部分用 f 表示,指数部分用 e 表示
  • 2 ^ (e - 1023) 表示 2 e - 1023 次方
  • 因为分数部分占 52 位,所以 f 的取值范围为 00...00(中间省略 48 个 0)     到 11...11(中间省略 48 个 1)
  • 因为指数部分占 11 位,所以 e 的取值范围为 000000000000) 到 204711111111111
从上面的公式可以看出:

  • 1 的存储方式:1.00 * 2 ^ (1023 - 1023)f = 0000..., e = 1023... 表示 48 个 0)
  • 2 的存储方式:1.00 * 2 ^ (1024 - 1023)f = 0000..., e = 1024... 表示 48 个 0)
  • 9 的存储方式:1.01 * 2 ^ (1025 - 1023)f = 0100..., e = 1025... 表示 48 个 0)
  • 0.5 的存储方式:1.00 * 2 ^ (1022 - 1023)f = 0000..., e = 1022... 表示 48 个 0)
  • 0.625 的存储方式:1.01 * 2 ^ (1021 - 1023)f = 0100..., e = 1021... 表示 48 个 0)
1.2 绝对值的取值范围与边界从上面的公式可以看出:
1.2.1 0 < e < 20470 < e < 2047 时,取值范围为:f= 0, e = 1 f= 11...11, e = 2046(中间省略 48 个 1)
即:Math.pow(2,-1022) ~= Math.pow(2, 1024) - 1= 表示约等于)
这当中,~=Math.pow(2, 1024) - 1 就是 Number.MAX_VALUE 的值,js 所能表示的最大数值。
1.2.2 e = 0, f > 0e = 0, f > 0 时,取值范围为:f= 00...01, e = 0(中间省略 48 个 0) 到 f = 11...11, e = 0(中间省略 48个 1)
即:Math.pow(2,-1074) ~= Math.pow(2, -1022)= 表示约等于)
这当中,Math.pow(2,-1074) 就是 Number.MIN_VALUE 的值,js 所能表示的最小数值(绝对值)。
1.2.3 e = 0, f = 0这只表示一个值 0,但加上符号位,所以有 +0 -0


回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Powered by Discuz!X3.5 ©2001-2013 Comsenz Inc.星点互联设计( 鲁ICP(125234543) )