Skip to content

Releases: ericmj/decimal

v3.1.0

08 May 17:37

Choose a tag to compare

Enhancements

  • Decimal.new/2 now accepts an optional opts keyword list and
    forwards it to Decimal.parse/2, allowing callers to override
    :max_digits and :max_exponent when constructing a decimal from
    a string.

Bug fixes

  • Fix infinite loop in Decimal.to_integer/1 when the coefficient is
    zero and the exponent is negative (e.g. Decimal.new("0.0")). Such
    values now correctly convert to the integer 0.

v2.4.1

08 May 17:39

Choose a tag to compare

Bug fixes

  • Fix infinite loop in Decimal.to_integer/1 when the coefficient is
    zero and the exponent is negative (e.g. Decimal.new("0.0")). Such
    values now correctly convert to the integer 0.

v3.0.0

07 May 13:51

Choose a tag to compare

Note on the new defaults

The new decimal128 defaults are more than sufficient for currency and
other real-world numeric use cases. With precision: 34 and a scale of
2 (two digits after the decimal point for cents), values from 0.00 up
to roughly 99_999_999_999_999_999_999_999_999_999_999.99 (~10³², 100
nonillion) round-trip without rounding. Most upgrades from 2.x require
no code changes.

Security

  • Make the v2.4.0 mitigations for CVE-2026-32686 the default. The
    default Decimal.Context and the public parse, cast, and to_string
    functions now follow IEEE 754 decimal128 limits, rejecting inputs
    such as 1e1000000000 without materializing them.

Breaking changes

  • Decimal.Context defaults change from precision 28 and unbounded
    emax/emin to decimal128 values: precision: 34, emax: 6_144,
    emin: -6_143. Operation results whose adjusted exponent leaves that
    band signal overflow or underflow.
  • Decimal.parse/1 and Decimal.cast/1 reject inputs whose digit count
    exceeds 34 (decimal128 precision) or whose absolute exponent exceeds
    6_144 (decimal128 emax). Use parse/2 / cast/2 with
    max_digits: :infinity and max_exponent: :infinity to restore
    unbounded behavior.
  • Decimal.parse/2 and Decimal.cast/2 default :max_digits to 34
    and :max_exponent to 6_144 when not specified.
  • Decimal.to_string/2 and Decimal.to_string/3 raise ArgumentError
    when the rendered output would exceed 6_178 digit characters
    (precision + emax — the worst-case :normal width of any in-range
    decimal128 value). Inspect, String.Chars, and JSON.Encoder
    protocol implementations pass max_digits: :infinity so debug output
    always succeeds.

v2.4.0

07 May 13:41

Choose a tag to compare

Security

  • Mitigate exponent amplification (CVE-2026-32686).
    Compact inputs such as 1e1000000 could force multi-second expansions
    during arithmetic, parsing, normalization, comparison, or formatting.
    Decimal.add/2 and Decimal.sub/2 now scale operands to precision + 2
    digits with a sticky bit instead of materializing the full coefficient.

Enhancements

  • Add :max_digits and :max_exponent options to Decimal.parse/2 and
    Decimal.cast/2 to reject pathological inputs without expansion
  • Add :max_digits option to Decimal.to_string/3 to cap formatted output
    before materialization
  • Add :emax and :emin fields to Decimal.Context for IBM General Decimal
    Arithmetic-style overflow and underflow signaling
  • Optimize hot paths for large decimals: coef_length, normalize,
    to_integer, integer?, parsing, and large-coefficient string formatting

v2.3.0

28 Apr 11:07

Choose a tag to compare

v2.2.0

28 Apr 11:07

Choose a tag to compare

  • Add Decimal.gte?/2 and Decimal.lte?/2
  • Add Decimal.compare/3 and Decimal.eq?/3 with threshold as parameter

v2.1.1

28 Apr 11:06

Choose a tag to compare

Decimal v2.1 requires Elixir v1.8+.

Bug fixes

  • Fix Decimal.compare/2 when comparing against 0

v2.1.0

28 Apr 11:06

Choose a tag to compare

Decimal v2.1 requires Elixir v1.8+.

Enhancements

  • Improve error message from Decimal.to_integer/1 during precision loss
  • Inspect protocol implementation returns strings in the Decimal.new(...) format
  • Add Decimal.scale/1
  • Optimize Decimal.compare/2 for numbers with large exponents

Bug fixes

  • Fix Decimal.integer?/1 spec
  • Fix Decimal.integer?/1 check on 0 with >1 significant digits

v2.0.0

08 Sep 14:33

Choose a tag to compare

Decimal v2.0 requires Elixir v1.2+.

Enhancements

  • Add Decimal.integer?/1

Breaking changes

  • Change Decimal.compare/2 to return :lt | :eq | :gt
  • Change Decimal.cast/1 to return {:ok, t} | :error
  • Change Decimal.parse/1 to return {t, binary} | :error
  • Remove :message and :result fields from Decimal.Error
  • Remove sNaN
  • Rename qNaN to NaN
  • Remove deprecated support for floats in Decimal.new/1
  • Remove deprecated Decimal.minus/1
  • Remove deprecated Decimal.plus/1
  • Remove deprecated Decimal.reduce/1
  • Remove deprecated Decimal.with_context/2, Decimal.get_context/1, Decimal.set_context/1,
    and Decimal.update_context/1
  • Remove deprecated Decimal.decimal?/1

v1.9.0

08 Sep 14:32

Choose a tag to compare

Enhancements

  • Add Decimal.negate/1
  • Add Decimal.apply_context/1
  • Add Decimal.normalize/1
  • Add Decimal.Context.with/2, Decimal.Context.get/1, Decimal.Context.set/2,
    and Decimal.Context.update/1
  • Add Decimal.is_decimal/1

Deprecations

  • Deprecate Decimal.minus/1 in favour of the new Decimal.negate/1
  • Deprecate Decimal.plus/1 in favour of the new Decimal.apply_context/1
  • Deprecate Decimal.reduce/1 in favour of the new Decimal.normalize/1
  • Deprecate Decimal.with_context/2, Decimal.get_context/1, Decimal.set_context/2,
    and Decimal.update_context/1 in favour of new functions on the Decimal.Context module
  • Deprecate Decimal.decimal?/1 in favour of the new Decimal.is_decimal/1