tags:

views:

215

answers:

3

I'm working on a few report output scripts that need to do some rudimentary calculations on some money values.

I am aware of the limitations of floating point arithmetic for this purpose, however the input values are all in a decimal format, so if I use the arithmetic operators on them PHP will cast them to floats.

So what is the best way to handle the numbers? Should I use BCMath? Is there something akin to Decimal in .NET? Or is it safe to use the arithmetic operators if I cast back to int?

+2  A: 

If you use BCMath all values will be stored in strings and passed to the functions as strings, just as the result will be a string. So, you needn't do any casting but ensure that the number given to the function is a value numeric value. Personally, if the math requires a high amount of precision on the decimal side then use BCMath.

The Wicked Flea
+4  A: 

Don't work in Dollars ($1.54), work in cents: (154c). Unless you need to be performing tasks where fractions of a cent are important, then you'll be working with integers and all is well. If you are interested in tenths of a cent, then just multiply everything by ten!

nickf
Generalization: Use a unit that is atomic for your currency.
TokenMacGuy
To convert a currency, banks provide us rates with 8 decimals.
Luc M
What about for display? It still needs to be shown as $1.54. Is there any situation with a floating point number where I'll end up with 1.53 or 1.55?
Shabbyrobe
just use a wrapper function: displayMoney($value){echo '$' . $value * 100;}
SeanDowney
is php really this bad at floats? I mean really, this seems sad
SeanDowney
Sean: No, the point is that you shouldn't use floats, regardless of the programming language. They are imprecise.
troelskn
A: 

If you're working with reasonable amounts (to a "normal person"), using floating point is not likely to be a problem, especially if you're just adding and subtracting amounts, rather than doing, say, interest calculations.

If you're looking for a quick fix, switching to integer is not likely to help you; you still have to deal with overflow. (Someone edited here to mention that if PHP encounters a number beyond the bounds of the integer type, it will be interpreted as a float instead. But then you're back to your original problem of using floating point!) Arbitrary length integers (GMP, referenced from that page) can help.)

Basically, doing this in a half-assed way works in most cases, and is cheap; doing it correctly is a serious pain. My suggestion is to look at this as a business problem: if someone complains about missing a cent, give them a dollar, and don't bother starting on a real solution until you're going to save more dollars by doing that.

Curt Sampson
That is incorrect. Floating points are incapable of representing all base-10 numbers. Even with small numbers, and simple addition/subtraction, you can get incorrect results.
troelskn
Rounded floating point numbers can represent all numbers between 0.01 and 1.00 (note significant digits there) just fine.
Curt Sampson