Rill v0.13 Reference

Standard library · Numbers

num/decimal

Imported as import "num/decimal" as decimal, its names are then decimal.…. Every signature below is the one the checker infers.

Decimal numbers with a fixed number of places: money, and anything else where 0.1 + 0.2 has to be 0.3.

A Decimal is an integer count of units and a scale, the number of places: Decimal(1250, 2) is 12.50. Adding and comparing align the scales; multiplying keeps every place and rounds only when asked; dividing takes the places to keep and how to round. The count is an Int, so eighteen digits in all is the limit, and a result past it is the wrong number rather than an error — the same as Int itself.

price = decimal.parse("19.99")?
total = decimal.mul(price, decimal.from_int(3))
total                                                  # => 59.97
vat = decimal.round_to(decimal.mul(total, decimal.parse("0.20")?), 2, decimal.HalfEven)
decimal.add(total, vat)                                # => 71.96

Types

Decimal

  • Decimal(units: Int, scale: Int)

Rounding

  • HalfUp
  • HalfEven
  • Down
  • Up

Implementations

  • impl Show(Decimal)
  • impl Ord(Decimal)

Functions

fn from_int(n: Int) -> Decimal

decimal.from_int(12)   # => 12

fn zero() -> Decimal

decimal.zero()   # => 0

fn is_zero(d: Decimal) -> Bool

decimal.is_zero(decimal.parse("0.00")?)   # => true

fn neg(d: Decimal) -> Decimal

decimal.neg(decimal.parse("1.50")?)   # => -1.50

fn abs_of(d: Decimal) -> Decimal

decimal.abs_of(decimal.parse("-1.50")?)   # => 1.50

fn sign(d: Decimal) -> Int

decimal.sign(decimal.parse("-0.01")?)   # => -1

fn round_to(d: Decimal, places: Int, how: Rounding) -> Decimal

The same number at places places — more, exactly; fewer, rounded.

decimal.round_to(decimal.parse("2.345")?, 2, decimal.HalfUp)     # => 2.35
decimal.round_to(decimal.parse("2.345")?, 2, decimal.HalfEven)   # => 2.34
decimal.round_to(decimal.parse("2.349")?, 2, decimal.Down)       # => 2.34
decimal.round_to(decimal.parse("2.341")?, 2, decimal.Up)         # => 2.35
decimal.round_to(decimal.parse("2.5")?, 3, decimal.HalfUp)       # => 2.500

fn add(a: Decimal, b: Decimal) -> Decimal

decimal.add(decimal.parse("0.1")?, decimal.parse("0.2")?)   # => 0.3

fn sub(a: Decimal, b: Decimal) -> Decimal

decimal.sub(decimal.parse("1.00")?, decimal.parse("0.75")?)   # => 0.25

fn mul(a: Decimal, b: Decimal) -> Decimal

Exact: the places add up. Round afterwards where a money amount wants its two.

decimal.mul(decimal.parse("1.5")?, decimal.parse("1.5")?)   # => 2.25

fn div(a: Decimal, b: Decimal, places: Int, how: Rounding) -> Result(Decimal, Str)

a / b to places places, rounded as asked; Err on a zero divisor.

decimal.div(decimal.from_int(1), decimal.from_int(3), 4, decimal.HalfUp)   # => Ok(0.3333)
decimal.div(decimal.from_int(1), decimal.zero(), 2, decimal.HalfUp)         # => Err(division by zero)

fn cmp(a: Decimal, b: Decimal) -> Int

decimal.cmp(decimal.parse("1.10")?, decimal.parse("1.1")?)   # => 0

fn eq(a: Decimal, b: Decimal) -> Bool

decimal.eq(decimal.parse("1.10")?, decimal.parse("1.1")?)   # => true

fn as_float(d: Decimal) -> Float

decimal.as_float(decimal.parse("12.50")?)   # => 12.5

fn text(d: Decimal) -> Str

-12.50 for Decimal(-1250, 2); a scale of zero prints no point.

decimal.text(decimal.Decimal(-1250, 2))   # => -12.50
decimal.text(decimal.Decimal(7, 0))       # => 7

fn parse(s: Str) -> Result(Decimal, Str)

12, 12.5, -0.75, +3.00: digits with at most one point.

decimal.parse("+3.00")   # => Ok(3.00)
decimal.parse("1.2.3")   # => Err(`1.2.3` has two points)

Tests

  • test_text_and_parse
  • test_arithmetic
  • test_rounding