86

So I am making a script that adds two numbers (decimal numbers) together, which I have encountered a problem.

http://jsfiddle.net/DerekL/esqnC/

I made the script, it turns out pretty good:

0.1 + 0.5  //0.6
0.2 + 0.3  //0.5

But soon I see:

0.1 + 0.2  //0.30000000000000004
0.01 + 0.06  //0.06999999999999999

And it does not look right to me. I know it is a shortcoming of using float point with finite bits, but I can't find a way to fix that.

Math.ceil   //No
Math.floor  //No
.slice      //No

UPDATE

Is it possible to multiply the numbers by 1000 first, then add them then divide it by 1000?

Derek 朕會功夫
  • 92,235
  • 44
  • 185
  • 247
  • This is not a bug, simply real values have a fixed precision, so doing computations on real values may result in some small errors. – Kru May 06 '12 at 20:31
  • 1
    `Math.round(0.1 + 0.2)` is 0. – Gazler May 06 '12 at 20:33
  • 7
    @Gazler - I need how to fix it, not why it happens. – Derek 朕會功夫 May 06 '12 at 20:33
  • The way around this is to perform operations on integers instead. So, if you're working with money values, don't work in dollars, but cents. (At the end of the calculation, just divide by 100 to get the value in dollars). – Šime Vidas May 06 '12 at 20:34
  • 2
    @Gazler Congrats :). Of course you will apply some math to decide the precision you need. On the other hand, everybody understands the issue that creates the situation in the question, but one thing is unclear to me: *what is the expected output?* – kapa May 06 '12 at 20:34
  • @bažmegakapa 0.3 and 0.07, I assume. – Dagg Nabbit May 06 '12 at 20:38
  • @Derek The solutions in the duplicate contain workarounds for your issue. http://stackoverflow.com/a/588053/219743 for example. – Gazler May 06 '12 at 20:39

4 Answers4

108

Use toFixed to convert it to a string with some decimal places shaved off, and then convert it back to a number.

+(0.1 + 0.2).toFixed(12) // 0.3

It looks like IE's toFixed has some weird behavior, so if you need to support IE something like this might be better:

Math.round((0.1 + 0.2) * 1e12) / 1e12
Dagg Nabbit
  • 75,346
  • 19
  • 113
  • 141
13

This is common issue with floating points.

Use toFixed in combination with parseFloat.

Here is example in JavaScript:

function roundNumber(number, decimals) {
    var newnumber = new Number(number+'').toFixed(parseInt(decimals));
    return parseFloat(newnumber); 
}

0.1 + 0.2;                    //=> 0.30000000000000004
roundNumber( 0.1 + 0.2, 12 ); //=> 0.3
Joshua Pinter
  • 45,245
  • 23
  • 243
  • 245
12
function add(){
    var first=parseFloat($("#first").val());
    var second=parseFloat($("#second").val());
    $("#result").val(+(first+second).toFixed(2));
}

DEMO.

The Alpha
  • 143,660
  • 29
  • 287
  • 307
7

Testing this Javascript:

var arr = [1234563995.721, 12345691212.718, 1234568421.5891, 12345677093.49284];

var sum = 0;
for( var i = 0; i < arr.length; i++ ) {
    sum += arr[i];
}

alert( "fMath(sum) = " + Math.round( sum * 1e12 ) / 1e12 );
alert( "fFixed(sum) = " + sum.toFixed( 5 ) );

Conclusion

Dont use Math.round( (## + ## + ... + ##) * 1e12) / 1e12

Instead, use ( ## + ## + ... + ##).toFixed(5) )

In IE 9, toFixed works very well.

BryanH
  • 5,826
  • 3
  • 34
  • 47
  • 1
    Please give example of results, or at least create a fiddle – Rafael Herscovici Mar 29 '16 at 12:42
  • 1
    What's your conclusion? – Noone Oct 20 '16 at 18:44
  • new Number((11200030006000.125 + 0.001).toFixed(5)) still = 11200030006000.127, but if you leave it as a string (11200030006000.125 + 0.001).toFixed(5) = (11200030006000.125 + 0.001).toFixed(5) so Number is rounding. It's still a weird issue and you have to really make assumptions about your decimal places. still looking for an accurate solution I don't have to worry about – hal9000 Apr 30 '21 at 16:26