Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

js 浮点数 #61

Open
MengZhaoFly opened this issue Feb 11, 2020 · 0 comments
Open

js 浮点数 #61

MengZhaoFly opened this issue Feb 11, 2020 · 0 comments

Comments

@MengZhaoFly
Copy link
Owner

MengZhaoFly commented Feb 11, 2020

前言

JavaScript 中所有数字包括整数和小数都只有一种类型 — Number,
它的实现遵循 IEEE 754 标准,使用 64 位固定长度来表示,也就是标准的 double 双精度浮点数(相关的还有float 32位单精度)
IEEE 754 标准: 维基百科详解

64位比特又可分为三个部分:

  • 符号位S:第 1 位是正负数符号位(sign),0代表正数,1代表负数
  • 指数位E:中间的 11 位存储指数(exponent),用来表示次方数
  • 尾数位M:最后的 52 位是尾数(mantissa),超出的部分自动进一舍零

可以由一个公式来表示:
image

以上的公式遵循科学计数法的规范

  • E:是一个无符号整数,因为长度是11位,取值范围是 0~2047, 规定减去一个中间数 1023
  • M:整数部分可以被舍去,只保留后面的小数部分

以 0.1 为例:
0.1 转成二进制表示为 0.0001100110011001100(1100循环),科学计数法表示:1.100110011001100 x 2^-4。

  • E:E=-4+1023=1019;
  • M:M 舍去首位的1,得到 100110011...

image
图片转换地址

转化成十进制后为 0.100000000000000005551115123126,因此就出现了浮点误差。

为什么 0.1+0.2=0.30000000000000004

计算步骤为:

// 0.1 和 0.2 都转化成二进制后再进行运算
0.00011001100110011001100110011001100110011001100110011010 +
0.0011001100110011001100110011001100110011001100110011010 =
0.0100110011001100110011001100110011001100110011001100111

// 转成十进制正好是 0.30000000000000004

浮点数加减法运算

规格化

0.1 是正数,所以符号位是0,
而其二进制位是0.000110011......0011...... (0011无限循环),进行规格化后为1.10011001......1001(1)*2^-4,根据0舍1入的规则,最后的值为

2^-4 * 1.1001100110011001100110011001100110011001100110011010
** 舍去部分数字 ** 影响了精度。
0.2 同理:
2^-3 * 1.1001100110011001100110011001100110011001100110011010

对阶

阶差为-1,也就是0.1的阶码比0.2的小,所以要把0.1的尾数右移1位,阶码加1。
2^-3 * 0.1100110011001100110011001100110011001100110011001101(0)
** 尾数位移时可能会发生数丢失的情况,影响精度 **

尾数求和

0.1100110011001100110011001100110011001100110011001101

  • 1.1001100110011001100110011001100110011001100110011010

——————————————————————————————

10.0110011001100110011001100110011001100110011001100111

结果规格化

尾数右移1位,阶码加1。
2^1 * 1.0011001100110011001100110011001100110011001100110011(1)
0舍1入得到
2^1 * 1.0011001100110011001100110011001100110011001100110100

溢出判断

非规格化

sum = 0.010011001100110011001100110011001100110011001100110100
image

浮点数正确的比较方法

Math.abs(0.1 + 0.2 - 0.3) <= Number.EPSILON

等式左右两边差的绝对值是否小于最小精度

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant