Page 1 of 2
rounding problems
Posted: Thu Apr 06, 2006 9:12 am
by hessodreamy
I've run into trouble with rounding the results of calculations. I presume its to do with floating-point precision, but can't seem to get around it.
take the following:
Code: Select all
$number = 227*0.175;
echo "number = $number<BR>";
echo "cast to float : ".(float) $number."<BR>";
echo "var_dump : ".var_dump($number)."<BR>";
echo "using round : ". round($number,2)."<BR>";
echo "using number format : ". number_format($number,2,".","")."<BR>";
echo "multiply by 100 and round to int: ".round($number*100)."<BR>";
echo "multiply by 100 and cast to int : ".(int)($number*100)."<BR>";
this gives me :
Code: Select all
number = 39.725
cast to float : 39.725
float(39.725) var_dump :
using round : 39.72
using number format : 39.72
multiply by 100 and round to int: 3972
multiply by 100 and cast to int : 3972
As you can see the number (39.725) is rounded down to 39.72 in each case, instead of up. Is this due to floating points?
If I say $number = 39.725 then it rounds upwards to 39.73 (except for casting to int).
How do I get around this?
I'm trying to make sure all the figures work out as they do in our acconting software. They probably store pence rather than pounds but I'm not sure this would make any difference in this case. If I multiply by a float (0.175) then I'll end up with a float again, won't I.
HELP ME!!!
Posted: Thu Apr 06, 2006 9:49 am
by feyd
I'd suggest using
bc (arbitrary length decimal math functions) for anything where the mantissa is critical (like accounting)
Posted: Thu Apr 06, 2006 10:31 am
by hessodreamy
OK. That seemed like a good plan. But, with the maths i've already got, turning calculations into function calls makes the code pretty hard to follow. Unless I layout the code differently, & a little more verbose.
Someone suggested casting the calculation result to a string. Lo and behold - it worked. Is there significant detriment to this method?
The use is in a shopping cart application. I'm calculating vat on each product line. The important thing is everything works out the same as our accounting seftware works out. ie the calculation and rounding of vat, and the subsequent totalling of net/gross figures.
Posted: Thu Apr 06, 2006 10:35 am
by feyd
use the bc functions. True, they are less intuitive to read than basic math, but since PHP lacks operator overrides/overloads, there's little than can be done about it. Maybe create a math object and use that instead then you can switch which functions or basic math is used internally while maintaining the same usage in the program itself.
Posted: Wed Apr 19, 2006 9:53 am
by hessodreamy
I found the bc functions no better. Maybe I was using them wrong but there were some calculations such as 93*0.175 =16.275 which still rounds down to 16.27
I found this function much better.
http://www.php-forum.com/p/viewtopic.ph ... 03#4366603
Posted: Wed Apr 19, 2006 11:17 am
by Ollie Saunders
Someone suggested casting the calculation result to a string. Lo and behold - it worked. Is there significant detriment to this method?
I think in general PHP is worse than other languages at floating point arithmatic. Its very disappointing your problem even occurred and somewhat shocking that this was the solution.
use the bc functions. True, they are less intuitive to read than basic math, but since PHP lacks operator overrides/overloads, there's little than can be done about it.
are there plans to implement operating overloading? it would be really nice.
Posted: Wed Apr 19, 2006 11:31 am
by feyd
Unfortunately there are many many ideas about rounding. The implementors of PHP had to choose one. They chose to round 0.5 down instead of up. That is a fairly common rounding method.
http://en.wikipedia.org/wiki/Rounding
As for operator overloading, it's not in PHP 6, so not for a while, if ever.
Posted: Wed Apr 19, 2006 11:54 am
by Oren
Since when? PHP rounds up...
http://us2.php.net/manual/en/function.round.php
And it's not a common method. Follow the link you posted yourself feyd... It is written there (under 'Common method of rounding'):
Example: 3.046 rounded to hundredths is 3.05 (because the next digit [6] is 5 or more).
Posted: Wed Apr 19, 2006 12:13 pm
by feyd
Thanks for proving my point Oren.
Posted: Wed Apr 19, 2006 1:58 pm
by Oren
What do you mean?
Posted: Wed Apr 19, 2006 2:01 pm
by feyd
6 > 5, of course it'll round up.
round(3.045, 2) = 3.04 in PHP's standard build.
Posted: Wed Apr 19, 2006 2:57 pm
by pickle
Holy crap does that every make things difficult when doing any sort of billing with PHP. Thanks for the heads up ~feyd- I didn't realize this was the case.
/me goes to try and fix the billing program I've been using for 2 years.
Posted: Wed Apr 19, 2006 3:03 pm
by someberry
Hrrmmm, don't know about you, but whenever I use the round function, point 5 is rounded up:
Code: Select all
<?PHP
echo(round(39.724, 2) . '<br />'); // Output: 39.72
echo(round(39.725, 2) . '<br />'); // Output: 39.73
echo(round(39.726, 2) . '<br />'); // Output: 39.73
?>
Posted: Wed Apr 19, 2006 3:13 pm
by pickle
Good point. ~feyd, 3.045 rounds to 3.05 on my box. As far as I know I've got a pretty standard build - any idea what might change that outcome?
Posted: Wed Apr 19, 2006 3:58 pm
by Oren
Here is (again) the quote from Wiki:
Example: 3.046 rounded to hundredths is 3.05 (because the next digit [6] is 5 or more).
This time the important part is bold. Also read the above 2 posts^^^