Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

toFixed(2) function not working

This one is weird, because I got it running in this fiddle but it is not working in the main fiddle. I believe the code is the same.

Here is the main function:

window.setInterval(function(){
    for(var i=0; i < companies.length; i++) {
        var randomVal = (Math.random()*(10 - (-10) + 1)) + (-10);
        randomVal = randomVal / 100;
        randomVal = Number(randomVal.toFixed(2));
        companies[i].price += randomVal;
        //companies[i].price = companies[i].price.toFixed(2);
        $('#price'+i).html(companies[i].price);
    }
}, 1000);

A value like 34.569999999999986 isnt been cut down to 34.56. Any idea what is wrong?

like image 321
Rahul Desai Avatar asked Dec 22 '12 02:12

Rahul Desai


People also ask

What is the use of toFixed 2 in JavaScript?

The toFixed() method converts a number to a string. The toFixed() method rounds the string to a specified number of decimals.

Does toFixed round up or down?

Description. toFixed() returns a string representation of numObj that does not use exponential notation and has exactly digits digits after the decimal place. The number is rounded if necessary, and the fractional part is padded with zeros if necessary so that it has the specified length.

Does toFixed work on strings?

The method toFixed(n) rounds the number to n digits after the point and returns a string representation of the result.


3 Answers

This has to do with a common problem that occurs when converting between binary floating point values and decimal representations. See this fiddle, which is like your "working" one, but I altered the price value so that it also breaks.

Here's an even simpler demo that gets right to the heart of the problem: http://jsfiddle.net/2NHSM/4/

As you can see, the output of 1.23 - 1 is 0.22999999999999998. That's obviously off by a little bit, but it has to do with the way computers represent numbers.

Computers hold numbers as binary digits. 1.23 is actually a "repeating decimal" in binary (just like 1/7 is repeating in decimal), so there's no 100% accurate way to store it. As a result, when you subtract 1.23 - 1 you get an answer that is slightly off because 1.23 was never accurate to begin with.

The same thing is happening in your case. To fix it, just use toFixed right before you display the value, not before you add something else to it.


Update

Here's a working fiddle: http://jsfiddle.net/2NHSM/6/


Update 2

Also note that toFixed can have unexpected rounding behavior. Try the following in the console:

1.35.toFixed(1);
// => 1.4
1.45.toFixed(1);
// => 1.4

You might want to use Math.round instead.

Math.round(1.35 * 10) / 10
// => 1.4
Math.round(1.45 * 10) / 10
// => 1.5
like image 152
Nathan Wall Avatar answered Sep 20 '22 10:09

Nathan Wall


Floating points are approximations so when you add, they don't always end up clean numbers. Just call toFixed when you display it:

companies[i].price += randomVal;
$('#price'+i).html(companies[i].price.toFixed(2));

Demo


This is why your //companies[i].price = companies[i].price.toFixed(2); didn't work:

toFixed() returns a string, so after the first call, companies[i].price is a string. When you do companies[i].price += randomVal;, it is doing string concatenation instead of numeric addition. It'll produce something like:

577.05
577.050.05
577.050.050.1

So you can't call toFixed on it anymore because:

  1. It's a string
  2. It's not even a valid number

So, how would you fix that? Convert it to a number by multiplying by 1 (or Number());

companies[i].price += randomVal;
companies[i].price = companies[i].price.toFixed(2)*1;
$('#price'+i).html(companies[i].price);

Demo

With either of these solutions, the first call to toFixed() is unnecessary.

like image 42
sachleen Avatar answered Sep 19 '22 10:09

sachleen


That's because after applying .toFixed() you're adding the value to another variable, which then causes the precision to go haywire again.

Instead use this for displaying:

$('#price'+i).html(companies[i].price.toFixed(2));
like image 38
Ja͢ck Avatar answered Sep 22 '22 10:09

Ja͢ck