No matching definitions.

tur/rational

stdlib/rational.tur

exact Rational arithmetic over an int64 num/den pair.

Since: Phase N1 (numeric-tower-rational-complex-plan)

defdata

ArithError

(defdata ArithError :copy (DivByZero) (Overflow))

the failure modes of exact integer/rational arithmetic.

Since: Phase N1

defstruct

Rational

(defstruct Rational :copy [num : int den : int])

an exact num/den pair over int64.

Since: Phase N1

defn

int/abs

(int/abs [x : int] :)

absolute value of an int.

xthe integer

|x|. `int/abs` of the int64 minimum is not representable and wraps back to itself, matching two's-complement negation.

(int/abs -7)  ; => 7

Since: Phase N1

defn

int/gcd

(int/gcd [a : int b : int] :)

greatest common divisor of two non-negative ints (Euclid).

afirst value, >= 0
bsecond value, >= 0

gcd(a, b); gcd(0, 0) is 0.

(int/gcd 6 8)  ; => 2

Since: Phase N1

defn

int/max-value

(int/max-value :)

the largest representable int (2^63 - 1).

9223372036854775807.

(int/max-value)  ; => 9223372036854775807

Since: Phase N1

defn

int/min-value

(int/min-value :)

the smallest representable int (-2^63).

-9223372036854775808. Written as `-(2^63 - 1) - 1` because the literal itself is one past the positive range.

(int/min-value)  ; => -9223372036854775808

Since: Phase N1

defn

int/add-overflows?

(int/add-overflows? [a : int b : int] :)

would `(+ a b)` leave the int64 range?

aleft addend
bright addend

true when the exact sum is outside [int/min-value, int/max-value]. The test itself never overflows: each comparison subtracts b from a bound, which stays in range for the sign of b being tested.

(int/add-overflows? (int/max-value) 1)  ; => true

Since: Phase N1

defn

int/sub-overflows?

(int/sub-overflows? [a : int b : int] :)

would `(- a b)` leave the int64 range?

aminuend
bsubtrahend

true when the exact difference is outside the int64 range.

(int/sub-overflows? (int/min-value) 1)  ; => true

Since: Phase N1

defn

int/mul-overflows?

(int/mul-overflows? [a : int b : int] :)

would `(* a b)` leave the int64 range?

aleft factor
bright factor

true when the exact product is outside the int64 range. The `-1` cases are peeled off first so the remaining tests can divide a bound by a factor without tripping the one division that overflows (`int/min-value / -1`).

(int/mul-overflows? 4294967296 4294967296)  ; => true

Since: Phase N1

defn

rat/normalize

(rat/normalize [n : int d : int] :)

build a Rational in lowest terms with a positive denominator.

nnumerator
ddenominator; must be non-zero (callers check first)

The normalized Rational n/d.

(rat/num (rat/normalize 6 -8))  ; => -3

Since: Phase N1

defn

rat/of

(rat/of [n : int d : int] :)

construct a Rational, reporting a zero denominator as an error.

nnumerator
ddenominator

`(ok r)` with r normalized, or `(err (DivByZero))` when d is 0.

(rat/of 6 8)  ; => ok 3/4
  (rat/of 1 0)  ; => err DivByZero

Since: Phase N1

defn

rat/of!

(rat/of! [n : int d : int] :)

construct a Rational, panicking on a zero denominator.

nnumerator
ddenominator; must not be 0

The normalized Rational n/d. Panics when d is 0 -- this is the form `#rat{n/d}` expands to, and the reader rejects a literal zero denominator at read time, so the panic is reachable only from a computed denominator.

(rat/num (rat/of! 6 8))  ; => 3

Since: Phase N1

defn

rat/from-int

(rat/from-int [n : int] :)

the Rational n/1.

nthe integer

n as an exact Rational.

(rat/den (rat/from-int 5))  ; => 1

Since: Phase N1

defn

rat/zero

(rat/zero :)

the Rational 0/1.

0 as an exact Rational.

(rat/num (rat/zero))  ; => 0

