5

I have known that the toFixed() method in javascript converts a number into a string, keeping a specified number of decimals, just like the code shown below, which sets the number of digits after the decimal point to be 2 .

My question is: Whether the number is rounded when necessary. As in the code below, I would convert the number: 0.075. I think rounding 0.075 should be 0.08 as "5 go up". However, it looks weird in the first case below. So I was confused.

var a=0.25*0.3;
var res1 = a.toFixed(2);
console.log(res1);
//Output: a is 0.07 (Is there something wrong?)

var b=0.025*3;
var res2= b.toFixed(2);
console.log(res2);
//Output:b is 0.08

I have known the problem could be solved by using Math.js. However, I was just wondering the reason of the problem? Is a matter of toFixed() method or a matter of data types in javascript.

Jayakumar Thangavel
  • 1,884
  • 1
  • 22
  • 29
s666
  • 266
  • 1
  • 3
  • 14

2 Answers2

2

As stated in the docs, toFixed() does round when necessary. The rounding behavior is to round in the range -.5 < x <= +.5 of the digit.

The strange behavior you're observing is consistent with the note in the docs linked above:

Floating point numbers cannot represent all decimals precisely in binary which can lead to unexpected results such as 0.1 + 0.2 === 0.3 returning false .

In other words, this is a classic case of floating point precision loss - a problem you'll encounter in virtually any language. If you observe the full outputs of a and b you'll see that a == 0.075 and b == 0.07500000000000001 due to floating point precision - and thus given these values it is consistent with the defined rounding behavior to round a to .07 and b to .08.

Klaycon
  • 10,599
  • 18
  • 35
  • Thanks a lot. Could you please explain the rounding rule of toFixed(). Because I don't think it is banking rounding, which rounds the value to the nearest even number, otherwise, it would be a==0.075=0.8. I also tried to print toFixed(22), which shows: a=0.0749999999999999972244 b=0.0750000000000000111022 Does this has something to do with this weird case. – s666 Nov 13 '19 at 18:54
  • It is as I wrote above, in other words, the fractional part up to and including 0.5 is rounded down to the lower integer, and even the tiniest fraction past 0.5 is rounded up to the higher integer. I'm not sure exactly how toFixed works, but it looks like you're asking it to display a higher precision than the default display amount is, which is revealing the precision loss many significant figures in. It is related in the sense that you can see clearly that a < 0.75 and b > 0.75 which is why they round in different directions – Klaycon Nov 13 '19 at 19:08
  • Yes, I got it. I think, as you said, It is not always" round half up" in computers, which means there are some cases like: 0.555=0.55, 1.555=1.56. – s666 Nov 13 '19 at 19:18
1

The problem you are encountering is not specific to JavaScript, it is common to computing in general.

Both these arithmetic calculations have the same result – 0.075:

  • 0.25 * 0.3 = 0.075
  • 0.025 * 3 = 0.075

This is using the decimal number system commonly used.

Computers, at their core, however, don't use the decimal system, but binary – everything is based on 0 and 1.

Because of this, they actually have a hard time getting the calculation above right. JavaScript and other programming languages have to approximate the result, giving you this:

  • 0.25 * 0.3 = 0.75
  • 0.025 * 3 = 0.07500000000000001

You can now see why toFixed returns different results:

  • 0.75.toFixed(2) = 0.07
  • 0.07500000000000001.toFixed(2) = 0.08
Patrick Hund
  • 19,163
  • 11
  • 66
  • 95
  • YES! But I was wondering why 0.075.toFix(2)= 0.07, is it because 0.075 is actually 0.7499999..... And toFixed() round it by using "5 go up"? – s666 Nov 13 '19 at 19:05
  • I think it's because rounding works in such a way that 1-5 is rounded down, 6-9 is rounded up, but I can only speculate, not an expert – Patrick Hund Nov 13 '19 at 19:20