March Docs

Decimal

Decimal module: fixed-point decimal arithmetic for financial math.

Representation: Decimal(coefficient, scale) where coefficient : Int — the unscaled integer value scale : Int — number of decimal places (>= 0)

Examples: 1.23 = Decimal(123, 2) -0.01 = Decimal(-1, 2) 100 = Decimal(100, 0)

All arithmetic normalizes to the higher scale of the two operands, avoiding loss of precision. Round uses half-up (0.5 rounds away from zero).

Interface implementations: impl Eq(Decimal) — eq/2 impl Ord(Decimal) — compare/2 impl Show(Decimal) — show/1

Types

ptypeDecimalDecimal = Decimal(Int, Int)#

Functions

fnabsabs(d : Decimal) : Decimal#

Returns the absolute value, keeping the scale.

Examples

march> Decimal.to_string(Decimal.abs(Decimal.from_string("-0.50")))
"0.50"
fnaddadd(a : Decimal, b : Decimal) : Decimal#

Adds two Decimals. Result has the larger of the two scales.

Examples

march> Decimal.to_string(Decimal.add(Decimal.from_string("0.1"), Decimal.from_string("0.25")))
"0.35"
march> Decimal.to_string(Decimal.add(Decimal.from_string("1.50"), Decimal.from_string("-1.5")))
"0.00"
fncoefficientcoefficient(d : Decimal) : Int#

Returns the unscaled Int coefficient.

Examples

march> Decimal.coefficient(Decimal.from_string("-3.140"))
-3140
fncomparecompare(a : Decimal, b : Decimal) : Int#

Compares two Decimals by value (scale-independent). Returns -1, 0, or 1.

Examples

march> Decimal.compare(Decimal.from_string("1.10"), Decimal.from_string("1.1"))
0
march> Decimal.compare(Decimal.from_string("-0.5"), Decimal.from_string("0.25"))
-1
fndivdiv(a : Decimal, b : Decimal, precision : {Int | _ >= 0}) : Decimal#

Divides a by b, keeping precision extra decimal places beyond the scale of a (the result scale is scale(a) + precision), truncating toward zero. Panics if b is zero.

For half-up rounding (e.g. money arithmetic where 0.5 should round away from zero), use div_round instead.

Examples

march> Decimal.to_string(Decimal.div(Decimal.from_int(1), Decimal.from_int(3), 2))
"0.33"
march> Decimal.to_string(Decimal.div(Decimal.from_string("1.00"), Decimal.from_int(3), 2))
"0.3333"
march> Decimal.to_string(Decimal.div(Decimal.from_int(-7), Decimal.from_int(2), 0))
"-3"
fndiv_rounddiv_round(a : Decimal, b : Decimal, precision : Int) : Decimal#

Divides a by b to exactly precision decimal places using half-up rounding: 0.5 rounds away from zero. Panics if b is zero.

Equivalent to round(div(a, b, precision + 1), precision). Unlike div, the result scale is precision regardless of the scale of a.

Examples

march> Decimal.to_string(Decimal.div_round(Decimal.from_string("2.00"), Decimal.from_int(3), 2))
"0.67"
march> Decimal.to_string(Decimal.div_round(Decimal.from_int(-7), Decimal.from_int(2), 0))
"-4"
fneqeq(a : Decimal, b : Decimal) : Bool#

Returns true if two Decimals have the same value, regardless of scale (also available as ==).

Examples

march> Decimal.eq(Decimal.from_string("1.0"), Decimal.from_string("1.00"))
true
march> Decimal.eq(Decimal.from_string("1.01"), Decimal.from_int(1))
false
fnfrom_intfrom_int(n : Int) : Decimal#

Creates a Decimal from a native Int (scale 0).

Examples

march> Decimal.to_string(Decimal.from_int(-42))
"-42"
fnfrom_int_scaledfrom_int_scaled(n : Int, scale : Int) : Decimal#