Since: Phase N1

defn

rat/one

(rat/one :)

the Rational 1/1.

1 as an exact Rational.

(rat/num (rat/one))  ; => 1

Since: Phase N1

defn

rat/num

(rat/num [r : Rational] :)

the numerator (carries the sign).

ra Rational

The numerator.

(rat/num (rat/of! -6 8))  ; => -3

Since: Phase N1

defn

rat/den

(rat/den [r : Rational] :)

the denominator (always positive).

ra Rational

The denominator.

(rat/den (rat/of! -6 8))  ; => 4

Since: Phase N1

defn

rat/zero?

(rat/zero? [r : Rational] :)

is this the rational 0?

ra Rational

true when the numerator is 0.

(rat/zero? (rat/of! 0 5))  ; => true

Since: Phase N1

defn

rat/integer?

(rat/integer? [r : Rational] :)

does this rational denote a whole number?

ra Rational

true when the (normalized) denominator is 1.

(rat/integer? (rat/of! 6 3))  ; => true

Since: Phase N1

defn

rat/add

(rat/add [x : Rational y : Rational] :)

exact sum of two rationals.

xleft addend
yright addend

The normalized sum. Cross-cancels by `g = gcd(b, d)` first and computes `(a*(d/g) + c*(b/g)) / (b*(d/g))`, which keeps the common case in int64 range far longer than the naive `(a*d + c*b) / (b*d)`. Wraps on int64 overflow; use `rat/try-add` to detect it.

(rat/den (rat/add (rat/of! 1 3) (rat/of! 1 6)))  ; => 2

Since: Phase N1

defn

rat/neg

(rat/neg [x : Rational] :)

negate a rational.

xa Rational

-x, still normalized (the denominator is untouched).

(rat/num (rat/neg (rat/of! 3 4)))  ; => -3

Since: Phase N1

defn

rat/sub

(rat/sub [x : Rational y : Rational] :)

exact difference of two rationals.

xminuend
ysubtrahend

The normalized difference. Wraps on int64 overflow.

(rat/num (rat/sub (rat/of! 1 2) (rat/of! 1 6)))  ; => 1

Since: Phase N1

defn

rat/mul

(rat/mul [x : Rational y : Rational] :)

exact product of two rationals.

xleft factor
yright factor

The normalized product. Cross-cancels each numerator against the OTHER denominator before multiplying, so the intermediates stay small. Wraps on int64 overflow; use `rat/try-mul` to detect it.

(rat/num (rat/mul (rat/of! 2 3) (rat/of! 3 4)))  ; => 1

Since: Phase N1

defn

rat/div

(rat/div [x : Rational y : Rational] :)

exact quotient of two rationals; panics on a zero divisor.

xdividend
ydivisor; must not be the zero rational

The normalized quotient. Panics when y is 0 -- use `rat/try-div` for the checked form. Wraps on int64 overflow.

(rat/num (rat/div (rat/of! 1 2) (rat/of! 3 4)))  ; => 2

Since: Phase N1

defn

rat/recip

(rat/recip [x : Rational] :)

the reciprocal; panics on the zero rational.

xa non-zero Rational

1/x, normalized (the sign moves back to the numerator).

(rat/num (rat/recip (rat/of! -3 4)))  ; => -4

Since: Phase N1

defn

rat/try-add

(rat/try-add [x : Rational y : Rational] :)

checked sum; `Err Overflow` instead of wrapping.

xleft addend
yright addend

`(ok (rat/add x y))`, or `(err (Overflow))` when any intermediate of the cross-cancelled formula would leave the int64 range.

(rat/try-add (rat/of! 1 3) (rat/of! 1 6))  ; => ok 1/2

Since: Phase N1

defn

rat/try-sub

(rat/try-sub [x : Rational y : Rational] :)

checked difference; `Err Overflow` instead of wrapping.

xminuend
ysubtrahend

`(ok (rat/sub x y))`, or `(err (Overflow))`. Negating the subtrahend is itself checked: the int64 minimum has no positive counterpart.

