1.我们先看几个四舍五入的实例
alert(Number(0.009).toFixed(2));
alert(Number(162.295).toFixed(2));
按正常结果,应该分别弹出0.01和162.30。但实际测试结果却是在不同浏览器中得到的是不同的结果:
在ie6、7、8下得到0.00和162.30,第一个数截取不正确;
在firefox中得到0.01和162.29,第二个数截取不正确;
在opera下得到0.01和162.29,第二个数截取不正确
2.再看有关于四则运算的实例
alert(1/3);//弹出: 0.3333333333333333
alert(0.1 + 0.2);//弹出: 0.30000000000000004
alert(-0.09 - 0.01);//弹出: -0.09999999999999999
alert(0.012345 * 0.000001);//弹出: 1.2344999999999999e-8
alert(0.000001 / 0.0001);//弹出: 0.009999999999999998
按正常结果,除第一行外(因为其本身就不能除尽),其他都应该要得到精确的结果,从弹出的结果我们却发现不是我们想要的正确结果。是因为没有转换成Number类型吗?我们转换成Number后再计算看看:
alert(Number(1)/Number(3));//弹出: 0.3333333333333333
alert(Number(0.1) + Number(0.2));//弹出: 0.30000000000000004
alert(Number(-0.09) - Number(0.01));//弹出: -0.09999999999999999
alert(Number(0.012345) * Number(0.000001));//弹出: 1.2344999999999999e-8
alert(Number(0.000001) / Number(0.0001));//弹出: 0.009999999999999998
还是一样的结果,看来javascript默认把数字识别为number类型。为了验证这一点,我们用typeof弹出类型看看:
alert(typeof(1));//弹出: number
alert(typeof(1/3));//弹出: number
alert(typeof(-0.09999999));//弹出: number
3.计算机原理
回忆一下大学时学过的计算机原理,计算机执行的是二进制算术,当十进制数不能准确转换为二进制数时,这种精度误差就在所难免。从上述的推演过程我们知道,这种误差是难免的,c#的decimal和Java的BigDecimal之所以没有出现精度差异,只是因为在其内部作了相应处理,把这种精度差异给屏蔽掉了,而javascript是一种弱类型的脚本语言,本身并没有对计算精度做相应的处理,这就需要我们另外想办法处理了
创建calc.js文件,其调用方法参考 thinkphp项目调用Vue扩展函数方式
参考文章
Vue.prototype.calc = {
/**
* 千分位格式化函数
* @param {*} number 要格式化的数字
* @param {*} decimals 保留几位小数
* @param {*} dec_point 小数点符号
* @param {*} thousands_sep 千分位符号
*/
number_format(number, decimals, dec_point, thousands_sep) {
if(parseFloat(number) == 0) return " - ";
number = (number + '').replace(/[^0-9+-Ee.]/g, '');
var n = !isFinite(+number) ? 0 : +number,
decimals = (typeof decimals === 'undefined') ? 2 : decimals,
prec = !isFinite(+decimals) ? 0 : Math.abs(decimals),
sep = (typeof thousands_sep === 'undefined') ? ',' : thousands_sep,
dec = (typeof dec_point === 'undefined') ? '.' : dec_point,
s = '',
toFixedFix = function (n, prec) {
var k = Math.pow(10, prec);
return '' + Math.ceil(n * k) / k;
};
s = (prec ? toFixedFix(n, prec) : '' + Math.round(n)).split('.');
var re = /(-?\d+)(\d{3})/;
while (re.test(s[0])) {
s[0] = s[0].replace(re, "$1" + sep + "$2");
}
if ((s[1] || '').length < prec) {
s[1] = s[1] || '';
s[1] += new Array(prec - s[1].length + 1).join('0');
}
return s.join(dec);
},
/**
* 加法函数,用来得到精确的加法结果
* 说明:javascript的加法结果会有误差,在两个浮点数相加的时候会比较明显。这个函数返回较为精确的加法结果。
* 调用:accAdd(arg1,arg2)
* 返回值:arg1加上arg2的精确结果
**/
accAdd: function(arg1, arg2) {
var r1, r2, m, c;
try {
r1 = arg1.toString().split(".")[1].length;
}
catch (e) {
r1 = 0;
}
try {
r2 = arg2.toString().split(".")[1].length;
}
catch (e) {
r2 = 0;
}
c = Math.abs(r1 - r2);
m = Math.pow(10, Math.max(r1, r2));
if (c > 0) {
var cm = Math.pow(10, c);
if (r1 > r2) {
arg1 = Number(arg1.toString().replace(".", ""));
arg2 = Number(arg2.toString().replace(".", "")) * cm;
} else {
arg1 = Number(arg1.toString().replace(".", "")) * cm;
arg2 = Number(arg2.toString().replace(".", ""));
}
} else {
arg1 = Number(arg1.toString().replace(".", ""));
arg2 = Number(arg2.toString().replace(".", ""));
}
return (arg1 + arg2) / m;
},
/**
* 减法函数,用来得到精确的减法结果
* 说明:javascript的减法结果会有误差,在两个浮点数相减的时候会比较明显。这个函数返回较为精确的减法结果。
* 调用:accSub(arg1,arg2)
* 返回值:arg1加上arg2的精确结果
**/
accSub: function(arg1, arg2) {
var r1, r2, m, n;
try {
r1 = arg1.toString().split(".")[1].length;
}
catch (e) {
r1 = 0;
}
try {
r2 = arg2.toString().split(".")[1].length;
}
catch (e) {
r2 = 0;
}
m = Math.pow(10, Math.max(r1, r2)); //last modify by deeka //动态控制精度长度
n = (r1 >= r2) ? r1 : r2;
return parseFloat(((arg1 * m - arg2 * m) / m).toFixed(n));
},
//乘法函数,用来得到精确的乘法结果
//说明:javascript的乘法结果会有误差,在两个浮点数相乘的时候会比较明显。这个函数返回较为精确的乘法结果。
//调用:accMul(arg1,arg2)
//返回值:arg1乘以arg2的精确结果
accMul: function(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的除法结果会有误差,在两个浮点数相除的时候会比较明显。这个函数返回较为精确的除法结果。
//调用:accDiv(arg1,arg2)
//返回值:arg1除以arg2的精确结果
accDiv: function(arg1, arg2) {
var t1 = 0,
t2 = 0,
r1, r2;
try {
t1 = arg1.toString().split(".")[1].length
} catch (e) {}
try {
t2 = arg2.toString().split(".")[1].length
} catch (e) {}
with(Math) {
r1 = Number(arg1.toString().replace(".", ""));
r2 = Number(arg2.toString().replace(".", ""));
return (r1 / r2) * pow(10, t2 - t1);
}
}
}