finanza/decimal

Fixed-point decimal arithmetic with explicit rounding.

A Decimal is represented internally as a signed integer coefficient and an exponent:

value = coefficient × 10^exponent

Decimal is pub opaque; construct values through from_int, from_string, or new, and inspect them through coefficient and exponent.

Precision boundary

On the JavaScript target, Gleam’s Int is a 64-bit IEEE 754 number, so coefficients are limited to ±(2^53 − 1) = 9_007_199_254_740_991. Operations that would produce a larger coefficient return PrecisionExceeded. On the Erlang target, integers are arbitrary precision; the same bound is enforced anyway so behaviour is consistent across targets.

Types

Errors returned by arithmetic operations.

pub type ArithmeticError {
  DivisionByZero
  PrecisionExceeded
}

Constructors

  • DivisionByZero

    The right-hand operand of a divide was zero.

  • PrecisionExceeded

    The result would not fit in the supported precision window (±9_007_199_254_740_991). Reduce intermediate precision with round and retry.

Fixed-point decimal value. Construct via from_int, from_string, or new.

pub opaque type Decimal

Errors returned by from_string.

pub type ParseError {
  EmptyInput
  InvalidCharacter(char: String, position: Int)
  MultipleDecimalPoints
  MultipleSigns
  NoDigits
  ParsedValueTooLarge
}

Constructors

  • EmptyInput

    The input was the empty string or contained only whitespace.

  • InvalidCharacter(char: String, position: Int)

    The input contained a character that is not a digit, sign, or decimal point.

  • MultipleDecimalPoints

    The input contained more than one decimal point.

  • MultipleSigns

    The input contained more than one sign character.

  • NoDigits

    The input contained no digits (e.g. "+", ".", "-.").

  • ParsedValueTooLarge

    The parsed coefficient would exceed ±9_007_199_254_740_991 (the JavaScript-safe integer ceiling). Such a value cannot be represented faithfully on the JavaScript target; rather than silently corrupt it (and emit unparseable strings from to_string), parsing fails fast.

Values

pub fn absolute(d d: Decimal) -> Decimal

Absolute value. Always safe.

pub fn add(
  a a: Decimal,
  b b: Decimal,
) -> Result(Decimal, ArithmeticError)

Add two decimals.

pub fn coefficient(d d: Decimal) -> Int

The signed coefficient component.

pub fn compare(a a: Decimal, b b: Decimal) -> order.Order

Total ordering. Two values with the same numeric value compare as equal even when their exponents differ.

pub fn divide(
  a a: Decimal,
  b b: Decimal,
  digits digits: Int,
  mode mode: rounding.Mode,
) -> Result(Decimal, ArithmeticError)

Divide a by b, returning a result rounded to digits decimal places using mode.

Returns DivisionByZero when b is zero, or PrecisionExceeded when the intermediate representation would exceed ±9_007_199_254_740_991.

pub fn equal(a a: Decimal, b b: Decimal) -> Bool

Equality test by numeric value, not by representation. equal(new(coefficient: 100, exponent: -2), one()) is True.

pub fn exponent(d d: Decimal) -> Int

The exponent component (base 10).

pub fn format(
  d d: Decimal,
  thousands thousands: String,
  decimal_separator decimal_separator: String,
) -> String

Render a Decimal with custom thousands and decimal separators.

format(d, thousands: ",", decimal_separator: ".")  // "1,234.56"
format(d, thousands: ".", decimal_separator: ",")  // "1.234,56" (German)
format(d, thousands: "",  decimal_separator: ".")  // "1234.56"

Equivalent to to_string when thousands is empty and decimal_separator is ".".

pub fn from_int(n n: Int) -> Decimal

Build a Decimal from an integer.

pub fn from_string(
  input input: String,
) -> Result(Decimal, ParseError)

Parse a decimal from a string. Accepts an optional leading + or -, decimal digits, and at most one . separator. Scientific notation is not supported.

from_string("3.14")    // Ok(Decimal with coefficient=314, exponent=-2)
from_string("-0.5")    // Ok(Decimal with coefficient=-5, exponent=-1)
from_string("")        // Error(EmptyInput)
from_string("1.2.3")   // Error(MultipleDecimalPoints)
pub fn is_negative(d d: Decimal) -> Bool

Test for a strictly negative decimal.

pub fn is_positive(d d: Decimal) -> Bool

Test for a strictly positive decimal.

pub fn is_zero(d d: Decimal) -> Bool

Test for the zero decimal.

pub fn multiply(
  a a: Decimal,
  b b: Decimal,
) -> Result(Decimal, ArithmeticError)

Multiply two decimals.

pub fn negate(d d: Decimal) -> Decimal

Negate the value. Always safe (the coefficient sign flips but magnitude does not change).

pub fn new(
  coefficient coefficient: Int,
  exponent exponent: Int,
) -> Decimal

Build a Decimal directly from a coefficient and exponent.

new(coefficient: 1234, exponent: -2) represents 12.34.

pub fn one() -> Decimal

The decimal value 1.

pub fn rescale(
  d d: Decimal,
  target_exponent target_exponent: Int,
  mode mode: rounding.Mode,
) -> Result(Decimal, ArithmeticError)

Force the decimal to a specific exponent. When the new exponent is finer (smaller), the coefficient grows by zero-padding (may overflow). When the new exponent is coarser (larger), digits are dropped using mode.

pub fn round(
  d d: Decimal,
  digits digits: Int,
  mode mode: rounding.Mode,
) -> Decimal

Round to digits decimal places. When the input is already at equal or coarser precision, the original Decimal is returned unchanged (no zero-padding); call rescale to force a target exponent.

pub fn subtract(
  a a: Decimal,
  b b: Decimal,
) -> Result(Decimal, ArithmeticError)

Subtract b from a.

pub fn to_string(d d: Decimal) -> String

Render a Decimal as a plain string. Preserves the encoded exponent (new(coefficient: 100, exponent: -2) renders as "1.00", not "1").

pub fn truncate(d d: Decimal, digits digits: Int) -> Decimal

Truncate to digits decimal places (rounding toward zero). When the input is already at equal or coarser precision, the original Decimal is returned unchanged.

pub fn zero() -> Decimal

The decimal value 0.

Search Document