You want to store your currency in long
and calculate your currency in double
, at least as a backup. You want all transactions to take place as long
.
The reason you want to store your currency in long
is that you don't want to lose any currency.
Let's suppose you use a double
, and you have no money. Someone gives you three dimes, and then takes them back.
You: 0.1+0.1+0.1-0.1-0.1-0.1 = 2.7755575615628914E-17
Well, that's not so cool. Maybe someone with $10 wants to give their fortune away by first giving you three dimes, and then giving $9.70 to someone else.
Them: 10.0-0.1-0.1-0.1-9.7 = 1.7763568394002505E-15
And then you give them the dimes back:
Them: ...+0.1+0.1+0.1 = 0.3000000000000018
This is just broken.
Now, let's use a long, and we'll keep track of tenths of cents (so 1 = $0.001). Let's give everyone on the planet one billion, one hundred and twelve million, seventy five thousand, one hundred and forty three dollars:
Us: 7000000000L*1112075143000L = 1 894 569 218 048
Um, wait, we can give everyone over a billion dollars, and only spend a little over two? Overflow is a disaster here.
So, whenever you're calculating an amount of money to transfer, use double
and Math.round
it to get a long
. Then fix up balances (add and subtract both accounts) using long
.
Your economy won't leak, and it will scale up to a quadrillion dollars.
There are more tricky issues--for example, what do you do if you make twenty payments?*--but this should get you started.
* You calculate what one payment is, round to long
; then multiply by 20.0
and check that it's in range; if so, you multiply the payment by 20L
to get the amount deducted from your balance. In general, all transactions must be handled as long
, so you really need to sum up all the individual transactions; you can multiply as a shortcut, but you need to make sure you don't add rounding errors and that you don't overflow, which means you need to check with double
before doing the real calculation with long
.
Currency
type like Delphi's, which uses scaled fixed-point math to give you decimal math without the precision problems inherent to floating-point? \$\endgroup\$BigDecimal
for these kind of problems. \$\endgroup\$