29 lines
1.4 KiB
JavaScript
29 lines
1.4 KiB
JavaScript
|
|
const fromFraction = (numerator, denominator, bits) => numerator * (1n << BigInt(bits)) / denominator;
|
||
|
|
|
||
|
|
function fixedAnalyticInterior(cr, ci, bits) {
|
||
|
|
const scale = 1n << BigInt(bits);
|
||
|
|
const x = cr - (scale >> 2n), y = ci, q = x * x + y * y;
|
||
|
|
if (4n * q * (q + x * scale) <= y * y * scale * scale) return true;
|
||
|
|
const d = cr + scale;
|
||
|
|
return 16n * (d * d + y * y) <= scale * scale;
|
||
|
|
}
|
||
|
|
|
||
|
|
const cases = [
|
||
|
|
{ id: 'origin-cardioid', re: [0n, 1n], im: [0n, 1n], expected: true },
|
||
|
|
{ id: 'cardioid-cusp', re: [1n, 4n], im: [0n, 1n], expected: true },
|
||
|
|
{ id: 'period2-center', re: [-1n, 1n], im: [0n, 1n], expected: true },
|
||
|
|
{ id: 'period2-boundary', re: [-5n, 4n], im: [0n, 1n], expected: true },
|
||
|
|
{ id: 'right-exterior', re: [13n, 50n], im: [0n, 1n], expected: false },
|
||
|
|
{ id: 'period3-not-analytic', re: [-123n, 1000n], im: [745n, 1000n], expected: false },
|
||
|
|
{ id: 'far-exterior', re: [1n, 1n], im: [1n, 1n], expected: false }
|
||
|
|
];
|
||
|
|
|
||
|
|
let checked = 0;
|
||
|
|
for (const bits of [256, 320]) for (const sample of cases) {
|
||
|
|
const cr = fromFraction(sample.re[0], sample.re[1], bits);
|
||
|
|
const ci = fromFraction(sample.im[0], sample.im[1], bits);
|
||
|
|
const actual = fixedAnalyticInterior(cr, ci, bits);
|
||
|
|
if (actual !== sample.expected) throw new Error(`${sample.id} at ${bits} bit: expected ${sample.expected}, got ${actual}`);
|
||
|
|
checked++;
|
||
|
|
}
|
||
|
|
console.log(JSON.stringify({ status: 'pass', checked, precisions: [256, 320], proof: 'integer cardioid/period-2 inequalities' }));
|