# 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:

## Installation

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"}]
end
``````

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.

## Contexts

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()
%Decimal.Context{
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(1)> Decimal.new(55)
#Decimal<55>
iex(2)> Decimal.from_float(20.5)
#Decimal<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
Decimal
iex(9)> Decimal.is_decimal("2.5")
false
iex(10)> Decimal.is_decimal(Decimal.new(2))
true
``````

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

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

``````iex(1)> Decimal.add(6, 7)
#Decimal<13>
#Decimal<13.5>
#Decimal<13.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(Decimal.new(6), 7)
#Decimal<-1>
``````

## Multiplication and division

We can multiply with `mult/2`:

``````iex(1)> Decimal.mult(Decimal.new(5), Decimal.new(3))
#Decimal<15>
iex(2)> Decimal.mult("Inf", -1)
#Decimal<-Infinity>
``````

And devide with `div/2`:

``````iex(1)> Decimal.div(1, 3)
#Decimal<0.3333333333333333333333333333>
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})
:ok
iex(2)> Decimal.div(1, 3)
#Decimal<0.333333333>
``````

## Comparison

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)
false
iex(2)> Decimal.equal?(0, "0.0")
true
``````

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

``````iex(1)> Decimal.compare(-1, 0)
:lt
iex(2)> Decimal.compare(0, -1)
:gt
iex(3)> Decimal.compare(0, 0)
:eq
``````

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

#### ← IT'S OUT NOW 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.