Zaziro
Zaziro

Reputation: 543

Rounding in JS: inconsistent and unexpected behaivior

I'm dealing with relatively small and simple numbers. I first tried to do the rounding (2 signs after digit) with infamous toFixed. It's a known issue: sometimes it works incorrectly. But what struck me is the fact that it also works inconsistently:

(0.395).toFixed(2); // "0.40"
(0.295).toFixed(2); // "0.29"

These numbers are very similar, 3 signs after digit and yet different behavior.

So, I decided to switch to using Math.round. Shortly, I encountered another problem:

Math.round(0.35055 * 10000) / 100; // produces 35.05 instead of 35.06

Is Math.round also problematic? Then, what method should be used?

Upvotes: 4

Views: 910

Answers (2)

Damien
Damien

Reputation: 3220

I think this is working as designed. Keep in mind these numbers are stored in base 2, so there is a loss of precision when converting to and from base 10. And you have to look at these conversions if you want to understand why it looks inconsistent. If you have a fixed number of decimals that you want to keep precisely, you can use integers for operations and convert only for display.

Upvotes: 0

BBog
BBog

Reputation: 3650

Unfortunately JavaScript is known to have such precision issues, issues that are better explained in the following question: Is floating point math broken?, as pointed in the comments.

If you require a greater degree of numerical accuracy, I would suggest you to use a library such as BigNumber, which also comes with its own toFixed method.

Your example would look something like this:

var a = new BigNumber('0.35055');
a = a.times(10000)
a = a.dividedBy(100)
console.log(a.toFixed(2)); //would log "35.06"

For brevity you can also chain the operations, like this: a.times(10000).dividedBy(100).toFixed(2)

Upvotes: 4

Related Questions