简体   繁体   English

Javascript加法使我的输出超过2个小数位

[英]Javascript addition gives me an output of more than 2 decimal places

I have an object that has a money property with the datatype Decimal(10,2) on mySql. 我有一个对象,该对象具有mySql上的数据类型Decimal(10,2)的money属性。

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: 我的JavaScript发出了http请求来检索这些值,然后在javascript函数中处理数据,以将所有值加到一个$ 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. price是包含125.89作为数据库中的值的货币值。 The iteration makes 31 iterations as collection.length returns me 31 . 迭代进行31次迭代,因为collection.length返回31

I used the Number Reference because it starts out as a string. 我使用了Number参考,因为它以字符串开头。

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. 当循环结束时,我得到的总和是: 3902.589999999999但是我想要的只是3902.58因为这是金钱,它必须是精确的表示形式。 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. 我研究了一下,社区似乎同意使用toFixed(2)但据我了解, toFixed(2)将数字四舍五入,因为此操作涉及现金,所以我不想这样做。

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. 在整个循环中,我还保存了console.log的日志。 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

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 看看小提琴

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 如果要截断最终结果,可以通过像这样调用Math.floor来实现

$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));
   }

The behavior you are describing is to be expected due to the way floating point numbers work in javascript. 由于浮点数在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. 您需要的解决方案取决于所需的准确范围:如果需要更大的数字范围,则可以使用javascript获取,应该查看大数字库。

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. 由于Math.pow(2, 53) === 9007199254740992是javascript中最大的可直接表示的整数,因此您可以将该范围减小100倍,从而获得2个小数位的精度。 That would make your positive range [0, 90071992547409]. 那将使您的正数范围为[0,90071992547409]。

I don't think you want 3902.58 ; 我不认为你想要3902.58 ; you probably want: 3902.59 (=125.89 * 31) 您可能想要: 3902.59 (= 125.89 * 31)

Assuming your input has a maximum precision of 2 decimals and no negative values: 假设您输入的最大精度为2位小数,并且没有负值:

 <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 不要被toFixed抛弃:我们使用它来确保2个小数(换句话说,为8.84数字添加尾随0的点(如果需要,还加上点))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM