Functional Weave
Code in Rust

math.rational@1.0.0

README.md

1,610 bytes · view raw

# math.rational

A fraction held as two integers, so 1/3 stays 1/3 and 1/10 + 2/10 is exactly
3/10. Use it for exchange rates, unit conversions and pro-rata factors that
are applied more than once: a float rate drifts a little on every step, a
rational one never does. Money itself stays in `money.amount` minor units;
turn a rational back into an integer with `rationalToInteger` and an explicit
rounding mode.

Every result is reduced (numerator and denominator share no factor) and its
denominator is positive, so two equal values always have the same fields and
compare equal as plain data. Inputs need not be reduced: `{2, -4}` is read as
-1/2.

The vectored entry is `calculateRational(a, op, b)`. The module also exports
`rational(n, d)` (build and reduce), `addRational`, `subtractRational`,
`multiplyRational`, `divideRational`, `compareRational(a, b)` (-1, 0 or 1) and
`rationalToInteger(r, mode)` (the `math.round-div` modes), which are the same
arithmetic under separate names.

**Limits.** A numerator or denominator must be an integer within
±(2^53 - 1), the range where a JavaScript number is exact, in inputs and in
results. Intermediate products are computed wide (TypeScript `bigint`, Python
`int`, Rust `i128`) and reduced before the check, so `(2^53-1)/2 × 2/(2^53-1)`
is 1 even though the unreduced product is far past the limit. A result that
is still too large after reducing is an error ("rational overflow"), never a
silently wrong fraction.

Level 1 rather than the catalogue's 0, because it builds on `math.gcd-lcm` and
`math.round-div` instead of carrying private copies of them.