Working with decimals in Elixir

Integers are not enough, and floats are flawed? Decimals to the rescue! A short guide of what’s important when working with decimals in Elixir.

This post is about the Decimal 2.0 module from decimal Hex package.

As with every module in Elixir, running h Module and Module.module_info in IEx is a good place to start.

Among other things, it will tell us that the Decimal module follows the following standards:


Decimals are not part of the stdlib, and so before using the Decimal module, we need to declare is as a dependency in mix.exs:

def deps do
  [{:decimal, "~> 2.0"}]

There was some discussion of inclusion in the standard library, but the Elixir core team is reluctant to add something that works well as a separate module.


Since using decimals is about getting the right precision in the first place, there is a little setting called context, which can be changed on the fly.

Decimal.Context.get/0 revels what’s our current settings:

iex(1)> Decimal.Context.get()
  flags: [],
  precision: 28,
  rounding: :half_up,
  traps: [:invalid_operation, :division_by_zero]

You’ll probably care about the maximum precision of calculations and how rounding is done.

Decimal.Context.set/1 can set different values. It accepts the %Decimal.Context struct.

Creation and conversion

We can create a decimal with new/1 or from_float/1 functions:

iex(2)> Decimal.from_float(20.5)

The other way around, we can use to_integer/1 and to_float/2.

To check something is actually indeed a decimal:

iex(8)> require Decimal
iex(9)> Decimal.is_decimal("2.5")
iex(10)> Decimal.is_decimal(

is_decimal/1 is a macro; therefore, we have to require the Decimal module first.

Addition and subtraction

We can use add/2 to get the sum of two decimals:

iex(1)> Decimal.add(6, 7)
iex(2)> Decimal.add(, Decimal.from_float(7.5))
iex(3)> Decimal.add(, "7.5")

Note that instead of using the from_float/1 function, we can pass a string (“7.5”). We can do that in any of the Decimal functions on this page.

Similarly we can substract a value from a decimal with sub/2 function:

iex(1)> Decimal.sub(, 7)

Multiplication and division

We can multiply with mult/2:

iex(1)> Decimal.mult(,
iex(2)> Decimal.mult("Inf", -1)

And devide with div/2:

iex(1)> Decimal.div(1, 3)
iex(2)> Decimal.div(1, 0)
** (Decimal.Error) division_by_zero
    (decimal) lib/decimal.ex:481: Decimal.div/2

Nobody solved the division by zero, so all you get is Decimal.Error.

Using contexts, we could change the precision to one we care about like this:

iex(1)> Decimal.Context.set(%Decimal.Context{Decimal.Context.get() | precision: 9})
iex(2)> Decimal.div(1, 3)


It’s super important not to expect that comparisons with < and > signs would work with Decimal.

Instead, we can use equal?/2 and compare/2 functions.

Checking equality is easy:

iex(1)> Decimal.equal?(-1, 0)
iex(2)> Decimal.equal?(0, "0.0")

Comparison returns one of :lt, :gt, and :eq atoms:

iex(1)>, 0)
iex(2)>, -1)
iex(3)>, 0)

Alternatively, there are gt?/2, lt?/2, min/2, max/2 functions as well.


I wrote a complete guide on web application deployment. Ruby with Puma, Python with Gunicorn, NGINX, PostgreSQL, Redis, networking, processes, systemd, backups, and all your usual suspects.

More →