两种精度丢失问题
最近在工作中频繁的遇到精度问题
1、在js中,当两个带小数点的数值进行加减运算时,在某些特殊情况下如小数点末尾为9或相加为9等情况,则存在精度问题,结果为两位小数点的数据计算出来的结果为很长一串。
解决办法:由于业务涉及到钱,所以不能使用四舍五入,只能采取直接截取或别的,目的是保留两位小数。
在尝试多种方法后 如使用toFix方法,转换成decimal等后均不能解决问题,后来自己实现了两个方法,一个相加一个相减。方法的核心是根据小数位数扩大相应倍数进行计算。
方法如下:
/**
* 加法运算,避免数据相加小数点后产生多位数和计算精度损失。
*
* @param num1加数1 | num2加数2
*/
function numAdd(num1, num2) {
var baseNum, baseNum1, baseNum2;
try {
baseNum1 = num1.toString().split(".")[1].length;
} catch (e) {
baseNum1 = 0;
}
try {
baseNum2 = num2.toString().split(".")[1].length;
} catch (e) {
baseNum2 = 0;
}
baseNum = Math.pow(10, Math.max(baseNum1, baseNum2));
return (num1 * baseNum + num2 * baseNum) / baseNum;
};
/**
* 加法运算,避免数据相减小数点后产生多位数和计算精度损失。
*
* @param num1被减数 | num2减数
*/
function numSub(num1, num2) {
var baseNum, baseNum1, baseNum2;
var precision;// 精度
try {
baseNum1 = num1.toString().split(".")[1].length;
} catch (e) {
baseNum1 = 0;
}
try {
baseNum2 = num2.toString().split(".")[1].length;
} catch (e) {
baseNum2 = 0;
}
baseNum = Math.pow(10, Math.max(baseNum1, baseNum2));
precision = (baseNum1 >= baseNum2) ? baseNum1 : baseNum2;
return ((num1 * baseNum - num2 * baseNum) / baseNum).toFixed(precision);
};
2、今日在mysql中也遇到类似的问题。由于也涉及到金钱,所以不能马虎。
select 20.43+'1.99',20.43+1.99得到的结果不一样。前者是数字与字符串数字相加,后者是纯数字类型相加。但是前者产生了精度问题。
得到的结果如下
多次试验之后发现,并不是所有的数字与字符串相加都会有精度问题,似乎当有一个小数的末尾为9或者小数点后一位相加等于9时会出现此种问题。猜想估计是mysql中字符串转数字的算法问题导致的。
经过db2数据库的校验,此种计算在db2中不存在问题。
解决办法:结果保留两位小数。使用truncate计算之后截取。
select 20.43+'1.99',truncate('1.99'+20.43,2),188.48+'3000.01',truncate(188.48+'3000.01',2)
cast函数和convert函数不满足要求。
由于多次遇到,故作记录。