最近在做项目的时候,遇到了四舍五入保留两位数的需要。当时我不假思索就用了js的native toFixed方法,结果出了问题。本文主要介绍JS中关于toFixed()方法舍入精度的相关信息,有需要的可以参考一下。
目录
踩坑
填坑法
什么样的坑?
摘要
踩坑
最近在计算一件商品的折扣价时,有时总会出现一分钱的差价,涉及到钱的问题比较敏感。经过调查,最后发现其实是JS原生的toFixed方法的问题。
好家伙,什么规则?(o)
填坑法
先不要着急探究问题。既然已经发现了问题,那就先修复bug吧。如果不能使用原生方法,就自己写一个。这不是分分钟的事哈哈哈!
/**
*保留几个小数位,自动填零,四舍五入。
* @param num:数值
* @param digit:小数位数
* @返回字符串
*/
函数myFixed(num,digit) {
if(Object.is(parseFloat(num),NaN)) {
Return console.log(`传入的值:${num}不是数字`);
}
num=parse float(num);
return(math . round((num num。)* math . pow(10,数字))/Math.pow(10,数字))。toFixed(数字);
}
什么样的坑?
好了,现在Bug已经解决了,我们来探索一下toFixed的奥秘。
嗯.首先,艾米.百度,对于百度编程工程师来说,果不其然,查了很多结果之后,好像是个经典问题。
经过一番了解,原来toFixed方法使用的舍入并不是我们理解的字面舍入。而toFixed方法是一种怪异的方法‘四舍六入五出’,也叫庄家算法。这是什么意思?
完整说法:‘四比六比五考虑,五后一比一是非零,五后一比一是零看奇偶性,五前一比一是偶数,五前一比一是奇数’。
大概意思是:截断位的值4时截断,6时加,但=5时按5后的数确定;当5后面有非零数时,将5放入1;当5之后没有有效数字时,需要分两种情况:5之前的数字是偶数,不输入5之前的数字;第一个5是奇数,第五个变成1。
按照这个规律,我在浏览器上运行了一些测试,还是感觉不对。
//五年前是偶数,不降?
console . log(1.00000065 . to fixed(7));//1.000007错误
console . log(1.000000065 . to fixed(8));//1.0000007错误
//五年前是奇数,没进一个?
console . log(1.00000015 . to fixed(7));//1.000001错误
console . log(1.000000015 . to fixed(8));//1.0000001错误
这到底是为什么?真的很混乱。(︶︿︶)
经过进一步的探索,我终于有所收获。我们来看看ECMAScript规范中对这个方法的定义。有时候回归规范是最可靠的方法。
上图是关于整个toFixed方法的定义,不过是翻译过来的版本,会有所不同但差别不大。也可以点击上面的链接查看原文。我们主要关注图中的红框,用公式计算截断的数字值。
我们举个栗子来测试一下。
console . log(1.0000005 . to fixed(6));//1.00001正确
console . log(1.00000005 . to fixed(7));//1.000000错误
首先,根据红框的条件,x10^21,1.000005和1.0000005都小于10^21,所以我们可以直接用公式n/10^-x来打。
我们先把x=1.000005代入公式看看情况:
//假设n1
var n1=1000000
var x=1.0000005
var f=6;
console.log((n1/Math.pow(10,f)-x));//-5.0000000069889 e-7
//假设n2
var n2=1000001
var x=1.0000005
var f=6;
console.log((n2/Math.pow(10,f)-x));//4.99999998478444 e-7
从结果可以看出,当n1=1,000,001时,得到的结果取最接近0的值,所以:
console . log(1.0000005 . to fixed(6));//1.00001正确
当x=1.0000005代入公式时,我们再试一次:
//假设n1
var n1=10000000
var x=1.00000005
var f=7;
console.log((n1/Math.pow(10,f)-x));//-4.9999918171056 e-8
//假设n2
var n2=10000001
var x=1.00000005
var f=7;
console.log((n2/Math.pow(10,f)-x));//5.000000014021566e-8
从结果可以看出,当n2=10000001时,结果是最接近0的值,所以:
console . log(1.00000005 . to fixed(7));//1.000000错误
嘿.写到这里发现自己挖了一个大坑。为什么我要做那么多零,我会头晕?
总的来说,上面的例子只是教你如何通过规范定义的公式计算结果。如果你能理解规范,那么直接代入就没问题了。
总结
关于JS中toFixed()方法的舍入精度的文章到此为止。有关JS toFixed()舍入精度的更多信息,请搜索我们以前的文章或继续浏览下面的相关文章。希望大家以后能多多支持我们!