diff --git a/package.json b/package.json index f8aff70..9405b91 100644 --- a/package.json +++ b/package.json @@ -42,6 +42,7 @@ "pretest": "npm run compile", "posttest": "npm run lint", "test": "vitest", + "fuzz": "FUZZ=1 vitest", "compile-legacy": "tsc -p tsconfig-legacy.json", "prebench": "npm run compile && npm run compile-legacy", "bench": "vitest bench", diff --git a/src/__tests__/index.spec.ts b/src/__tests__/index.spec.ts index ac6e836..f34bd7e 100644 --- a/src/__tests__/index.spec.ts +++ b/src/__tests__/index.spec.ts @@ -24,6 +24,8 @@ import { wilsonHeight, } from '../index'; +const FUZZ = 'FUZZ' in process.env; + describe('Array equality tester', () => { it('works on integer arrays', () => { expect(arraysEqual([1, 2, 3], [1, 2, 3])).toBeTruthy(); @@ -600,7 +602,7 @@ describe('Wilson complexity measure', () => { expect(wilsonHeight(fraction)).toBe(height); }); - it.skip('fuzzes the fraction property', () => { + it.runIf(FUZZ)('fuzzes the fraction property', () => { for (let i = 0; i < 100; ++i) { const n = Math.floor(Math.random() * 1073741823); const d = Math.floor(Math.random() * 1073741822) + 1; @@ -609,7 +611,7 @@ describe('Wilson complexity measure', () => { } }); - it.skip('fuzzes the multiplicative property', () => { + it.runIf(FUZZ)('fuzzes the multiplicative property', () => { for (let i = 0; i < 10000; ++i) { const x = Math.floor(Math.random() * 32768); const y = Math.floor(Math.random() * 32768); diff --git a/src/__tests__/monzo.spec.ts b/src/__tests__/monzo.spec.ts index 8bbf796..6ab2b2f 100644 --- a/src/__tests__/monzo.spec.ts +++ b/src/__tests__/monzo.spec.ts @@ -10,6 +10,8 @@ import { } from '../monzo'; import {isPrime} from '../primes'; +const FUZZ = 'FUZZ' in process.env; + function toMonzoAndResidual11(n: number): [number[], number] { const result = [0, 0, 0, 0, 0]; if (!n) { @@ -442,6 +444,7 @@ describe('Sparse monzos', () => { 17719 * 21909, 15812 * 27083, 21097 * 29468, + 30038 * 7605, ])('works on a tough case %s found during fuzzing', n => { const exponentByPrime = primeFactorize(n); let m = 1; @@ -452,7 +455,7 @@ describe('Sparse monzos', () => { expect(m).toBe(n); }); - it.skip('fuzzes for more broken cases', () => { + it.runIf(FUZZ)('fuzzes for more broken cases', () => { for (let i = 0; i < 100; ++i) { const n = Math.floor(Math.random() * 62837328) + 1; const exponentByPrime = primeFactorize(n); diff --git a/src/monzo.ts b/src/monzo.ts index 5279c3a..175a186 100644 --- a/src/monzo.ts +++ b/src/monzo.ts @@ -694,16 +694,28 @@ export function primeFactorize(value: FractionValue): Map { result.set(-1, 1); value = -value; } - if (value > 1073741823) { - throw new Error('Factorization not implemented above 1073741823.'); + if (value > Number.MAX_SAFE_INTEGER) { + throw new Error( + `Factorization not implemented above ${Number.MAX_SAFE_INTEGER}.` + ); } let [monzo, residual] = intToMonzo7(value); + if (residual > 1073741823) { + throw new Error( + 'Factorization not implemented when 7-limit residual > 1073741823.' + ); + } for (let i = 0; i < monzo.length; ++i) { if (monzo[i]) { result.set(PRIMES[i], monzo[i]); } } - // This is entirely ad. hoc. with holes patched as they came up during fuzzing. + // Skip cascade for known primes. + if (PRIMES.includes(residual)) { + result.set(residual, 1); + return result; + } + // This is entirely ad hoc with holes patched as they came up during fuzzing. while (residual !== 1) { let factor = rhoCascade(residual); residual /= factor;