Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”.
On the pit of
In my recent work, when calculating the discount price of a commodity, sometimes there is always a difference of one cent in the price. All problems related to money are quite sensitive. After investigation, it was finally found to be the problem of JS original toFixed method.
Boy, it’s not a rule… (it’s even)
Filling holes method
First do not worry to explore the problem, since found the problem, it is the first to fix the Bug, the original method can not be used, write a bai, is not a minute thing, ha ha ha!
@param num: @param digit: @param digit: Function myFixed(num, digit) {if(object. is(parseFloat(num), NaN)) {return console.log(' passed value: ${num} is not a number '); } num = parseFloat(num); return (Math.round((num + Number.EPSILON) * Math.pow(10, digit)) / Math.pow(10, digit)).toFixed(digit); }Copy the code
What kind of pit?
Ok, now that the Bug is solved, let’s explore the mystery of toFixed.
Uh… First of all, the Em… Baidu once, face Baidu programming engineer, as expected a check big result, looked like a classic problem.
After some understanding, it turns out that the toFixed method uses the round, not the literal round we understand. And toFixed method it is the use of a weird method “rounding off six five even”, also called the banker algorithm, what is the meaning of this?
Complete statement: “four rounding six into five consideration, five non-zero into one, five after zero to see odd even, five before even should be dropped, five before strange to enter a”.
When it is greater than or equal to 6, it is added. When it is equal to 5, it depends on the number after 5. If 5 is followed by a non-zero number, round 5 to 1. If 5 is not followed by a significant digit, it needs to be divided into two cases: if 5 is an even number before 5, it cannot be rounded. If 5 is an odd number, round 5 to 1.
Following this rule, I ran some more tests on the browser, but it still didn’t feel right.
// The number before five is even. The console. The log (1.00000065 toFixed (7)); // 1.0000007 error console.log(1.000000065.tofixed (8)); // 1.00000007 error // 5 is an odd number, not a decimal? The console. The log (1.00000015 toFixed (7)); // 1.0000001 error console.log(1.000000015.tofixed (8)); / / 1.00000001 errorCopy the code
Why is that? It’s really confusing… ().
After a bit of exploration, it’s time to take a look at the ECMAScript specification’s definition of this method, and sometimes going back to the specification makes the most sense.
The figure above is about the definition of the whole toFixed method, but it is the translated version. There will be some differences but not much difference. You can also click the link above to view the original text.
Let’s take the next two and test them.
The console. The log (1.0000005 toFixed (6)); // 1.000001 Correct console.log(1.00000005.tofixed (7)); / / 1.0000000 errorCopy the code
First, according to the red box condition, x<10^21, 1.0000005 and 1.00000005 are both less than 10^21, so we can play with the formula N / 10^ -x directly.
Let’s first use x=1.0000005 to plug into the formula to see what happens:
Var n1 = 1000000; Var x = 1.0000005; var f = 6; console.log((n1 / Math.pow(10, f) - x)); // -5.00000000069889E-7 // assume n2 var n2 = 1000001; Var x = 1.0000005; var f = 6; console.log((n2 / Math.pow(10, f) - x)); / / 4.999999998478444 e-7Copy the code
According to the results, when N1 =1000001, the result obtained is the value closest to 0, so:
The console. The log (1.0000005 toFixed (6)); / / 1.000001 is correctCopy the code
Try again when x=1.00000005:
Var n1 = 10000000; Var x = 1.00000005; var f = 7; console.log((n1 / Math.pow(10,f) - x)); // -4.9999999918171056e-8 var n2 = 10000001; Var x = 1.00000005; var f = 7; console.log((n2 / Math.pow(10,f) - x)); / / 5.000000014021566 e-8Copy the code
According to the results, when n2=10000001, the value closest to 0 is obtained, so:
The console. The log (1.00000005 toFixed (7)); / / 1.0000000 errorCopy the code
Ah… Write here just discover to dig a big hole for oneself, why want to make so many zero, oneself all count dizzy circle…
In summary, the above example just shows you how to calculate the result from the formula defined by the specification. If you can read the specification, it is ok to plug in directly.
At this point, this article is finished, sa Hua Sa hua.
I hope this article has been helpful to you. If you have any questions, I am looking forward to your comments. Same old, likes + comments = you know it, favorites = you know it.