In ex_money (I’m the author) this is one reason for using decimal. Rounding to the currencies precision (and for some currencies and usages to a multiple) is deferred until the latest possible moment.
Using your example, its perfectly acceptable to have arbitrary precision on money arithmetic. This is relevant not only at the gas pump but in financial trading as well. So maybe I have a value $3.45678. Perfectly OK and in factor in financial instruments a requirement to at least 7 digits if I recall (it may not be that exactly).
Another example is when doing currency conversion - higher precision is desirable.
The at some point the result is credited to a bank account which means applying the appropriate rounding. There are at least three considerations:
-
Rounding to the right number of decimal digits. 0,1,2, 3 and 4 digits are in use with different currencies around the world.
-
Use the right rounding mode. Typically you would use bankers rounding which, in the
Decimallibrary is mode:half_evenand is also the default inex_money. -
Apply any necessary
round nearestfor the currency. For example, in Australia there is no cash amount below 5c so you need to round to the nearest 5c for cash amounts. Similar for the Swiss franc.
Last example. Lets say you have $5.23 and you want to split it 3 ways.
hex> m = Money.new(:USD, "5.23")
#Money<:USD, 5.23>
iex> Money.div m, 3
{:ok, #Money<:USD, 1.743333333333333333333333333>}
iex> Money.div!(m, 3) |> Money.round
#Money<:USD, 1.74>
iex> Money.div!(m, 3) |> Money.round |> Money.mult!(3)
#Money<:USD, 5.22>
Where did the last cent go? Thats the reason I implemented Money.split/2.
iex> Money.split(m, 3)
{#Money<:USD, 1.74>, #Money<:USD, 0.01>}
Which allows you to decide what you do with the amount left over. Oh, and Money.split/2 takes an arbitrary precision money amount, rounds it correctly and does the math.
I don’t recommend using integers for money amounts for all of these reasons.






















