1

I have an object that has a money property with the datatype Decimal(10,2) on mySql.

My javascript makes an http reques to retrieve those values and I process the data inside my javascript function to add up all the values into one $scope:

 $scope.expected = 0;
 for(var k = 0; k < collection.length; k++)
    {
        $scope.expected += Number(collection[k].price);
    }

price is the money value that contains 125.89 as the value from the DB. The iteration makes 31 iterations as collection.length returns me 31.

I used the Number Reference because it starts out as a string.

When The looping finishes, I end up with this sum: 3902.589999999999 But all I want is 3902.58 since this is money and it must be an exact representation. I researched around and the community seems to agree on using toFixed(2) but from my understanding, toFixed(2) rounds the number up which is something I do NOT want to do since this operation involves cash.

Is there a way to keep the 2 decimal places without rounding?

I also kept a log of the console.log throughout the entire loop. Here is the result:

125.89
251.78
377.67
503.56
629.45
755.34
881.23
1007.12
1133.01
1258.9
1384.7900000000002
1510.6800000000003
1636.5700000000004
1762.4600000000005
1888.3500000000006
2014.2400000000007
2140.1300000000006
2266.0200000000004
2391.9100000000003
2517.8
2643.69
2769.58
2895.47
3021.3599999999997
3147.2499999999995
3273.1399999999994
3399.0299999999993
3524.919999999999
3650.809999999999
3776.699999999999
3902.589999999999
GitaarLAB
  • 14,536
  • 11
  • 60
  • 80
remedy.
  • 2,032
  • 3
  • 25
  • 48
  • 1
    there is no mysql syntax here why it is being tag? – CodeSlayer Dec 01 '14 at 08:14
  • possible duplicate of [Is floating point math broken?](http://stackoverflow.com/questions/588004/is-floating-point-math-broken) – Andreas Dec 01 '14 at 08:14
  • possible duplicate of [Elegant workaround for JavaScript floating point number problem](http://stackoverflow.com/questions/1458633/elegant-workaround-for-javascript-floating-point-number-problem) – GitaarLAB Dec 01 '14 at 08:15
  • You can check this QA http://stackoverflow.com/questions/10808671/javascript-how-to-prevent-tofixed-from-rounding-off-decimal-numbers – Miqdad Ali Dec 01 '14 at 08:35

3 Answers3

0

Here i have created code for your problem:

for(var k = 0; k < data.length; k++)
{
    var num2 = data[k].toString().split('.');
    if(typeof num2[1] != 'undefined')
    {
        num2[1] = num2[1].toString().substring(0,2);
        data[k] = num2[0] + "." + num2[1];
    }
    console.log(Number(data[k]));
}

Have a Look at Fiddle

Ankur
  • 496
  • 1
  • 6
  • 11
0

It appears from your post like you are dealing with positive numbers.

If you want to truncate the final result, you could achieve that by invoking Math.floor like this

$scope.expected = Math.floor($scope.expected * 100)/100;

However if on the other hand you wanted to truncate to each number to two decimal places before summation, then you could use the following

$scope.expected = 0;
 for(var k = 0; k < collection.length; k++)
    {
        $scope.expected += Math.floor(Number(collection[k].price) * 100) / 100;
    }

Note that this will only work if all your numbers are positive (greater or equal to zero).

If you expect negative numbers, you could devise a function as follows:

truncateNumber = function (number) {
    if(number < 0){
       return Math.ceil(number * 100) / 100;
    }else{
       return Math.floor(number * 100) / 100;
    }   
};

Example

Use either

 $scope.expected = truncateNumber($scope.expected);

or

  for(var k = 0; k < collection.length; k++)
   {
        $scope.expected += truncateNumber(Number(collection[k].price));
   }
Simon Savai
  • 182
  • 2
  • 13
0

The behavior you are describing is to be expected due to the way floating point numbers work in javascript. The solution you require depends on the accurate range you need: if you need a number-range larger then you can obtain with javascript you should look into a big-number library.

Because Math.pow(2, 53) === 9007199254740992 is the largest directly representable integer in javascript, you could decrease that range by factor 100, thereby gaining 2 decimal places in accuracy. That would make your positive range [0, 90071992547409].

I don't think you want 3902.58; you probably want: 3902.59 (=125.89 * 31)

Assuming your input has a maximum precision of 2 decimals and no negative values:

<xmp id="dbg"></xmp>
<script>// create $scope, collection and get debug output element for example:
for(var dbg=document.getElementById('dbg'), $scope={}, L=31, collection=new Array(L); L--; collection[L]={price:'125.89'});

// ==========  ANSWER BEGINS HERE:  ==========

$scope.expected = 0;
for(var k = 0; k < collection.length; k++){
   $scope.expected += Number(collection[k].price)*100;  //increase precision
   //added debug line meant to resemble the debug listing in your question:
   dbg.innerHTML+=($scope.expected / 100).toFixed(2) + '\n' ;
}
// maintain precision internally and only round when needed (like before output)
// flooring your total is optional (not needed when you can guarantee 
//   no more than 2 decimals at the input-side). 
// divide by 100 before output
// then use toFixed to convert the number to string 
//   AND append dot/decimals when needed 
dbg.innerHTML+='\nTotal: ' + (Math.floor($scope.expected) / 100).toFixed(2);
</script>

Don't be thrown off by the toFixed: we use it to ensure 2 decimals (in other words, add trailing 0's (and a dot if necessary) for the cents for numbers like 8.8 or 4

GitaarLAB
  • 14,536
  • 11
  • 60
  • 80