# Decimal `==` is not value equality

`Decimal.new("1.0")` and `Decimal.new("1.00")` represent the same number, but Elixir's `==` says they are different:

```elixir
a = Decimal.new("1.0")
b = Decimal.new("1.00")
c = Decimal.new("1.0")

a == b
# => false

a == c
# => true

Decimal.equal?(a, b)
# => true

Decimal.compare(a, b)
# => :eq

a in [b]
# => false

Enum.uniq([a, b])
# => [Decimal.new("1.0"), Decimal.new("1.00")]
```

`a == c` is `true` because `c` was built from the exact same string as `a`, so the two structs are field-for-field identical. `a == b` is `false` even though `a` and `b` are mathematically equal, because they carry different precision.

## Why

`Decimal` is a plain struct:

```elixir
%Decimal{sign: 1, coef: 10, exp: -1}
```

`==` in Elixir doesn't know anything about decimal arithmetic. It falls back to Erlang term comparison, which compares the struct like any other map: by its fields. `Decimal.new("1.0")` stores `coef: 10, exp: -1` (1.0 = 10 × 10⁻¹), while `Decimal.new("1.00")` stores `coef: 100, exp: -2` (1.00 = 100 × 10⁻²). Same value, different coefficient and exponent, so the terms don't match.

This is exactly why `in`, `Enum.member?/2`, and `Enum.uniq/1` all misbehave — they use `==` under the hood. `a in [b]` is `false`, and `Enum.uniq([a, b])` keeps both entries instead of collapsing them to one. The same trap applies to using a `Decimal` as a bare map key: `%{a => :x, b => :y}` keeps two entries, not one, because map key matching also uses term equality.

`Enum.sort/1` doesn't crash, but it doesn't tie-break on numeric value either — it orders by the same struct-field comparison, so equal-valued decimals with different precision can still end up in a specific, coefficient-driven order rather than being genuinely tied.

## Use the right function

- `Decimal.equal?/2` for equality that respects numeric value, not representation.
- `Decimal.compare/2` for ordering — returns `:lt`, `:eq`, or `:gt`.
- `Decimal.lt?/2`, `Decimal.gt?/2`, `Decimal.lte?/2`, `Decimal.gte?/2` for direct comparisons.

None of these care whether the operands came from `"1.0"` or `"1.00"` — they compare the actual numbers.

This matters most for money and other exact-decimal fields loaded from a database or parsed from user input, where trailing zeros routinely differ between two values that should be treated as equal.

[Decimal.equal?/2 docs](https://hexdocs.pm/decimal/Decimal.html#equal?/2)


---

Created by: almirsarajcic
Date: August 29, 2026
URL: https://elixirdrops.net/d/mo82YVG9