(rat/try-sub (rat/of! 1 2) (rat/of! 1 6))  ; => ok 1/3

Since: Phase N1

defn

rat/try-mul

(rat/try-mul [x : Rational y : Rational] :)

checked product; `Err Overflow` instead of wrapping.

xleft factor
yright factor

`(ok (rat/mul x y))`, or `(err (Overflow))` when either cross-cancelled product would leave the int64 range.

(rat/try-mul (rat/of! 2 3) (rat/of! 3 4))  ; => ok 1/2

Since: Phase N1

defn

rat/try-div

(rat/try-div [x : Rational y : Rational] :)

checked quotient; `Err DivByZero` / `Err Overflow`.

xdividend
ydivisor

`(err (DivByZero))` when y is the zero rational, `(err (Overflow))` when the product would leave the int64 range, else `(ok (rat/div x y))`.

(rat/try-div (rat/of! 1 2) (rat/of! 0 1))  ; => err DivByZero

Since: Phase N1

defn

rat/eq?

(rat/eq? [x : Rational y : Rational] :)

exact equality of two rationals.

xleft value
yright value

true when the two denote the same number. Both are normalized, so this is plain structural equality.

(rat/eq? (rat/of! 2 4) (rat/of! 1 2))  ; => true

Since: Phase N1

defn

rat/cmp

(rat/cmp [x : Rational y : Rational] :)

three-way comparison of two rationals.

xleft value
yright value

-1 when x < y, 0 when equal, 1 when x > y. Compares `a*(d/g)` against `c*(b/g)` for `g = gcd(b, d)`, so the cross-products stay small; both denominators are positive, so the comparison direction is preserved.

(rat/cmp (rat/of! 1 3) (rat/of! 1 2))  ; => -1

Since: Phase N1

defn

rat/lt?

(rat/lt? [x : Rational y : Rational] :)

is x strictly less than y?

xleft value
yright value

true when x < y.

(rat/lt? (rat/of! 1 3) (rat/of! 1 2))  ; => true

Since: Phase N1

defn

rat/lte?

(rat/lte? [x : Rational y : Rational] :)

is x less than or equal to y?

xleft value
yright value

true when x <= y.

(rat/lte? (rat/of! 1 2) (rat/of! 1 2))  ; => true

Since: Phase N1

defn

rat/gt?

(rat/gt? [x : Rational y : Rational] :)

is x strictly greater than y?

xleft value
yright value

true when x > y.

(rat/gt? (rat/of! 1 2) (rat/of! 1 3))  ; => true

Since: Phase N1

defn

rat/gte?

(rat/gte? [x : Rational y : Rational] :)

is x greater than or equal to y?

xleft value
yright value

true when x >= y.

(rat/gte? (rat/of! 1 2) (rat/of! 1 2))  ; => true

Since: Phase N1

defn

rat->float

(rat->float [r : Rational] :)

the nearest float to this rational.

ra Rational

`num / den` as a double. Inexact by construction -- this is the lossy direction out of the exact tower.

(rat->float (rat/of! 1 4))  ; => 0.25

Since: Phase N1

defn

rat->string

(rat->string [r : Rational] :)

render a Rational as "3/4", "-3/4", or "5".

ra Rational

A fresh owned String. A whole number prints without a denominator; every other value round-trips through the `#rat{...}` literal.

(rat->string (rat/of! 6 8))  ; => String "3/4"

Since: Phase N1

definstance

Num[Rational]

(definstance Num [Rational])

exact rational arithmetic behind + - * /.

definstance

Eq[Rational]

(definstance Eq [Rational])

structural equality, which normalization makes exact.

definstance

Ord[Rational]

(definstance Ord [Rational])

total order via the cross-cancelled cross-product.

definstance

Hash[Rational]

(definstance Hash [Rational])

mixes the normalized numerator and denominator.

definstance

Show[Rational]

(definstance Show [Rational])

"3/4" / "-3/4" / "5"; round-trips through #rat{...}.