0.1 + 0.2 为什么不等于 0.3
JavaScript内部计算都是以二进制进行的
- 整数部分转换为二进制的规则是:除以2取余,余数逆序排列。
10 / 2 = 5 ... 0 // ↑
5 / 2 = 2 ... 1 // ↑
2 / 2 = 1 ... 0 // ↑
1 / 2 = 0 ... 1 // ↑
所以10转换为二进制就是1010。
- 小数部分转换为二进制的规则是:乘2取整,整数部分顺序排列。
0.1 * 2 = 0.2 // 整数0 ↓
0.2 * 2 = 0.4 // 整数0 ↓
0.4 * 2 = 0.8 // 整数0 ↓
0.8 * 2 = 1.6 // 整数1 ↓
0.6 * 2 = 1.2 // 整数1 ↓
0.2 * 2 = 0.4 // 整数0 ↓
0.4 * 2 = 0.8 // 整数0 ↓
0.8 * 2 = 1.6 // 整数1 ↓
0.6 * 2 = 1.2 // 整数1 ↓
// 无限循环
小数部分转换为二进制可能出现无限循环,比如0.1的二进制表示为0.0001100110011...(0011循环)。
JavaScript中number类型使用IEEE754标准64位存储
IEEE754标准64位存储也就是双精度浮点数(double),系统会为每个数值分配64位存储空间,以科学计数法的方式存储(1.xx * 2 ^ n)。
64位存储空间分为3个部分:
1 * 符号位(sign) + 11 * 指数位(exponent) + 52 * 小数位(fraction)
- 符号位:0正数,1负数
- 指数位:固定值1023 + 指数实际值
- (2 ^ (e - 1)) - 1 => (2 ^ (11 - 1)) => 1023
- 小数位:二进制小数点后的数字
IEEE754标准64位数相加
总结
- JavaScript的Number类型的实现遵循IEEE754标准,以64位双精度浮点数存储,即计算机最多存储64位二进制数
- 小数在转换成二进制表示的时候,可能会存在无限循环的情况,但是由于最多只能存储64位二进制数,就只能舍入(0舍1入),这就发生了第一次精度丢失。