Creates a Decimal from a native Int coefficient and a scale, i.e. the value n / 10^scale. A negative scale is clamped to 0.

Examples

march> Decimal.to_string(Decimal.from_int_scaled(12345, 2))
"123.45"
march> Decimal.to_string(Decimal.from_int_scaled(5, 3))
"0.005"
march> Decimal.to_string(Decimal.from_int_scaled(5, -3))
"5"
fnfrom_stringfrom_string(s : String) : Decimal#

Creates a Decimal from a string like "1.23", "-0.5", "100". The scale is the number of characters after the first .; a leading +, or an empty integer part (".5"), is accepted. Input that does not parse yields a zero coefficient (no error is reported): "abc" gives 0, and "1.2.3" gives 0.000.

Examples

march> Decimal.to_string(Decimal.from_string("-0.05"))
"-0.05"
march> Decimal.scale(Decimal.from_string("1.230"))
3
march> Decimal.to_string(Decimal.from_string(".5"))
"0.5"
march> Decimal.is_zero(Decimal.from_string("abc"))
true
fngtgt(a : Decimal, b : Decimal) : Bool#

Returns true if a > b.

Examples

march> Decimal.gt(Decimal.from_string("-1.5"), Decimal.from_int(-2))
true
march> Decimal.gt(Decimal.from_string("2.0"), Decimal.from_int(2))
false
fnis_zerois_zero(d : Decimal) : Bool#

Returns true if the Decimal is zero (at any scale).

Examples

march> Decimal.is_zero(Decimal.from_string("0.000"))
true
march> Decimal.is_zero(Decimal.from_string("0.001"))
false
fnltlt(a : Decimal, b : Decimal) : Bool#

Returns true if a < b.

Examples

march> Decimal.lt(Decimal.from_string("0.09"), Decimal.from_string("0.1"))
true
fnmulmul(a : Decimal, b : Decimal) : Decimal#

Multiplies two Decimals exactly. Result scale is the sum of the two scales.

Examples

march> Decimal.to_string(Decimal.mul(Decimal.from_string("1.5"), Decimal.from_string("-0.25")))
"-0.375"
march> Decimal.to_string(Decimal.mul(Decimal.from_string("2.50"), Decimal.from_int(4)))
"10.00"
fnroundround(d : Decimal, places : Int) : Decimal#

Rounds a Decimal to places decimal places using half-up rounding (0.5 rounds away from zero). A Decimal whose scale is already places or less is returned unchanged (it is not padded).

Examples

march> Decimal.to_string(Decimal.round(Decimal.from_string("2.345"), 2))
"2.35"
march> Decimal.to_string(Decimal.round(Decimal.from_string("-2.345"), 2))
"-2.35"
march> Decimal.to_string(Decimal.round(Decimal.from_string("2.344"), 2))
"2.34"
march> Decimal.to_string(Decimal.round(Decimal.from_string("1.5"), 3))
"1.5"
fnscalescale(d : Decimal) : Int#

Returns the scale (number of decimal places) of a Decimal.

Examples

march> Decimal.scale(Decimal.from_string("3.140"))
3
fnsubsub(a : Decimal, b : Decimal) : Decimal#

Subtracts b from a. Result has the larger of the two scales.

Examples

march> Decimal.to_string(Decimal.sub(Decimal.from_string("1"), Decimal.from_string("0.01")))
"0.99"
march> Decimal.to_string(Decimal.sub(Decimal.from_string("0.5"), Decimal.from_string("2")))
"-1.5"
fnto_stringto_string(d : Decimal) : String#

Converts a Decimal to its string representation, always showing exactly scale fractional digits (e.g. "1.23", "-0.50"); a scale-0 Decimal has no decimal point.

Examples

march> Decimal.to_string(Decimal.from_int_scaled(-50, 2))
"-0.50"
march> Decimal.to_string(Decimal.from_int_scaled(7, 0))
"7"