转自:http://www.jb51.net/article/47659.htm
表现:
var numA = 0.1;
var numB = 0.2;
alert( (numA + numB) === 0.3 ); //执行结果是 false 为什么不是 true?
alert( numA + numB ); // 执行结果是 0.30000000000000004 为什么不是 0.3?
分析原因:
对于浮点数的四则运算,几乎所有的编程语言都会有类似精度误差的问题,只不过在 C++/C#/Java 这些语言中已经封装好了方法来避免精度的问题,而 JavaScript 是一门弱类型的语言,从设计思想上就没有对浮点数有个严格的数据类型,所以精度误差的问题就显得格外突出。
能被计算机读懂的是二进制,而 0.1 和 0.2 转换成二进制:
0.1 => 0.0001 1001 1001 1001…(无限循环)
0.2 => 0.0011 0011 0011 0011…(无限循环)
(十进制0.1转二进制导致的精度误差原因http://blog.sina.com.cn/s/blog_56811e6b0100h7hi.html)
双精度浮点数的小数部分最多支持 52 位,所以两者相加之后得到这么一串 0.0100110011001100110011001100110011001100110011001100 因浮点数小数位的限制而截断的二进制数字,这时候,再把它转换为十进制,就成了 0.30000000000000004。
解决方法:
Math.formatFloat = function(f, digit) {
var m = Math.pow(10, digit);
return parseInt(f * m, 10) / m;
}
var numA = 0.1;
var numB = 0.2;
alert("和为:"+Math.formatFloat(numA + numB, 1) );
原理:
为了避免产生精度差异,大部分编程语言都是把需要计算的数字乘以 10 的 n 次幂,换算成计算机能够精确识别的整数,然后再除以 10 的 n 次幂,这样就可以处理精度差异。
涉及两位小数的金额计算时:
Math.formatFloat(36288.12-450.84-11.3,2); // 35825.98
// 金额
Math.formatFloat = function(f, digit) {
// digit = 2; // 涉及保留两位小数的计算时
var m = Math.pow(10, digit);
var tNum = new Number(parseInt(f * m, 10) / m).toFixed(2);
return tNum;
}
// 设置预算可用金额(实际预算可用金额为可用金额)
function setYuSuanKeYongMoney(){
// 预算可用金额 = 预算金额 - 暂扣金额
var tYuSuanKeYongMoney = Math.formatFloat(getYuSuanMoney()-getZanKouMoney()-getLiuChengMoney(),4);
document.getElementById("Textbox31").value = tYuSuanKeYongMoney;
// alert( "预算金额:"+getYuSuanMoney()+"\n暂扣金额:"+getZanKouMoney()+"\n流程中金额:"+getLiuChengMoney()+"\n预算可用金额:"+tYuSuanKeYongMoney);
}
// 金额
Math.formatFloat = function(f, digit) {
// digit = 2; // 涉及保留两位小数的计算时
var m = Math.pow(10, digit);
var tNum = new Number(parseInt(f * m, 10) / m).toFixed(2);
return tNum;
}