You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

100 lines
2.6 KiB
TypeScript

import { gcd } from './math'
export type Rational = { num: number; den: number }
export function isRational(v: any): v is Rational {
return typeof v === 'object' && 'num' in v && 'den' in v
}
export const Rationals = {
name: 'Rationals',
zero: { num: 0, den: 1 },
one: { num: 1, den: 1 },
isZero: (r: Rational) => r.num === 0,
isOne: (r: Rational) => r.num === r.den,
of: (num: number, den: number = 1) => {
if (den === 0) {
throw new Error('Division by zero')
}
if ((num | 0) !== num || (den | 0) !== den) {
throw new Error('Expected integer')
}
return { num, den }
},
toString: (r: Rational) => (r.den === 1 ? r.num.toString() : `${r.num} / ${r.den}`),
simplify: (r: Rational) => {
if (r.den === 0) {
throw new Error('Division by zero')
}
if (r.num === 0) {
return Rationals.zero
}
if (r.den < 0) {
r = { num: -r.num, den: -r.den }
}
const g = Math.abs(gcd(r.num, r.den))
return {
num: r.num / g,
den: r.den / g,
}
},
sum: (a: Rational, b: Rational) =>
Rationals.simplify({
num: a.num * b.den + b.num * a.den,
den: a.den * b.den,
}),
sub: (a: Rational, b: Rational) =>
Rationals.simplify({
num: a.num * b.den - b.num * a.den,
den: a.den * b.den,
}),
mul: (a: Rational, b: Rational) =>
Rationals.simplify({
num: a.num * b.num,
den: a.den * b.den,
}),
div: (a: Rational, b: Rational) =>
Rationals.simplify({
num: a.num * b.den,
den: a.den * b.num,
}),
inverse: (a: Rational) => {
if (a.num === 0) {
throw new Error('Division by zero')
}
return Rationals.simplify({
num: a.den,
den: a.num,
})
},
neg: (a: Rational) => {
return Rationals.simplify({
num: -a.num,
den: a.den,
})
},
scale: (a: Rational, k: number) =>
Rationals.simplify({
num: a.num * k,
den: a.den,
}),
eq: (a: Rational, b: Rational) => a.num * b.den === b.num * a.den,
lt: (a: Rational, b: Rational) => a.num * b.den < b.num * a.den,
gt: (a: Rational, b: Rational) => a.num * b.den > b.num * a.den,
leq: (a: Rational, b: Rational) => a.num * b.den <= b.num * a.den,
geq: (a: Rational, b: Rational) => a.num * b.den >= b.num * a.den,
}