Home  >  Article  >  Web Front-end  >  Solution to toFixed calculation error in Javascript

Solution to toFixed calculation error in Javascript

黄舟
黄舟Original
2017-08-22 10:40:211881browse

This article mainly introduces the solution to the toFixed calculation error in Javascript (the defect of relying on the banker's rounding method). It is of great practical value. Friends in need can refer to it

Preface

In the company's project, a module involving a large number of floating-point price calculations was involved, which triggered a series of thoughts in me:

The problem of lack of calculation accuracy of floating-point numbers in the computer binary environment;


console.log(.1+.2);
0.30000000000000004

In order to solve the above problem, the toFixed method was used, but a rounding error occurred in which the decimal place of the floating point number ended with 5;


var num = 0.045;
console.log(num.toFixed(2));
0.04

This started from my series of explorations about toFixed, and I finally found some useful information. The calculation rules used by toFixed are:

Banker rounding: the so-called banker The essence of the rounding method is a method of rounding to even and leaving even (also known as rounding to five and leaving even).

To put it simply: consider rounding up to five. If the number after five is not zero, add one. If the number after five is zero, look at the odd or even number. If the number before five is even, it should be discarded. If the number before five is odd, it should be rounded. one.

Text

Let’s verify this so-called banker’s rounding method. The verification is divided into three situations, with 4, 5, and 6 as the rounding methods. Confirmation of toFixed bits (taking chrome as an example):

with 4 as the rounding bit:


var num = 0.004;
console.log(num.toFixed(2));
0.00
var num = 0.014;
console.log(num.toFixed(2));
0.01
var num = 0.094;
console.log(num.toFixed(2));
0.09

at the end of 4 In this case, toFixed performed pretty well and there were no errors.

Use 6 as the rounding digit:


var num = 0.006;
console.log(num.toFixed(2));
0.01
var num = 0.016;
console.log(num.toFixed(2));
0.02
var num = 0.096;
console.log(num.toFixed(2));
0.10

ends with 6. In this case, toFixed also performs well. , and there is no wrong question.

Use 5 as the rounding digit:

Non-zero after 5:


var num = 0.0051;
console.log(num.toFixed(2));
0.01
var num = 0.0052;
console.log(num.toFixed(2));
0.01
var num = 0.0059;
console.log(num.toFixed(2));
0.01

According to the rules, if the number after five is not zero, then one will be advanced. We confirmed that there is no problem.

Use 5 as the rounding digit:

5 is followed by zero: Since this situation is quite special, it is a calculation error in the toFixed method, so I have conducted a lot of confirmations and tested them in common mainstream browsers:

Take the following test cases as an example:


var num = 0.005;
console.log(num.toFixed(2));
var num = 0.015;
console.log(num.toFixed(2));
var num = 0.025;
console.log(num.toFixed(2));
var num = 0.035;
console.log(num.toFixed(2));
var num = 0.045;
console.log(num.toFixed(2));
var num = 0.055;
console.log(num.toFixed(2));
var num = 0.065;
console.log(num.toFixed(2));
var num = 0.075;
console.log(num.toFixed(2));
var num = 0.085;
console.log(num.toFixed(2));
var num = 0.095;
console.log(num.toFixed(2));

The results for chrome, firefox, safari, and opera are as follows:

0.01
0.01
0.03
0.04
0.04
0.06
0.07
0.07
0.09
0.10

ie11 The results are as follows:

0.01
0.02
0.03
0.04
0.05
0.06
0.07
0.08
0.09
0.10

It can be seen that it is normal under Ie11, but errors occur under other browsers. Although it does not fully comply with the rules of banker's rounding method, I think it is due to the pitfalls of floating point numbers in binary that it does not fully comply with this rule.

In short: Whether toFixed is introduced to solve the problem of lack of precision in floating-point calculations, or whether it uses the banker's rounding method, it is all to solve the problem of precision, but it cannot be separated from the binary system. Floating point environment, but at least it helped us find the problem and gave us a solution.

Solution

Below I provide a method by overriding toFixed:


 Number.prototype.toFixed = function(length)
    {
      var carry = 0; //存放进位标志
      var num,multiple; //num为原浮点数放大multiple倍后的数,multiple为10的length次方
      var str = this + ''; //将调用该方法的数字转为字符串
      var dot = str.indexOf("."); //找到小数点的位置
      if(str.substr(dot+length+1,1)>=5) carry=1; //找到要进行舍入的数的位置,手动判断是否大于等于5,满足条件进位标志置为1
      multiple = Math.pow(10,length); //设置浮点数要扩大的倍数
      num = Math.floor(this * multiple) + carry; //去掉舍入位后的所有数,然后加上我们的手动进位数
      var result = num/multiple + ''; //将进位后的整数再缩小为原浮点数
      /*
      * 处理进位后无小数
      */
      dot = result.indexOf(".");
      if(dot < 0){
        result += &#39;.&#39;;
        dot = result.indexOf(".");
      }
      /*
      * 处理多次进位
      */
      var len = result.length - (dot+1);
      if(len < length){
        for(var i = 0; i < length - len; i++){
          result += 0;
        }
      }
      return result;
    }

The general idea of ​​​​this method is to first find the rounding bit, determine whether the position is greater than or equal to 5, manually carry out one digit if the condition is met, and then amplify the original floating point number by the parameter exponential times of 10 through the parameter size, and then Then use floor to remove all the digits including the rounding bit, and determine whether to carry based on our previous manual carry.

The above is the detailed content of Solution to toFixed calculation error in Javascript. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn