「这是我参与2022首次更文挑战的第18天,活动详情查看:2022首次更文挑战」
JavaScript 的数学还真是不太好,小学生看到的话,都得说一声:就 这 ?
不服气的,就往下看 ⬇️
let a = 1
let b = 2
let c = 3
let d = a + b
let e = b + c
console.log('a:', a, 'b:', b, 'c:', c, 'd:', d, 'e:', e)
// 打印结果 a: 1 b: 2 c: 3 d: 3 e: 5
这打印结果也没毛病呀。。。全对 ✅
那我们再来看看小数的计算。。。
let a = 0.1
let b = 0.2
let c = 0.3
let d = a + b
let e = b + c
console.log('a:', a, 'b:', b, 'c:', c, 'd:', d, 'e:', e)
// 打印结果 a: 0.1 b: 0.2 c: 0.3 d: 0.30000000000000004 e: 0.5
咦 ~ ~ ~
0.1 + 0.2 竟然不等于 0.3
0.1+0.2 = 0.3,这连小学生都会算的题,咋会出错呢。。。这又是咋回事呢?到底是谁在捣鬼???
探探号要发车咯,我们一起去找找原因吧
探探第一站 —— IEEE 754
- 二进制浮点数算术标准
- 浮点数的四种表示方式
【 单精确度(32位)、双精确度(64位)、延伸单精确度(43比特以上,很少使用)与延伸双精确度(79比特以上,通常以80位实现) 】 - 浮点数 = 符号位(sign)✖️ 指数偏移值(exponent) ✖️ 分数值(fraction)
- 单精度浮点数(共32位)= 1个符号位 + 8个指数位 + 23个小数位
- 双精度浮点数(共64位)= 1个符号位 + 11个指数位 + 52个小数位
- 浮点数通过利用指数达到了浮动小数点的效果,可以表达更大范围的实数,但同时也会产生误差
探探第二站 —— 误差取舍
- 默认向偶数舍入 【 取最接近且可表示的值 —— 只需考虑最低有效数字是奇数还是偶数 】
- 1.4 -> 1; 1.5 -> 2; 1.6 -> 2; 2.5 -> 2; -1.5 -> -2
- 向 0 舍入
- 1.4 -> 1; 1.5 -> 1; 1.6 -> 1; 2.5 -> 2; -1.5 -> -1
- 向上舍入 【 +∞ 方向 】
- 1.4 -> 2; 1.5 -> 2; 1.6 -> 2; 2.5 -> 3; -1.5 -> -1
- 向下舍入 【 -∞ 方向 】
- 1.4 -> 1; 1.5 -> 1; 1.6 -> 1; 2.5 -> 2; -1.5 -> -2
探探第三站
- 鉴于浮点数不可避免滴会有误差的情况出现,不推荐在计算中使用浮点数
- 前提已知最终计算结果的小数点位数,可以先把小数转换为整数,再进行加减,得到的结果,再除以其转为整数时扩大的倍数
let a = 0.1 let b = 0.2 let c = (a * 10 + b * 10 ) / 10 console.log(c) // 输出结果 0.3
终点 🏁
- 万万没想到 JavaScript 的数学不好的背后,竟然是二进制浮点数算术标准在作怪