# `Bourse.Precise`
[🔗](https://github.com/ZenHive/bourse/blob/main/lib/bourse/precise.ex#L1)

Money-exact decimal string arithmetic for response normalization.

The contract is **string in, string out**: operands and results are decimal
strings, never floats. A computed field such as trade
`cost = amount × price` therefore remains `"10.4727"` for
`"0.0001" × "104727.0"` instead of acquiring binary-float drift.

Only the operations the response-normalization layer needs (`add`, `mul`,
`div`) are ported.

## Semantics

- A `nil` operand returns `nil`.
- `string_div/3` truncates **toward zero** to `precision` decimal places
  using `Decimal` `:down` rounding. Default precision is 18; `precision` may
  be zero or negative.
- Division by zero returns `nil`.
- Results are reduced (trailing zeros trimmed) and never scientific notation.

# `string_add`

```elixir
@spec string_add(String.t() | nil, String.t() | nil) :: String.t() | nil
```

Adds two decimal strings, returning a reduced decimal string (or `nil`).

# `string_div`

```elixir
@spec string_div(String.t() | nil, String.t() | nil, integer()) :: String.t() | nil
```

Divides two decimal strings, truncating toward zero to `precision` decimal
places. Returns a reduced decimal string, or `nil` on a `nil` operand or a
zero divisor.

    iex> Bourse.Precise.string_div("69696900000", "1e8")
    "696.969"
    iex> Bourse.Precise.string_div("0.00000002", "69696900000", 19)
    "0.0000000000000000002"
    iex> Bourse.Precise.string_div("5", "0")
    nil

# `string_mul`

```elixir
@spec string_mul(String.t() | nil, String.t() | nil) :: String.t() | nil
```

Multiplies two decimal strings, returning a reduced decimal string (or `nil`).

    iex> Bourse.Precise.string_mul("0.0001", "104727.0")
    "10.4727"
    iex> Bourse.Precise.string_mul("0.00000002", "69696900000")
    "1393.938"
    iex> Bourse.Precise.string_mul(nil, "5")
    nil

---

*Consult [api-reference.md](api-reference.md) for complete listing*
