export function gcd(a: number, b: number): number { a = Math.abs(a); b = Math.abs(b); while (b) { [a, b] = [b, a % b]; } return a; } export function lcm(a: number, b: number): number { return Math.abs(a * b) / gcd(a, b); } export function simplify(num: number, den: number): [number, number] { if (den === 0) return [num, den]; const g = gcd(Math.abs(num), Math.abs(den)); const sign = den < 0 ? -1 : 1; return [(num / g) * sign, (den / g) * sign]; } export function add( n1: number, d1: number, n2: number, d2: number, ): [number, number] { const num = n1 * d2 + n2 * d1; const den = d1 * d2; return simplify(num, den); } export function subtract( n1: number, d1: number, n2: number, d2: number, ): [number, number] { const num = n1 * d2 - n2 * d1; const den = d1 * d2; return simplify(num, den); } export function multiply( n1: number, d1: number, n2: number, d2: number, ): [number, number] { return simplify(n1 * n2, d1 * d2); } export function divide( n1: number, d1: number, n2: number, d2: number, ): [number, number] { return simplify(n1 * d2, d1 * n2); } export function toDecimal(num: number, den: number): number { return num / den; } export function fromDecimal(decimal: number, precision: number = 6): [number, number] { const str = decimal.toFixed(precision); const parts = str.split("."); if (!parts[1]) return [parseInt(parts[0]), 1]; const den = Math.pow(10, parts[1].length); const num = Math.round(decimal * den); return simplify(num, den); } export function compare( n1: number, d1: number, n2: number, d2: number, ): -1 | 0 | 1 { const diff = n1 * d2 - n2 * d1; if (diff > 0) return 1; if (diff < 0) return -1; return 0; } export function fractionOfQuantity(num: number, den: number, quantity: number): number { return (num / den) * quantity; } export function wholeFromFraction(num: number, den: number, part: number): number { return (part * den) / num; } export function isProper(num: number, den: number): boolean { return Math.abs(num) < Math.abs(den); } export function toMixed(num: number, den: number): [number, number, number] { const whole = Math.floor(Math.abs(num) / Math.abs(den)); const remainder = Math.abs(num) % Math.abs(den); const sign = (num < 0) !== (den < 0) ? -1 : 1; return [whole * sign, remainder, Math.abs(den)]; } export function fromMixed(whole: number, num: number, den: number): [number, number] { const sign = whole < 0 ? -1 : 1; return [sign * (Math.abs(whole) * den + num), den]; } export function isSimplified(num: number, den: number): boolean { return gcd(Math.abs(num), Math.abs(den)) === 1; } export function toKatex(num: number, den: number): string { if (den === 1) return `${num}`; return `\\frac{${num}}{${den}}`; }