开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第27天,点击查看活动详情
前言
日常开发中我们经常会碰到数字计算问题如求和计算,在js中我们会发现整数计算没问题,但如果计算中出现浮点型结果会超出我们的预想。
问题
我们以求和为例,先简单写一个求和函数:
function sum(array: number[]): number {
const result = array.reduce((pre, cur) => pre + cur, 0);
return result;
}
console.log(sum([1, 2])); //3
这里我们利用数组reduce进行求和,用整数计算完全没问题,我们再换浮点型进行计算:
console.log(sum([1.2, 2.03])); //3.2299999999999995
结果不是我们预想中的3.23,而是约等于3.23后面还跟了很多小数位。这是因为在js中Number是用二进制方法——IEEE 754标准的64-bits表示,这是一种双精度方法。也就是js中的Number都是用二进制保存的,而有些浮点型在转换时不能被精确表示,就产生了误差。
解决
这个原因是js内部自己造成的,不可能修改js源码,那么我们以已有的方法去保证精确度,解决该问题。
- 保留小数位。解决该问题最简单的方法就是保留小数位,需求一般也会有位数要求。我们可以通过toFixed实现,该方法接收一个参数,表示保留的位数,需要特别注意toFixed()返回是string类型。
console.log(sum([1.2, 2.03]).toFixed(2));//3.23
该方法简单粗暴,前提是要契合需求,如果不符合需求就不能用。
- 利用Math.js库,Math是专门处理数字计算相关的库,一些数学相关的计算引用此库事半功倍。有了好的工具,我们继续来思考,整数不会出现精确问题,那么我们可以先升幂再降幂,升幂为整数计算然后再降幂为真实数据。
function sum(array: number[]): number {
let powerNum = 0;
array.forEach((item) => {
//获取每项浮点型小数点位数
const num = (item + '').split('.')[1].length;
//获取最大小数位
if (num > powerNum) {
powerNum = num;
}
});
const enlarge = Math.pow(10, powerNum);
const result = array.reduce(
(pre, cur) => (pre * enlarge + cur * enlarge) / enlarge,
0
);
return result;
}
console.log(sum([1.2, 2.03])); //3.23
该方法对于需求覆盖度更高,但是如果小数位过多可能引起内存泄漏。
总结
以上就是float计算问题解决思路,上述案例是通过加法角度讲解,对于减、乘等算法也是相同的思路。案例中使用的reduce方法也是能够方便进行多个数字之间的运算。