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

<

defn

(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.

<=

defn

(Fn [a, a] Bool)

                        (<= a b)
                    

checks whether Rational a is less than or equal to b.

=

defn

(Fn [(Ref Rational a), (Ref Rational a)] Bool)

                        (= a b)
                    

compares two Rationals a and b.

>

defn

(Fn [a, a] Bool)

                        (> a b)
                    

checks whether Rational a is greater than b.

>=

defn

(Fn [a, a] Bool)

                        (>= a b)
                    

checks whether Rational a is greater than or equal to b.

abs

defn

(Fn [Rational] Rational)

                        (abs r)
                    

returns the absolute value of the Rational r.

add

defn

(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

defn

(Fn [Rational] a)

                        (ceil r)
                    

returns the smallest integer not less than the Rational r (rounding toward positive infinity) as a whole Rational.

clamp

defn

(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.

copy

instantiate

(Fn [(Ref Rational a)] Rational)

copies a Rational.

delete

instantiate

(Fn [Rational] ())

deletes a Rational. Should usually not be called manually.

denominator

instantiate

(Fn [(Ref Rational a)] (Ref Int a))

gets the denominator property of a Rational.

div

defn

(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

defn

(Fn [Rational] a)

                        (floor r)
                    

returns the largest integer not greater than the Rational r (rounding toward negative infinity) as a whole Rational.

from-double

defn

(Fn [Double] Rational)

                        (from-double f)
                    

builds a Rational from a Double d.

from-float

defn

(Fn [Float] Rational)

                        (from-float f)
                    

builds a Rational from a Float f.

from-int

defn

(Fn [Int] Rational)

                        (from-int i)
                    

builds a Rational from an Integer i.

from-string

defn

(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.

hash

defn

(Fn [(Ref Rational a)] Int)

                        (hash r)
                    

calculates the hash of the Rational r.

max

defn

(Fn [(Ref a b), (Ref a b)] a)

                        (max a b)
                    

returns the larger of the Rationals a and b.

min

defn

(Fn [(Ref a b), (Ref a b)] a)

                        (min a b)
                    

returns the smaller of the Rationals a and b.

modulo

defn

(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

defn

(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

defn

(Fn [Rational] Rational)

                        (neg r)
                    

negates the Rational r.

neg?

defn

(Fn [(Ref Rational a)] Bool)

                        (neg? r)
                    

returns whether the Rational r is strictly negative.

new

defn

(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

instantiate

(Fn [(Ref Rational a)] (Ref Int a))

gets the numerator property of a Rational.

pos?

defn

(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

defn

(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.

prn

instantiate

(Fn [(Ref Rational a)] String)

converts a Rational to a string.

rationalize

defn

(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

defn

(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

defn

(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

instantiate

(Fn [Rational, Int] Rational)

sets the denominator property of a Rational.

set-denominator!

instantiate

(Fn [(Ref Rational a), Int] ())

sets the denominator property of a Rational in place.

set-numerator

instantiate

(Fn [Rational, Int] Rational)

sets the numerator property of a Rational.

set-numerator!

instantiate

(Fn [(Ref Rational a), Int] ())

sets the numerator property of a Rational in place.

sign

defn

(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

defn

(Fn [(Ref Rational a)] String)

                        (str r)
                    

stringifies the Rational r. The format is (Rational <numerator>/<denominator>).

sub

defn

(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

defn

(Fn [(Ref Rational a)] Double)

                        (to-double r)
                    

converts a Rational r to a Double.

This function might incur a precision loss.

to-float

defn

(Fn [(Ref Rational a)] Float)

                        (to-float r)
                    

converts a Rational r to a Float.

This function might incur a precision loss.

to-int

defn

(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

instantiate

(Fn [Rational, (Ref (Fn [Int] Int a) b)] Rational)

updates the denominator property of a Rational using a function f.

update-numerator

instantiate

(Fn [Rational, (Ref (Fn [Int] Int a) b)] Rational)

updates the numerator property of a Rational using a function f.

zero

defn

(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?

defn

(Fn [(Ref Rational a)] Bool)

                        (zero? r)
                    

returns whether the Rational r is zero, i.e. its numerator is zero.