form 1 topics added
This commit is contained in:
@@ -11,97 +11,100 @@ 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];
|
||||
/**
|
||||
* An immutable fraction. Sign is kept on the numerator; arithmetic returns a new
|
||||
* Fraction and does NOT auto-simplify — call `.simplified()` when you want lowest
|
||||
* terms (this lets teaching views show the un-reduced working). Prefer this over
|
||||
* passing `(num, den)` pairs around: positional pairs are easy to mis-order.
|
||||
*/
|
||||
export class Fraction {
|
||||
readonly n: number;
|
||||
readonly d: number;
|
||||
|
||||
constructor(n: number, d: number) {
|
||||
// Canonical sign: keep it on the numerator. A zero denominator is tolerated
|
||||
// (kept as-is) so divide-by-zero in a lesson renders rather than throwing.
|
||||
if (d < 0) {
|
||||
n = -n;
|
||||
d = -d;
|
||||
}
|
||||
this.n = n;
|
||||
this.d = d;
|
||||
}
|
||||
|
||||
static of(n: number, d: number): Fraction {
|
||||
return new Fraction(n, d);
|
||||
}
|
||||
|
||||
get isZero(): boolean {
|
||||
return this.n === 0;
|
||||
}
|
||||
|
||||
plus(o: Fraction): Fraction {
|
||||
return new Fraction(this.n * o.d + o.n * this.d, this.d * o.d);
|
||||
}
|
||||
|
||||
minus(o: Fraction): Fraction {
|
||||
return new Fraction(this.n * o.d - o.n * this.d, this.d * o.d);
|
||||
}
|
||||
|
||||
times(o: Fraction): Fraction {
|
||||
return new Fraction(this.n * o.n, this.d * o.d);
|
||||
}
|
||||
|
||||
dividedBy(o: Fraction): Fraction {
|
||||
return new Fraction(this.n * o.d, this.d * o.n);
|
||||
}
|
||||
|
||||
simplified(): Fraction {
|
||||
if (this.d === 0) return this;
|
||||
if (this.n === 0) return new Fraction(0, 1);
|
||||
const g = gcd(Math.abs(this.n), Math.abs(this.d));
|
||||
return new Fraction(this.n / g, this.d / g);
|
||||
}
|
||||
|
||||
get isSimplified(): boolean {
|
||||
return gcd(Math.abs(this.n), Math.abs(this.d)) === 1;
|
||||
}
|
||||
|
||||
/** Value equality (cross-multiplication), independent of the written form. */
|
||||
equals(o: Fraction): boolean {
|
||||
return this.n * o.d === o.n * this.d;
|
||||
}
|
||||
|
||||
toDecimal(): number {
|
||||
return this.n / this.d;
|
||||
}
|
||||
|
||||
/** [whole, remainderNumerator, denominator] */
|
||||
toMixed(): [number, number, number] {
|
||||
const whole = Math.trunc(this.n / this.d);
|
||||
const remainder = Math.abs(this.n % this.d);
|
||||
return [whole, remainder, this.d];
|
||||
}
|
||||
|
||||
toKatex(): string {
|
||||
if (this.d === 1) return `${this.n}`;
|
||||
return `\\frac{${this.n}}{${this.d}}`;
|
||||
}
|
||||
|
||||
/** Like toKatex, but writes negatives with the sign in front: -\frac{3}{4} rather than \frac{-3}{4}. */
|
||||
toSignedKatex(): string {
|
||||
if (this.d === 1) return `${this.n}`;
|
||||
const sign = this.n < 0 ? "-" : "";
|
||||
return `${sign}\\frac{${Math.abs(this.n)}}{${this.d}}`;
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return this.d === 1 ? `${this.n}` : `${this.n}/${this.d}`;
|
||||
}
|
||||
}
|
||||
|
||||
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}}`;
|
||||
/**
|
||||
* Convenience KaTeX formatter for raw (num, den) pairs. Handy in the step-by-step
|
||||
* lesson views, which build up strings from loose numerators/denominators rather
|
||||
* than Fraction objects. For arithmetic, use the Fraction class instead.
|
||||
*/
|
||||
export function toKatex(n: number, d: number): string {
|
||||
return new Fraction(n, d).toKatex();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user