Skip to content

Commit

Permalink
Implement a method for accurately measuring the sizes of small commas
Browse files Browse the repository at this point in the history
  • Loading branch information
frostburn committed Apr 24, 2024
1 parent 29401f5 commit 670f4b4
Show file tree
Hide file tree
Showing 3 changed files with 152 additions and 0 deletions.
22 changes: 22 additions & 0 deletions src/__tests__/monzo.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {describe, it, expect} from 'vitest';
import {Fraction} from '../fraction';
import {
monzoToBigInt,
monzoToCents,
monzoToFraction,
primeLimit,
toMonzo,
Expand Down Expand Up @@ -372,3 +373,24 @@ describe('Prime limit calculator', () => {
expect(primeLimit(2n ** 1025n)).toEqual(2);
});
});

describe('Monzo size measure', () => {
it('calculates the size of the perfect fourth accurately', () => {
expect(monzoToCents([2, -1])).toBeCloseTo(498.0449991346125, 12);
});

it('calculates the size of the neutrino accurately', () => {
// XXX: Produces 1.6358114862669026e-10. Three digits of accuracy, smh...
expect(monzoToCents([1889, -2145, 138, 424])).toBeCloseTo(
1.6361187484440885e-10,
13
);
});

it('calculates the size of the demiquartervice comma accurately', () => {
expect(monzoToCents([-3, 2, -1, -1, 0, 0, -1, 0, 2])).toBeCloseTo(
0.3636664332386927,
14
);
});
});
35 changes: 35 additions & 0 deletions src/commas.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Mapping commas for measuring the sizes of small intervals

export const MAPPING_COMMA_MONZOS = [
[1], // Octave
[-1, 1], // Pure fifth
[554, -351, 1], // Quectisma
[-55, 30, 2, 1], // Nommisma
[-30, 27, -7, 0, 1], // Negative syntonoschisma / syntonisma
[9, 0, -1, 0, -3, 1], // Jacobin comma
[-2, 2, -1, -5, 0, 3, 1], // Aksial comma
[9, -3, -3, -2, 0, 0, 1, 1], // Decimillisma
[-1, -1, 0, -1, -2, 1, 1, 0, 1], // Broadviewsma
];

export const MAPPING_COMMA_CENTS = [
1200, 701.9550008653874, 0.10841011385118912, 0.1033601604170961,
-0.09303132362673557, 0.2601208102056527, 0.005150328654440726,
0.010468503793319029, 0.34062647410756758,
];

// Auxiliary commas for chipping away at the 3-limit
export const SATANIC_COMMA_MONZO = [-1054, 665];
export const SATANIC_COMMA_CENTS = 0.07557548263280008;

export const MERCATOR_COMMA_MONZO = [-84, 53];
export const MERCATOR_COMMA_CENTS = 3.61504586553314;

export const PYTH_COMMA_MONZO = [-19, 12];
export const PYTH_COMMA_CENTS = 23.46001038464901;

export const PYTH_LIMMA_MONZO = [8, -5];
export const PYTH_LIMMA_CENTS = 90.22499567306291;

export const PYTH_TONE_MONZO = [-3, 2];
export const PYTH_TONE_CENTS = 203.9100017307748;
95 changes: 95 additions & 0 deletions src/monzo.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
import {Fraction, FractionValue} from './fraction';
import {BIG_INT_PRIMES, PRIMES} from './primes';
import {
MAPPING_COMMA_CENTS,
MAPPING_COMMA_MONZOS,
MERCATOR_COMMA_CENTS,
MERCATOR_COMMA_MONZO,
PYTH_COMMA_CENTS,
PYTH_COMMA_MONZO,
PYTH_LIMMA_CENTS,
PYTH_LIMMA_MONZO,
PYTH_TONE_CENTS,
PYTH_TONE_MONZO,
SATANIC_COMMA_CENTS,
SATANIC_COMMA_MONZO,
} from './commas';

/**
* Array of integers representing the exponents of prime numbers in the unique factorization of a rational number.
Expand Down Expand Up @@ -593,3 +607,84 @@ function bigIntToMonzo7(n: bigint): [Monzo, bigint] {
}
return [result, n];
}

export function monzoToCents(monzo: Monzo) {
monzo = [...monzo];
while (monzo.length && !monzo[monzo.length - 1]) {
monzo.pop();
}
let result = 0;
while (monzo.length > 2) {
const component = monzo.pop()!;
result += component * MAPPING_COMMA_CENTS[monzo.length];
const comma = MAPPING_COMMA_MONZOS[monzo.length];
for (let i = 0; i < monzo.length; ++i) {
monzo[i] -= component * comma[i];
}
}
if (monzo.length === 2) {
while (monzo[1] >= 665) {
result += SATANIC_COMMA_CENTS;
monzo[0] -= SATANIC_COMMA_MONZO[0];
monzo[1] -= SATANIC_COMMA_MONZO[1];
}
while (monzo[1] <= -665) {
result -= SATANIC_COMMA_CENTS;
monzo[0] += SATANIC_COMMA_MONZO[0];
monzo[1] += SATANIC_COMMA_MONZO[1];
}

while (monzo[1] >= 53) {
result += MERCATOR_COMMA_CENTS;
monzo[0] -= MERCATOR_COMMA_MONZO[0];
monzo[1] -= MERCATOR_COMMA_MONZO[1];
}
while (monzo[1] <= -53) {
result -= MERCATOR_COMMA_CENTS;
monzo[0] += MERCATOR_COMMA_MONZO[0];
monzo[1] += MERCATOR_COMMA_MONZO[1];
}

while (monzo[1] >= 12) {
result += PYTH_COMMA_CENTS;
monzo[0] -= PYTH_COMMA_MONZO[0];
monzo[1] -= PYTH_COMMA_MONZO[1];
}
while (monzo[1] <= -12) {
result -= PYTH_COMMA_CENTS;
monzo[0] += PYTH_COMMA_MONZO[0];
monzo[1] += PYTH_COMMA_MONZO[1];
}

while (monzo[1] >= 5) {
result -= PYTH_LIMMA_CENTS;
monzo[0] += PYTH_LIMMA_MONZO[0];
monzo[1] += PYTH_LIMMA_MONZO[1];
}
while (monzo[1] <= -5) {
result += PYTH_LIMMA_CENTS;
monzo[0] -= PYTH_LIMMA_MONZO[0];
monzo[1] -= PYTH_LIMMA_MONZO[1];
}

while (monzo[1] >= 2) {
result += PYTH_TONE_CENTS;
monzo[0] -= PYTH_TONE_MONZO[0];
monzo[1] -= PYTH_TONE_MONZO[1];
}
while (monzo[1] <= -2) {
result -= PYTH_TONE_CENTS;
monzo[0] += PYTH_TONE_MONZO[0];
monzo[1] += PYTH_TONE_MONZO[1];
}
}
while (monzo.length) {
const component = monzo.pop()!;
result += component * MAPPING_COMMA_CENTS[monzo.length];
const comma = MAPPING_COMMA_MONZOS[monzo.length];
for (let i = 0; i < monzo.length; ++i) {
monzo[i] -= component * comma[i];
}
}
return result;
}

0 comments on commit 670f4b4

Please sign in to comment.