Functional Weave
Code in Rust

math.gcd-lcm@2.0.0

README.md

2,466 bytes · view raw

# math.gcd-lcm

Returns the greatest common divisor (also called the highest common factor)
and the least common multiple of two integers. Both are never negative:
`gcd(-4, 6)` is 2 and `lcm(-4, 6)` is 12.

The conventions at zero are the ones every maths library uses: `gcd(0, n)` is
`|n|`, `gcd(0, 0)` is 0, and the lcm of anything with 0 is 0.

The lcm is computed as `|a| / gcd * |b|`, dividing first. The textbook
`a * b / gcd` overflows a 64-bit integer, and loses digits in a JavaScript
number, long before the answer itself is large; one of the vectors is a case
where it does.

Inputs and results are limited to ±(2^53 - 1), the range where a JavaScript
number is still an exact integer, so the three languages agree on every
answer. An input outside it, or an lcm beyond it, is an error.

This is a group of three functions: `gcdLcm(a, b)` returns both answers,
`gcd(a, b)` and `lcm(a, b)` one each. `lcm` uses `gcd`, and `gcdLcm` uses
both, so `require math.gcd-lcm ^2.0.0 only=gcd` installs the gcd alone.

`gcdWide(a, b)`, a gcd over wide integers (TypeScript `bigint`, Python `int`,
Rust `i128`) with no range limit, is still exported from the `gcd` file for
fraction arithmetic that reduces products already past 2^53. It is a helper,
not a published function: the registry's type vocabulary has no wide integer
(`int` is a JavaScript number and an `i64`), so it has no `fn` line and no
vectors of its own, and it is exercised through `gcd`'s vectors. Its signature
and behaviour are exactly those of 1.0.0.

## What changed from 1.0.0

1.0.0 was one function, `gcdLcm`, with `gcd`, `lcm` and `gcdWide` exported
alongside it but unpinned: no signature in the manifest and no vectors, so
nothing held the three languages to the same answer for them. 2.0.0 is a
group: `gcd` and `lcm` are published functions with their own signatures,
files and vectors, and `gcdLcm` keeps every 1.0.0 vector.

No answer changed. The Rust adapters now refuse a fractional argument with
the same "must be an integer" wording as TypeScript and Python, which only
affects the vectors. It is a new major version because the package's shape
and public surface changed: it installs as one module per function plus the
group module (`math_gcd_lcm` still re-exports every function and `gcdWide`),
a project can take only some of it, and the Python module no longer exports
its `MAX_SAFE` constant. Dependents stay on `^1.0.0` until they move
deliberately; 1.0.0 is unchanged.