nathanmickler
nathanmickler

Reputation: 13

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 2047.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?

Upvotes: 1

Views: 279

Answers (4)

nathanmickler
nathanmickler

Reputation: 13

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.

Upvotes: 0

Christopher Armstrong
Christopher Armstrong

Reputation: 7953

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

Upvotes: 1

Robert Harvey
Robert Harvey

Reputation: 180787

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
?> 

Upvotes: 1

Josh Lee
Josh Lee

Reputation: 177550

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

Upvotes: 1

Related Questions