Rational
A module for rational numbers in Carp.
Fractions are expressed as pairs of integers: a numerator and a denominator. Mathematical operations and conversion primitives to and from integers and floating point numbers are provided.
(load "git@github.com:carpentry-org/rational@0.7.1")
(Rational.new 22 12) ; => (Rational 11/6)
(* (Rational.new 22 12) (Rational.new 1 6)) ; => (Rational 2/1)
(to-int (Rational.new 2 1)) ; => 2
(to-float (Rational.new 1 4)) ; => 0.25
(to-double (Rational.new 1 4)) ; => 0.25
<
(Fn [(Ref Rational a), (Ref Rational b)] Bool)
(< a b)
checks whether Rational a is less than b.
The comparison is exact for every representable pair: it walks the two continued-fraction expansions instead of cross-multiplying, so no intermediate product can overflow.
add
(Fn [(Ref Rational a), (Ref Rational b)] Rational)
(add a b)
adds two Rationals a and b. Common factors are cancelled
first, but the result still overflows when the sum in lowest terms is not
representable, for example when both denominators are large and coprime.
ceil
(Fn [Rational] a)
(ceil r)
returns the smallest integer not less than the Rational r
(rounding toward positive infinity) as a whole Rational.
clamp
(Fn [(Ref a b), (Ref a b), (Ref a b)] a)
(clamp lo hi x)
clamps the Rational x into the inclusive range [lo, hi],
which assumes lo is not greater than hi.
denominator
(Fn [(Ref Rational a)] (Ref Int a))
gets the denominator property of a Rational.
div
(Fn [(Ref Rational a), (Ref Rational b)] Rational)
(div a b)
divides two Rationals a and b. Like add it can
overflow when the quotient in lowest terms is not representable.
floor
(Fn [Rational] a)
(floor r)
returns the largest integer not greater than the Rational r
(rounding toward negative infinity) as a whole Rational.
from-string
(Fn [(Ref String a)] (Maybe Rational))
(from-string s)
parses a Rational from text: either a fraction like 3/4
or -2/7, or a bare integer like 5. The result is reduced to lowest terms and
its sign normalized onto the numerator, so 6/-8 yields -3/4. Returns
Nothing for malformed input, an empty numerator or denominator, or a zero
denominator.
modulo
(Fn [(Ref Rational a), (Ref Rational b)] Rational)
(modulo a b)
calculates the modulo of two Rationals a and b, i.e. the
remainder a - trunc(a/b)*b, which carries the sign of a.
The quotient is never materialized, so a representable remainder is returned
exactly even when the quotient itself would overflow: 100000/1 mod 1/100000
has quotient 10^10 and remainder 0/1. When a is smaller than b in
magnitude the quotient is zero and a is returned unchanged.
The one inexact case is a at least as large as b in magnitude while the
magnitude of numerator(b) * denominator(a), with common factors cancelled,
leaves Int range. There the quotient is estimated by cross-multiplication,
which overflows in turn: 2059044299/195 mod 1285988199/265 is wrong for that
reason. The denominator of the result always divides the product of the two
denominators.
mul
(Fn [(Ref Rational a), (Ref Rational b)] Rational)
(mul a b)
multiplies two Rationals a and b. Like add it can
overflow when the product in lowest terms is not representable.
neg?
(Fn [(Ref Rational a)] Bool)
(neg? r)
returns whether the Rational r is strictly negative.
new
(Fn [Int, Int] Rational)
(new n d)
builds a Rational from a numerator n and a denominator d.
The resulting fraction is always in lowest terms. Negative denominators are normalized so the sign is carried by the numerator.
numerator
(Fn [(Ref Rational a)] (Ref Int a))
gets the numerator property of a Rational.
pos?
(Fn [(Ref Rational a)] Bool)
(pos? r)
returns whether the Rational r is strictly positive. Since a
Rational always carries its sign on the numerator, this is the sign of the
numerator.
pow
(Fn [(Ref Rational a), Int] Rational)
(pow r n)
raises the Rational r to the integer power n. A negative
exponent inverts the fraction, so r^-n is (1/r)^n, and r^0 is 1. Like
the other arithmetic operations the result can overflow for large powers, and a
negative power of zero is undefined.
rationalize
(Fn [Double, Int] Rational)
(rationalize x max-denom)
builds the Rational nearest to the Double x whose
denominator does not exceed max-denom. This is the best rational approximation
under that bound; it walks the convergents of the continued-fraction expansion,
so the result is the simplest such fraction. For example, 3.14159... bounded by
300 yields 355/113. max-denom should be at least 1.
Non-finite and out-of-range inputs saturate to a valid, finite Rational with a
non-zero denominator, so the result is always safe to divide by: NaN yields
0/1, and infinities or magnitudes beyond the representable range clamp to
±1073741824/1.
reciprocal
(Fn [(Ref Rational a)] Rational)
(reciprocal r)
returns the reciprocal (multiplicative inverse) 1/r of the
Rational r. The reciprocal of zero is undefined, mirroring division by
zero.
round
(Fn [Rational] a)
(round r)
rounds the Rational r to the nearest integer, with halves
rounded away from zero, as a whole Rational.
set-denominator
(Fn [Rational, Int] Rational)
sets the denominator property of a Rational.
set-denominator!
(Fn [(Ref Rational a), Int] ())
sets the denominator property of a Rational in place.
set-numerator!
(Fn [(Ref Rational a), Int] ())
sets the numerator property of a Rational in place.
sign
(Fn [Rational] a)
(sign r)
returns the sign of the Rational r as a Rational: -1 when
r is negative, 0 when it is zero, and 1 when it is positive. The numerator
carries the sign, so a positive denominator is guaranteed by new.
str
(Fn [(Ref Rational a)] String)
(str r)
stringifies the Rational r. The format is
(Rational <numerator>/<denominator>).
sub
(Fn [(Ref Rational a), (Ref Rational b)] Rational)
(sub a b)
subtracts two Rationals a and b. Like add it can
overflow when the difference in lowest terms is not representable.
to-double
(Fn [(Ref Rational a)] Double)
(to-double r)
converts a Rational r to a Double.
This function might incur a precision loss.
to-float
(Fn [(Ref Rational a)] Float)
(to-float r)
converts a Rational r to a Float.
This function might incur a precision loss.
to-int
(Fn [(Ref Rational a)] Int)
(to-int r)
converts a Rational r to an Integer.
This function might incur a precision loss; it truncates toward zero. See floor, ceil, and round for other rounding modes.
update-denominator
(Fn [Rational, (Ref (Fn [Int] Int a) b)] Rational)
updates the denominator property of a Rational using a function f.
update-numerator
(Fn [Rational, (Ref (Fn [Int] Int a) b)] Rational)
updates the numerator property of a Rational using a function f.
zero
(Fn [] Rational)
(zero)
returns the additive identity 0/1. The denominator is 1, not
0, so the result is safe to use in any arithmetic operation.
zero?
(Fn [(Ref Rational a)] Bool)
(zero? r)
returns whether the Rational r is zero, i.e. its numerator is
zero.