JS中toFixed()方法四舍五入的精度问题详解

JS中toFixed()方法四舍五入的精度问题详解

最近在做项目的时候,遇到了四舍五入保留两位数的需要。当时我不假思索就用了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()舍入精度的更多信息,请搜索我们以前的文章或继续浏览下面的相关文章。希望大家以后能多多支持我们!

JS中toFixed()方法四舍五入的精度问题详解