最近项目中用到了浮点的乘法运算,遇到了两个问题,一个是运算的结果出现了误差,另一个问题是运算结果出现了科学计数法,需要将科学计数法转换成普通数字。下面我们一一来处理。
1、js浮点数做数学运算的时候出现误差
我们都知道在计算机中所有的运算都是以二进制的形式进行的,所以浮点数在进行数学运算的时候也会先转换成二进制,但是浮点数转换成二进制的时候可能会有无限位,而IEEE 754 标准的 64 位双精度浮点数的小数部分最多支持 53 位二进制位,所以二进制表示的浮点数本身就有误差,数学运算之后同样存在误差。
那么,怎样消除这种误差呢?目前通用的方式是:
//乘法
function accMul(arg1,arg2) {
var m=0,s1=arg1.toString(),s2=arg2.toString();
try{m+=s1.split(".")[1].length}catch(e){}
try{m+=s2.split(".")[1].length}catch(e){}
return Number(s1.replace(".",""))*Number(s2.replace(".",""))/Math.pow(10,m);
}
原理就是将浮点数转化正整数,运算之后再转化成浮点数。下边这边文章有非常详细的讲解:JavaScript 浮点数运算的精度问题。
2、科学计数法转换成普通数字
JavaScript在以下情景会自动将数值转换为科学计数法:
(1)小数点前的数字个数大于等于22位;
(2)小数点前边是0,小数点后十分位(包含十分位)之后连续零的个数大于等于6个。
但是,我并不想以科学技术法的形式展示给用户,于是找到了以下这个函数,并且做了逐行分析:
:function scientificToNumber(num) {
if(/\d+\.?\d*e[\+\-]*\d+/i.test(num)) { //正则匹配科学计数法的数字
var zero = '0', //
parts = String(num).toLowerCase().split('e'), //拆分成系数和指数
e = parts.pop(),//存储指数
l = Math.abs(e), //取绝对值,l-1就是0的个数
sign = e/l, //判断正负
coeff_array = parts[0].split('.'); //将系数按照小数点拆分
if(sign === -1) { //如果是小数
num = zero + '.' + new Array(l).join(zero) + coeff_array.join(''); //拼接字符串,如果是小数,拼接0和小数点
} else {
var dec = coeff_array[1];
if(dec) l = l - dec.length; //如果是整数,将整数除第一位之外的非零数字计入位数,相应的减少0的个数
num = coeff_array.join('') + new Array(l+1).join(zero); //拼接字符串,如果是整数,不需要拼接小数点
}
}
return num;
}
通过这两个方法可以解决项目中遇到的两个问题,验证有效,在此记录。
网友评论