README.md

# dee

[![Package Version](https://img.shields.io/hexpm/v/dee)](https://hex.pm/packages/dee)
[![Hex Docs](https://img.shields.io/badge/hex-docs-ffaff3)](https://hexdocs.pm/dee/)
[![CI](https://github.com/kantox/dee/actions/workflows/test.yml/badge.svg)](https://github.com/kantox/dee/actions/workflows/test.yml)

Arbitrary precision decimal arithmetic for Gleam. A pure Gleam implementation of [Elixir's Decimal](https://hexdocs.pm/decimal) library that works identically on both Erlang and JavaScript targets.

```gleam
import dee/decimal

pub fn main() {
  // Floating point: 0.1 + 0.2 = 0.30000000000000004
  // Decimal: 0.1 + 0.2 = 0.3
  let assert Ok(a) = decimal.from_string("0.1")
  let assert Ok(b) = decimal.from_string("0.2")
  let sum = decimal.add(a, b)
  decimal.to_string(sum)
  // -> "0.3"
}
```

## Installation

```sh
gleam add dee
```

## Features

- **Elixir Decimal compatible**: API and behavior aligned with [Elixir's Decimal](https://hexdocs.pm/decimal) as the reference implementation
- **Arbitrary precision**: No overflow or precision loss for any size numbers
- **Cross-platform**: Works identically on Erlang and JavaScript targets
- **Pure Gleam**: Single codebase, no FFI, no Elixir dependency

## Quick Start

```gleam
import dee/decimal.{type Decimal}

pub fn calculate_tax(price: Decimal, rate: Decimal) -> Decimal {
  decimal.multiply(price, rate)
  |> decimal.round(2, decimal.HalfUp)
}

pub fn main() {
  let assert Ok(price) = decimal.from_string("19.99")
  let assert Ok(tax_rate) = decimal.from_string("0.0825")

  let tax = calculate_tax(price, tax_rate)
  decimal.to_string(tax)
  // -> "1.65"
}
```

## Elixir Decimal Compatibility

This library uses [Elixir's Decimal](https://hexdocs.pm/decimal) as its reference implementation. The API, arithmetic behavior, rounding modes, and special value handling are designed to match. Code ported between the two libraries should produce identical results.

### Why Pure Gleam Instead of FFI?

Using FFI to Elixir's Decimal would only work on the Erlang target. A pure Gleam implementation gives us a single codebase that works identically on both Erlang and JavaScript targets, with no Elixir dependency.

Arbitrary precision is achieved via the [`bigi`](https://hexdocs.pm/bigi/) library, which uses native BEAM integers on Erlang and native `BigInt` on JavaScript.

### Interoperability

Both libraries use the same mathematical representation (`sign * coefficient * 10^exponent`) with the same semantics for NaN, Infinity, and signed zero. The default context matches Elixir's: 28 digits of precision with HalfUp rounding.

While the runtime representations differ (Gleam opaque type vs Elixir struct), converting between them on the BEAM is straightforward via `to_string`/`from_string` or by mapping component fields through `from_parts`, `sign`, and `exponent`.

## Development

```sh
gleam test --target erlang      # Run tests on Erlang
gleam test --target javascript  # Run tests on JavaScript
gleam docs build                # Build documentation
```

## Further Documentation

Full API documentation is available at [https://hexdocs.pm/dee](https://hexdocs.pm/dee).