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?
The toFixed() method converts a number to a string. The toFixed() method rounds the string to a specified number of decimals.
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.
The method toFixed(n) rounds the number to n digits after the point and returns a string representation of the result.
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.
Here's a working fiddle: http://jsfiddle.net/2NHSM/6/
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
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:
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.
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));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With