Skip to content

Commit

Permalink
Merge pull request #14 from xenharmonic-devs/lens-add
Browse files Browse the repository at this point in the history
Implement harmonic addition and subtraction
  • Loading branch information
frostburn authored Feb 7, 2024
2 parents 118f33f + d4e1ec2 commit a566798
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 0 deletions.
54 changes: 54 additions & 0 deletions src/__tests__/fraction.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -371,4 +371,58 @@ describe('Fraction', () => {
const fraction = new Fraction(3, 2);
expect(fraction.geoRoundTo('10/9')!.equals('10000/6561')).toBe(true);
});

it('has harmonic addition', () => {
const fraction = new Fraction('7/5');
expect(fraction.lensAdd('13/11').toFraction()).toBe('91/142');
});

it('has harmonic addition of zero (left)', () => {
const fraction = new Fraction(0);
expect(fraction.lensAdd('3/2').toFraction()).toBe('0');
});

it('has harmonic addition of zero (right)', () => {
const fraction = new Fraction('3/2');
expect(fraction.lensAdd(0).toFraction()).toBe('0');
});

it('has harmonic addition of zero (both)', () => {
const fraction = new Fraction(0);
expect(fraction.lensAdd(0).toFraction()).toBe('0');
});

it('has harmonic subtraction', () => {
const fraction = new Fraction('7/5');
expect(fraction.lensSub('13/11').toFraction()).toBe('-91/12');
});

it('has harmonic subtraction of zero (left)', () => {
const fraction = new Fraction(0);
expect(fraction.lensSub('3/2').toFraction()).toBe('0');
});

it('has harmonic subtraction of zero (right)', () => {
const fraction = new Fraction('3/2');
expect(fraction.lensSub(0).toFraction()).toBe('0');
});

it('has harmonic subtraction of zero (both)', () => {
const fraction = new Fraction(0);
expect(fraction.lensSub(0).toFraction()).toBe('0');
});

it('cancels harmonic addition with harmonic subtraction', () => {
const a = new Fraction(
Math.floor(Math.random() * 1000),
Math.floor(Math.random() * 1000) + 1
);
const b = new Fraction(
Math.floor(Math.random() * 1000),
Math.floor(Math.random() * 1000) + 1
);
const lensSum = a.lensAdd(b);
expect(lensSum.lensSub(b).equals(a)).toBe(true);
expect(lensSum.lensSub(a).equals(b)).toBe(true);
});
});
28 changes: 28 additions & 0 deletions src/fraction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,34 @@ export class Fraction {
return new Fraction(this.s * this.n * d - s * n * this.d, this.d * d);
}

/**
* Perform harmonic addition of two rational numbers according to the thin lens equation f⁻¹ = u⁻¹ + v⁻¹
*
* Ex: new Fraction('5/3').lensAdd('3/2') => 15/19
*/
lensAdd(other: FractionValue) {
const {s, n, d} = new Fraction(other);
if (!n) {
// Based on behavior in the limit where both terms become zero.
return new Fraction({s: 0, n: 0, d: 1});
}
return new Fraction(this.s * this.n * s * n, this.n * d + n * this.d);
}

/**
* Perform harmonic subtraction of two rational numbers u⁻¹ = f⁻¹ - v⁻¹ (rearranged thin lens equation)
*
* Ex: new Fraction('15/19').lensSub('3/2') => 5/3
*/
lensSub(other: FractionValue) {
const {s, n, d} = new Fraction(other);
if (!n) {
// Based on behavior in the limit where both terms become zero.
return new Fraction({s: 0, n: 0, d: 1});
}
return new Fraction(this.s * this.n * s * n, n * this.d - this.n * d);
}

/**
* Multiplies two rational numbers
*
Expand Down

0 comments on commit a566798

Please sign in to comment.