1,499 bytes · the TypeScript implementation · view raw
import { type GcdLcm } from"./math_gcd_lcm_types.ts";
function checkSafe(name: string, value: number): void {
if (!Number.isInteger(value)) {
thrownew TypeError(`${name} must be an integer, received ${value}`);
}
if (!Number.isSafeInteger(value)) {
thrownew RangeError(`${name} is outside the safe integer range (±9007199254740991)`);
}
}
/** Euclid's algorithm on wide integers. Never negative; gcdWide(0, 0) is 0. */exportfunction gcdWide(a: bigint, b: bigint): bigint {
let x = a < 0n ? -a : a;
let y = b < 0n ? -b : b;
while (y !== 0n) {
const r = x % y;
x = y;
y = r;
}
return x;
}
exportfunction gcd(a: number, b: number): number {
checkSafe("a", a);
checkSafe("b", b);
return Number(gcdWide(BigInt(a), BigInt(b)));
}
exportfunction lcm(a: number, b: number): number {
const g = gcd(a, b);
if (g === 0) return0;
// Divide before multiplying: a * b overflows long before the lcm does.const result = (BigInt(Math.abs(a)) / BigInt(g)) * BigInt(Math.abs(b));
if (result > BigInt(Number.MAX_SAFE_INTEGER)) {
thrownew RangeError(`the lcm of ${a} and ${b} exceeds 2^53 - 1`);
}
return Number(result);
}
/** * Greatest common divisor and least common multiple of two integers. * * Both are returned together because a caller needing one nearly always * needs the other (common denominators, repeating schedules). */exportfunction gcdLcm(a: number, b: number): GcdLcm {
return { gcd: gcd(a, b), lcm: lcm(a, b) };
}