On Mon, Oct 12, 2009 at 11:19 AM, Phil Ashby phil.ashby@bt.com wrote:
On Mon, 2009-10-12 at 11:08 +0100, Mark Rogers wrote:
Can anyone explain this code's output?
<?php $x = (15/100) * 10.7; $y = 1.605; var_dump($x, $y, round($x,2), round($y,2),round(1.605,2)); ?>
Result: float(1.605) float(1.605) float(1.6) float(1.61) float(1.61)
As you suspect, it's because 15/100 and 10.7 (and 1.605 infact) cannot be exactly represented in IEEE 784 format binary floating point. Thus the calculated value is very slightly below 1.605 and is thus rounded down whereas the constant 1.605 is very slightly above (this is just how the compiler chooses the represent the value of course) and gets rounded up.
Borland had a solution to this problem 25 years ago: they produced a version of Turbo Pascal that worked in binary coded decimal (BCD) instead of base 2, and thus has no problem with decimal representation or calculations. A similar solution is in use today in packages like Sage... perhaps you can find a BCD maths library or compiler switch?
I am so sorry, I did my replies straight to Mark and not to the group: You are absolutely correct, PHP's manual states quite clearly a warning for 0.7 in particular (http://us2.php.net/manual/en/language.types.float.php ) and gives a link to their higher precisions BC library: http://us2.php.net/manual/en/ref.bc.php
Also I have suggested not using floats to represent currency instead representing by integer of lowest denomination (i.e. pence:
$x = 10.7 * 100; $x = $x * .15 / 100; var_dump( round($x,2));
produces float(1.61)
JT