I initially replied to James direct, as his email came to me not the list. This was my reply to him. His email to me wasn't exactly the same as his mail to the list so the quotes below won't match his list mails, but they're close enough.
James Taylor wrote:
The problem here I believe is the .7 part of the 10.7. Try looking into http://us2.php.net/manual/en/ref.bc.php if you require better precision. (http://us2.php.net/manual/en/language.types.float.php has a big warning box on it).
I thought the BC libraries would be my saviour, but: bcdiv("160.5",100,2) gives "1.60", which surprised me, given that 160.5 is now a string. (160.5 is 15 * 10.7).
Unless the scale isn't supposed to round (making it equivalent to floor) in which case I can't see how I can then perform the rounding later without resorting to floating point maths at some stage.
Just out of interest, why do you round, and not floor or ceil (where required?). I thought for tax you always rounded up (this is just my own jumbled memories and might not be relevant or apply).
My understanding (and I'm neither lawyer nor accountant, and just write the code to meet the spec I'm given) is that there are lots of ways you can do VAT, but one way is to round each line on the invoice to the nearest pence (which is what we do), and another is to calculate the VAT against the ex-VAT subtotal (in which case you round up).
However, the direction of rounding is presumably not significant in itself; I am sure there are calculations that could leave me rounding something like 1.70 up to 1.71 because 1.70 was actually a floating point value ever-so-slightly over 1.70.
Another quick solution is to try and move away from floats as your currency - instead of representing things in pounds, we represent our values in pennies, meaning we avoid using the decimal part - the decimal part is ignored for the raw values:
We always do this for code we write from scratch; not least because its more reliable to store the pence value in a database and uses less storage space. But this code is something I'm maintaining and it supports currencies where there are more than 2 decimal places that are relevant, and it stores things as floats throughout.
My idea to do a 2-stage rounding is easily proved to be a bad idea, btw: 1.6449 should round to 1.64, but if I round to 3dp then to 2dp I get 1.645 then 1.65
One day I'll learn how to reply to mailing list messages properly.
If the BC scale is just that -scale not a round function, we have to move ont o http://uk.php.net/manual/en/ref.gmp.php
Or you do the Superman 2 hack and collect all the fractions of pennies and become rich.
JT
James Taylor wrote:
If the BC scale is just that -scale not a round function, we have to move ont o http://uk.php.net/manual/en/ref.gmp.php
The GMP functions have the same issue.
What I don't understand is that this isn't the world's first eCommerce application that I'm working on. Surely there must be a "standard" solution that any software making financial calculations must adhere to, whether that's BCD or something else?