RE: Simple math failing - PHP Bug?

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



To view the terms under which this email is distributed, please go to http://disclaimer.leedsmet.ac.uk/email.htm



On 01 November 2004 06:31, Brian T. Allen wrote:

[....]

> When adding dollar amounts using only whole cents (and excluding the
> limitation we've been discussing) you should always have a credit >=
> .01, a balance >= .01, or no balance / credit due, which
> would equal 0
> or 0.00, but NOT 0.0000000000034322.
> 
> Yes, there are ways to program around this, but it shouldn't be
> necessary.  The example above shouldn't be questionable or
> complicated, in fact it is about as basic as it comes.  It's 2nd
> Grade math.

Possibly -- but the explanation of the discrepancy is probably
something nearer high school level (or GCSE Maths, in my
vernacular!).

Very briefly, computers work in binary -- and the binary system can
represent very few decimal fractions exactly.  Take, for example,
your 503.54: in binary, this converts to
111110111.100010100011110101110000..., or, slightly more readably, in
hexadecimal it's 1f7.8a3d70a3d70a3d70....  You can see how this has a
repeating fractional part, and so cannot be represented exactly in
any finite number of bits -- so there is no way of storing exactly
503.54 in any computer working in the binary system.

>  You just should have to program around that.  I would
> MUCH rather 
> have PHP
> run a little slower

Unfortunately, it is very unlikely that "fixing" it the way you'd
like would be only a *little* slower -- more likely, it would be
massively slower.  Given this, it's more efficient and effective to
have the computer calculate the answer as accurately as it can, and
let the programmer decide the level of accuracy it should be tested
for.  (Some early business-oriented computers, and some calculators
(especially financial ones) did use a system called binary-coded
decimal -- BCD -- to calculate "accurately" in the sense you mean,
but the fact that they were never widely used and have died out
almost totally should tell you something about their usefulness.)

Having said all that, here are a couple of golden rules:

  (i) If your numbers can be represented exactly to a given number
of decimals, consider using integers for your calculations and
dividing/multiplying by the appropriate power of 10 on output/input
(this, of course, won't work if the scaled numbers exceed the integer
range).

  (ii) NEVER EVER compare floats for equality -- always build in an
appropriate amount of fuzz (e.g. if you have to use floats for money
amounts, a check for equality to 4 decimal places is probably
sufficient: if (abs($a-100)<0.0001) echo "close enough to $100.00";

  (iii) Always format your numbers to an appropriate number of
decimal places on output (using number_format() or printf(), for
example).

Cheers!

Mike

---------------------------------------------------------------------
Mike Ford,  Electronic Information Services Adviser,
Learning Support Services, Learning & Information Services,
JG125, James Graham Building, Leeds Metropolitan University,
Headingley Campus, LEEDS,  LS6 3QS,  United Kingdom
Email: m.ford@xxxxxxxxxxxxxx
Tel: +44 113 283 2600 extn 4730      Fax:  +44 113 283 3211 

-- 
PHP General Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php


[Index of Archives]     [PHP Home]     [Apache Users]     [PHP on Windows]     [Kernel Newbies]     [PHP Install]     [PHP Classes]     [Pear]     [Postgresql]     [Postgresql PHP]     [PHP on Windows]     [PHP Database Programming]     [PHP SOAP]

  Powered by Linux