How to handle small amounts/rates/fees when using an integer (e.g. like Money)

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:

  1. Rounding to the right number of decimal digits. 0,1,2, 3 and 4 digits are in use with different currencies around the world.

  2. Use the right rounding mode. Typically you would use bankers rounding which, in the Decimal library is mode :half_even and is also the default in ex_money.

  3. Apply any necessary round nearest for 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.