开发者

Possible Workaround for Inaccurate Floating Point Rounding?

I have created a PHP system that is having some problems with rounding. After looking further into this, I found that it goes back to the round function in PHP.

For instance...

Rounding 2047.615 to 2 decimal places gives 20开发者_如何学Python47.62 (as expected)

Rounding 2048.615 to 2 decimal places gives 2048.61 (doesn't round up as expected)

I understand that the issue here most likely goes back to the inaccuracy of representing floating numbers in binary, but what is the most elegant way to take care of such issues?


It rounds as expected for me. Have you tried explicitly setting the mode parameter to round()?

round( 2048.615, 2, PHP_ROUND_HALF_UP); // however, PHP_ROUND_HALF_UP is the default

EDIT: It looks like round() was changed in PHP 5.3.0:

Changed round() to act more intuitively when rounding to a certain precision and round very large and very small exponents correctly. (Christian Seiler)2


2048.615 is actually 2048.6149999999998, so it will round down to 2048.61 no matter the rounding method used.


Most likely your particular round function is performing Banker's Rounding (or PHP_ROUND_HALF_EVEN).

If you want a different kind of rounding, use one of the other PHP rounding variants:

<?php
echo round(9.5, 0, PHP_ROUND_HALF_UP);   // 10
echo round(9.5, 0, PHP_ROUND_HALF_DOWN); // 9
echo round(9.5, 0, PHP_ROUND_HALF_EVEN); // 10
echo round(9.5, 0, PHP_ROUND_HALF_ODD);  // 9

echo round(8.5, 0, PHP_ROUND_HALF_UP);   // 9
echo round(8.5, 0, PHP_ROUND_HALF_DOWN); // 8
echo round(8.5, 0, PHP_ROUND_HALF_EVEN); // 8
echo round(8.5, 0, PHP_ROUND_HALF_ODD);  // 9
?> 


Here's the best solution I've come up with. In the following snippet I separate out the integer and decimal parts of the number and then do my rounding just on the decimal part (which gives me more bits available to work on the decimal accuracy). Does anybody see any problems with this solution?

function my_round($number, $decimals) 
  return floor($number) + round(round($number - floor($number), $decimals + 4), $decimals);
}

The "+ 4" is somewhat arbitrary (about half of the trailing digits of detail), but is attempting to be accurate enough without being so accurate as to run into the .499999999 issue causing this whole thing.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