携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第5天,点击查看活动详情
0.1 + 0.2 !== 0.3 ?
引言
- 我们平时做的数学题:加法运算,从小的口诀就是
逢十进一,也就是十进制。你可能还听说过“半斤八两”,意思是两个人水平差不多。放在数学的角度,半斤可以是十进制去表示的,表示一半,八两如果也想表示一半,那他自然就是十六进制。所以站在进制的角度去看这个问题,半斤(十进制) 就是 八两(十六进制)。在计算机里面,是用另一种进制表现的,那就是二进制。他的加法口诀自然就是逢二进一
js中的数字类型
在 js中使用Number类型表示数字(整数和浮点数)。遵循IEEE-754标准,通过64位二进制来表示一个数字。
64位的详解
第0位:符号位,0表示正数,1表示负数
第1 - 11位:【11位指数】:存储指数部分
第12 - 63位:【52位尾数】:存储小数部分
注: 尾数部分在规定形式下,第一位默认是1(省略不写)
最大安全数[16位]
- 获取最大安全数
Number.MAX_SAFE_INTEGER -》 9007199254740991
Number.MAX_SAFE_INTEGER === Number.MAX_SAFE_INTEGER === Math.pow(2, 53) - 1
52(位尾数) + 1(省略不写的尾数) - 1(符号位)
- 获取最小安全数(最大安全数的负数)
Number.MIN_SAFE_INTEGER -》 -9007199254740991
js中关于小数(浮点数)计算,精度丢失的问题
-
计算机在底层存储的都是0,1的二进制(浮点数转化为二进制,可能会出现无限循环的情况)
0.1 + 0.2 !== 0.3
我们来看看这两个十进制转成二进制是多少
(0.1).toString(2) // '0.0001100110011001100110011001100110011001100110011001101'
(0.2).toString(2) // '0.001100110011001100110011001100110011001100110011001101'
0.1+ 0.2 // 0.30000000000000004
十进制转二进制
-
简单的进制转化,我们可能口算就可以,但是复杂一点,就需要公式来进行计算了
-
比如把十进制6.36 转换为二进制
- 整数部分:
用整数部分,每次 ÷ 2 ,得到的余数位的倒叙,就是整数转化为二进制的整数部分
- 小数部分
每次 * 2, 得到的结果如果小于1,则补零。大于1 则将 1取出,继续相乘
- 结果: 最终结果可能出乎你的意外。出现了循环。浮点数不能精确地用二进制表示所有小数。这可能会导致意外的结果
怎么解决精度问题?
toFixed(digits)
toFixed() 方法使用定点表示法来格式化一个数值。会四舍五入
- digits 小数点后数字的个数;介于 0 到 20(包括)之间,实现环境可能支持更大范围。如果忽略该参数,则默认为 0。
这样尽管可以解决一些问题,但还会有一些其他问题
保留两位小数,本来结果是 0.11 ,但是却返回了 0.10
扩大系数法
- 既然浮点数计算,会出现精度问题,那我们就把十进制浮点数,通过扩大倍数,将其转化为整数。二进制计算完毕,对十进制再除以系数还原即可。
代码
加法: 核心是找出小数位数最多的位数
const coefficient = (num) => {
num += '';
let [, char = ''] = num.split('.');
let len = char.length;
return Math.pow(10, len); // 返回要扩大的系数
// return 10 ** len
};
const plus = (num1, num2) => {
num1 = +num1;
num2 = +num2;
if (isNaN(num1) || isNaN(num2)) return NaN;
let max = Math.max(coefficient(num1), coefficient(num2));
return (max * num1 + max * num2) / max;
};
console.log(plus(0.1, 0.2)); // 0.3
引入三方库
摘录来自(juejin.cn/post/708180…)
Math.js
介绍:功能强大,内置大量函数,体积较大
Github地址:github.com/josdejong/m…
star: 12.2k+
decimal.js
介绍:支持三角函数等,并支持非整数幂
Github地址:github.com/MikeMcl/dec…
star: 4.8k+
big.js
介绍:体积6k,提供了CDN
Github地址:github.com/MikeMcl/big…
star: 3.9k+
number-precision
介绍:体积很小,只有1k左右
Github地址:github.com/nefe/number…
star: 3.4k+