js中toFixed精度问题的原因及解决办法
toFixed() ⽅法可把 Number 四舍五⼊为指定⼩数位数的数字。例如将数据Num保留2位⼩数,则表⽰为:toFixed(Num);但是其四舍五⼊的规则与数学中的规则不同,使⽤的是银⾏家舍⼊规则,银⾏家舍⼊:所谓银⾏家舍⼊法,其实质是⼀种四舍六⼊五取偶(⼜称四舍六⼊五留双)法。具体规则如下:简单来说就是:四舍六⼊五考虑,五后⾮零就进⼀,五后为零看奇偶,五前为偶应舍去,五前为奇要进⼀。会议纪要怎么写
经测试发现,在chorme下⾯,并没有完全遵守这个规则,尤其是5的后⾯没有数字的时候,不是这么判断的,如下:
var b = 1.335
"1.33"
var b = 1.345
"1.34"
var b = 1.355
"1.35"
var b = 1.365
"1.36"
var b = 1.375
"1.38"
var b = 1.385
党费自查报告
"1.39"
可以发现在chorme下没有完全去遵循这个规律,或许它有⾃⼰的算法,但是毕竟它没有遵循通⽤的银⾏家算法,所以tofixed这个⽅法在涉及到⾦钱计算的业务中还是少⽤.
总⽽⾔之:不论引⼊toFixed解决浮点数计算精度缺失的问题也好,它有没有使⽤银⾏家舍⼊法也罢,都是为了解决精度的问题,但是⼜离不开⼆进制浮点数的环境,但⾄少他帮助我们找到了问题所在,从⽽让我们有解决⽅法。
⼀开始的办法是把要四舍五⼊的后⼀位单独拎出来单独判断。
解决⽅法:
通过重写toFixed⽅法:
Fixed = function (n) {
let result = String();
尽的组词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 (parInt(last, 10) >= 5) {
形容人虚伪的成语
const x = Math.pow(10, n);
result = ((parFloat(result) * x) + 1) / x;
result = Fixed(n);
}
return result;
}
然后⼜发现计算机⼆进制编码导致的精度问题,详见上⼀篇博客。
⾃⼰debugger,发现页⾯中的js进了死循环。很明显问题出在toFixed中回调了toFixed,结果没有⾛出来,继续debugger,⼜有了惊⼈的发现。以下是控制台测试:
console.log(2.115 * 100) // 211.50000000000003
console.log(2.0115 * 1000) // 2011.4999999999998
既然你⼀直进⼊循环,我就⼿动把你拉出来。
result = (und((parFloat(result)) * x) + 1) / x;
最终完整的重写toFixed的⽅法
// toFixed兼容⽅法
Fixed = 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)) {
String();
水库管理条例
}
if (typeof (n) == 'undefined' || n == 0) {
return (und(number)).toString();
}
let result = String();
kt猫简笔画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 (parInt(last, 10) >= 5) {
const x = Math.pow(10, n);
result = (und((parFloat(result) * x)) + 1) / x; result = Fixed(n);
}
return result;
}