# BigDecimal

`BigDecimal` represents a decimal number with arbitrary precision. It exists to
avoid the rounding errors of JavaScript's binary floating-point `number`, where
`0.1 + 0.2 === 0.30000000000000004`. When you are working with money, financial
calculations, or any domain where exactness matters, use `BigDecimal` instead of
`number`. A `BigDecimal` stores an arbitrary-precision integer (`value`, a
`bigint`) together with a `scale` (the number of digits after the decimal
point).

```ts
import { BigDecimal } from "effect"

// Floating point: wrong
console.log(0.1 + 0.2) // 0.30000000000000004

// BigDecimal: exact
const sum = BigDecimal.sum(
  BigDecimal.fromStringUnsafe("0.1"),
  BigDecimal.fromStringUnsafe("0.2")
)
console.log(BigDecimal.format(sum)) // "0.3"
```

`fromStringUnsafe` parses a decimal literal exactly, and `BigDecimal.sum` adds
two values with no loss of precision. `BigDecimal.format` renders the result
back to a string.

## Creating a BigDecimal

The safest constructors return an `Option`, because not every input is a valid
decimal:

```ts
import { BigDecimal } from "effect"

// From a string — None if the string is not a valid number
const fromStr = BigDecimal.fromString("123.45")   // Some(123.45)
const invalid = BigDecimal.fromString("nope")     // None

// From a number — None if not finite (NaN / Infinity)
const fromNum = BigDecimal.fromNumber(123.45)
```

When you control the input (e.g. a hard-coded literal) the `*Unsafe` variants
return a `BigDecimal` directly and throw on bad input:

```ts
import { BigDecimal } from "effect"

const price = BigDecimal.fromStringUnsafe("19.99")
```

<small>Note the v4 convention: the throwing variant carries the `Unsafe` suffix
(`fromStringUnsafe`), while the total version returns an `Option`
(`fromString`).</small>

## Arithmetic

`sum`, `subtract`, and `multiply` are exact and return a `BigDecimal`. Division
returns an `Option`, because dividing by zero has no result:

```ts
import { BigDecimal, Option } from "effect"

const a = BigDecimal.fromStringUnsafe("10.5")
const b = BigDecimal.fromStringUnsafe("3")

console.log(BigDecimal.format(BigDecimal.sum(a, b)))       // "13.5"
console.log(BigDecimal.format(BigDecimal.subtract(a, b)))  // "7.5"
console.log(BigDecimal.format(BigDecimal.multiply(a, b)))  // "31.5"

// divide is partial: None when dividing by zero
const quotient = BigDecimal.divide(a, b)
console.log(Option.map(quotient, BigDecimal.format))
// { _id: 'Option', _tag: 'Some', value: '3.5' }

console.log(BigDecimal.divide(a, BigDecimal.fromStringUnsafe("0")))
// { _id: 'Option', _tag: 'None' }
```

## Rounding

`BigDecimal.round` rounds to a given number of decimal places using a rounding
mode:

```ts
import { BigDecimal } from "effect"

const value = BigDecimal.fromStringUnsafe("3.14159")

// Round to 2 decimal places
console.log(BigDecimal.format(BigDecimal.round(value, { scale: 2 })))
// "3.14"
```

## Comparison

Use `BigDecimal.equals` for value equality. Because comparison is numeric,
values with different scales but the same magnitude are equal:

```ts
import { BigDecimal } from "effect"

console.log(
  BigDecimal.equals(
    BigDecimal.fromStringUnsafe("1.0"),
    BigDecimal.fromStringUnsafe("1.00")
  )
) // true
```

## A worked example: money

Modelling currency is the canonical use case. Keeping amounts as `BigDecimal`
guarantees totals add up to the cent.

```ts
import { BigDecimal } from "effect"

const lineItems = ["19.99", "5.49", "12.00"].map(BigDecimal.fromStringUnsafe)

// sumAll folds a collection without intermediate rounding
const subtotal = BigDecimal.sumAll(lineItems)

const taxRate = BigDecimal.fromStringUnsafe("0.08")
// Round the tax to 2 decimal places (cents)
const tax = BigDecimal.round(BigDecimal.multiply(subtotal, taxRate), { scale: 2 })
const total = BigDecimal.sum(subtotal, tax)

console.log(BigDecimal.format(subtotal)) // "37.48"
console.log(BigDecimal.format(total))    // subtotal plus rounded tax, exact to the cent
```

For validating and persisting `BigDecimal` values at the edges of your system,
the [Schema](https://effect.plants.sh/schema/) module provides matching codecs.