The problem

The other day, the customer service told me that a customer had complained that the billing figures were incorrect, and that the test results were correct on Internet Explorer 11.

After investigation, it was found to be caused by toFixed().

The reason

Take a look at how toFixed() behaves in Chrome, Firefox, and IE.

Chrome:

Firefox:

IE:

You can see that toFixed() rounding is inaccurate on Chrome and Firefox.

ToFixed () on Chrome and Firefox does not use banker rounding as described online.

The rule of the banker rounding method is “four rounding six into five, five after non-zero into one, five after zero to see odd even, five before even should be dropped, five before the surprise into one”.

For example, banker rounding does not apply to (2.55).tofixed (1) = 2.5, (3.55).tofixed (1) = 3.5.

The ecMAScript specification defines toFixed as:

Follow the steps in the figure above to demonstrate the processing of (2.55).tofixed (1) = 2.5.

X = 2.55, less than 102110^{21}1021, f = 1, make n÷10f−xn\div10^ F-xn ÷ 10F −x as close to zero as possible, take n = 25 and n = 26,

You can see that the closest to zero is -0.04999… , so n is 25, then m is 25, k is 2, k−fk-fk−f is 1, so A is 2, then B is 5, so (2.55). ToFixed (1) is 2.5.

2.55=−0.049999925/10 −2.55=−0.049999925/10 −2.55=−0.049999925/10 −2.55=− 0.049999999 2.5525/10− 2.5525/10− 2.5525/10−2.55 does not equal 0.50.50.5 for the same reason that 0.1+0.20.1+0.20.1+0.2 is 0.30.30.3.

In Internet Explorer, 25/10−2.5525/10-2.5525/10−2.55 and 26/10−2.5526/10-2.5526/10−2.55 are the same as those in Chrome and Firefox. Here we can only infer that the definition of toFixed in IE browser does not comply with ECMAScript specification. The specific reason is not clear at present. If you know, you can leave a message in the comments.

To solve

Assuming that the number to be rounded is number, and to keep n decimals, use number∗10nnumber*10^nnumber∗10n, then math.round (), and finally remove 10n10^n10n to achieve indirect rounding. ToFixed () also has an automatic zeroing function, also want to implement, so the following simple encapsulation of a toFixed method to achieve the round.

function toFixed(number, m) { if (typeof number ! == 'number') {throw new Error("number not a number "); } let result = Math.round(Math.pow(10, m) * number) / Math.pow(10, m); result = String(result); if (result.indexOf(".") == -1) { if(m ! = 0){ result += "."; result += new Array(m + 1).join('0'); } } else { let arr = result.split('.'); if (arr[1].length < m) { arr[1] += new Array(m - arr[1].length + 1).join('0') } result = arr.join('.') } return result }Copy the code