toFixed() 方法可把 Number 四舍五入为指定小数位数的数字。通俗点就是传入的参数是几,那么我们的小数就保留几位。
eg: alert(0.056.toFixed(2));–>0.06
但是使用过程中发现了一个小问题 ,就是0.0056.toFixed(2)结果却为0.00
遂重写toFixed()
代码如下:
//重写toFixed方法
Number.prototype.toFixed=function(len)
{
var tempNum = 0;
var s,temp;
var s1 = this + "";
var start = s1.indexOf(".");
//截取小数点后,0之后的数字,判断是否大于5,如果大于5这入为1
if(s1.substr(start+len+1,1)>=5)
tempNum=1;
//计算10的len次方,把原数字扩大它要保留的小数位数的倍数
var temp = Math.pow(10,len);
//求最接近this * temp的最小数字
//floor() 方法执行的是向下取整计算,它返回的是小于或等于函数参数,并且与之最接近的整数
s = Math.floor(this * temp) + tempNum;
return s/temp;
}
js中toFixed精度问题的解决办法
最近在做项目的时候,遇到了有四舍五入保留两位的需求,当时不假思索的直接使用了js原生的toFixed方法,结果问题百出。主要还是有以下几点问题:
一:四舍五入并不是真正的四舍五入
以下是在chrome上的结果:
1.35.toFixed(1) // 1.4 正确
1.335.toFixed(2) // 1.33 错误
1.3335.toFixed(3) // 1.333 错误
1.33335.toFixed(4) // 1.3334 正确
1.333335.toFixed(5) // 1.33333 错误
1.3333335.toFixed(6) // 1.333333 错误
以下是IE上的结果:
1.35.toFixed(1) // 1.4 正确
1.335.toFixed(2) // 1.34 正确
1.3335.toFixed(3) // 1.334 正确
1.33335.toFixed(4) // 1.3334 正确
1.333335.toFixed(5) // 1.33334 正确
1.3333335.toFixed(6) // 1.333334 正确
难道是浏览器兼容性问题?兼容性问题难道不应该是出在IE中吗?既然找到问题所在,就好下手。我的办法是把要四舍五入的后一位单独拎出来单独判断。
let result = number.toString();
const arr = result.split('.');
const integer = arr[0];
const decimal = arr[1];
result = integer + '.' + decimal.substr(0, n);
const last = decimal.substr(n, 1);
// 四舍五入,转换为整数再处理,避免浮点数精度的损失
if (parseInt(last, 10) >= 5) {
const x = Math.pow(10, n);
result = ((parseFloat(result) * x) + 1) / x;
result = result.toFixed(n);
}
return result;
测了几遍,貌似没什么问题,OK~
二:计算机二进制编码导致的精度问题
自己debugger,发现页面中的js进了死循环。很明显问题出在toFixed中回调了toFixed,结果没有走出来,继续debugger,又有了进人的发现。以下是控制台测试:
console.log(2.115 * 100) // 211.50000000000003
console.log(2.0115 * 1000) // 2011.4999999999998
好吧,我猜到了,肯定是计算机的进度问题。既然你一直进入循环,我就手动把你拉出来。
result = (Math.round((parseFloat(result)) * x) + 1) / x;
强制四舍五入取整,不会进死循环了!
以下是全部代码:
// toFixed兼容方法
Number.prototype.toFixed = function (n) {
if (n > 20 || n < 0) {
throw new RangeError('toFixed() digits argument must be between 0 and 20');
}
const number = this;
if (isNaN(number) || number >= Math.pow(10, 21)) {
return number.toString();
}
if (typeof (n) == 'undefined' || n == 0) {
return (Math.round(number)).toString();
}
let result = number.toString();
const arr = result.split('.');
// 整数的情况
if (arr.length < 2) {
result += '.';
for (let i = 0; i < n; i += 1) {
result += '0';
}
return result;
}
const integer = arr[0];
const decimal = arr[1];
if (decimal.length == n) {
return result;
}
if (decimal.length < n) {
for (let i = 0; i < n - decimal.length; i += 1) {
result += '0';
}
return result;
}
result = integer + '.' + decimal.substr(0, n);
const last = decimal.substr(n, 1);
// 四舍五入,转换为整数再处理,避免浮点数精度的损失
if (parseInt(last, 10) >= 5) {
const x = Math.pow(10, n);
result = (Math.round((parseFloat(result) * x)) + 1) / x;
result = result.toFixed(n);
}
return result;
};