User:ArrowHead294/Purely consistent EDOs by odd limit/Appendix: Difference between revisions
Jump to navigation
Jump to search
ArrowHead294 (talk | contribs) m Updated version, optimising so I don't have to call the error function all the time |
ArrowHead294 (talk | contribs) mNo edit summary |
||
| Line 156: | Line 156: | ||
for (let j = 1; ; j++) | for (let j = 1; ; j++) | ||
{ | { | ||
let t = j * a; t -= Math.floor(t); | let t = j * a; | ||
t -= Math.floor(t); | |||
if (!jm && t < L) | if (!jm && t < L) | ||
{ | { | ||
| Line 175: | Line 176: | ||
while (x >= L) | while (x >= L) | ||
{ | { | ||
N++; x += a - 1; | N++; | ||
x += a - 1; | |||
if (x >= 1) | if (x >= 1) | ||
{ | { | ||
Latest revision as of 17:55, 31 August 2026
Additional results
The smallest EDOs purely consistent in the 7-, 15-, 31-, and 63-odd-limits are 10, 87, 311, and 3159811, respectively.
Additionally, there are (12) 7-odd-limit purely-consistent EDOs less than 87, (3) 15-odd-limit purely-consistent EDOs less than 311, and (481) 31-odd-limit purely consistent EDOs less than 3159811.
31-odd-limit purely consistent EDOs less than 3159811
311, 16808, 20567, 25540, 28342, 31920, 34691, 60392, 65322, 90623, 93664, 116498, 124702, 143958, 148418, 164838, 165226, 165879, 175878, 185793, 195339, 195727, 209851, 210569, 212147, 220633, 241200, 248975, 256119, 263323, 265323, 266901, 285172, 286350, 292376, 298467, 301592, 308712, 318400, 324296, 328645, 330645, 334553, 339998, 344145, 346742, 349643, 351672, 354185, 358987, 360565, 363466, 370499, 371564, 373677, 377373, 385729, 385912, 389618, 395256, 405050, 406296, 406426, 414965, 431385, 439524, 451051, 459944, 460438, 470372, 477470, 482971, 490175, 490358, 491510, 494589, 530634, 536089, 536443, 536983, 542792, 547442, 550955, 570416, 571134, 579803, 587942, 589737, 590843, 597876, 606545, 607263, 610304, 610776, 612764, 642696, 643349, 646915, 649428, 652630, 666236, 669749, 675269, 684507, 687632, 710208, 729980, 732129, 736360, 739261, 739914, 744899, 746294, 751267, 753168, 763102, 763820, 766861, 771834, 775347, 775530, 785464, 791767, 824588, 829142, 836917, 839818, 849034, 850740, 852075, 855154, 859279, 861279, 866153, 876087, 891199, 896654, 905140, 911520, 920777, 922172, 934600, 937585, 948507, 948724, 951408, 958441, 965315, 965532, 971341, 977560, 986099, 1002907, 1003914, 1007697, 1024505, 1025223, 1030314, 1035157, 1041313, 1042031, 1044761, 1045072, 1051965, 1055543, 1078300, 1090545, 1095937, 1096925, 1099826, 1100479, 1109760, 1110083, 1117287, 1118576, 1122272, 1124385, 1132206, 1132399, 1141410, 1144451, 1146747, 1149207, 1152332, 1161259, 1161977, 1163331, 1173330, 1177679, 1183575, 1183898, 1200383, 1206732, 1220950, 1235074, 1236652, 1238652, 1248586, 1251882, 1265705, 1272803, 1281342, 1298150, 1306164, 1311973, 1326097, 1330723, 1334236, 1336031, 1336749, 1337137, 1349124, 1359058, 1359776, 1363472, 1371247, 1373406, 1385788, 1395722, 1402459, 1403748, 1405326, 1410952, 1412530, 1418879, 1430801, 1432379, 1441583, 1447221, 1456502, 1461044, 1464029, 1476274, 1477852, 1479141, 1501975, 1506905, 1507476, 1508194, 1510114, 1511909, 1521824, 1522542, 1536666, 1539350, 1542475, 1549284, 1553474, 1567297, 1577231, 1581515, 1594757, 1595639, 1598323, 1601448, 1612447, 1615348, 1626270, 1626795, 1660650, 1662269, 1667854, 1680894, 1691893, 1696307, 1697702, 1705229, 1711826, 1712544, 1714510, 1719623, 1726755, 1737149, 1749201, 1756675, 1771517, 1777866, 1785865, 1788325, 1791366, 1800753, 1810687, 1823016, 1824594, 1829312, 1833714, 1836528, 1836839, 1846120, 1853647, 1862540, 1867470, 1872474, 1887704, 1894106, 1895501, 1897231, 1908401, 1912309, 1918335, 1921159, 1953026, 1955322, 1959105, 1973012, 1975913, 1976631, 1984052, 2010604, 2026347, 2027412, 2027636, 2038064, 2044444, 2051887, 2052458, 2066011, 2073109, 2083614, 2086792, 2089917, 2092818, 2092958, 2095859, 2097931, 2109766, 2112279, 2114739, 2116970, 2126090, 2129087, 2132082, 2148890, 2151791, 2161135, 2169674, 2183581, 2186482, 2197404, 2202225, 2203290, 2207338, 2208403, 2222568, 2222751, 2224146, 2235863, 2268836, 2285644, 2287439, 2293658, 2296255, 2299768, 2307242, 2310466, 2313591, 2322655, 2327809, 2331117, 2355228, 2358741, 2372564, 2381821, 2382209, 2384281, 2387794, 2390090, 2396333, 2398629, 2427682, 2442601, 2448969, 2458496, 2461481, 2463951, 2475304, 2479535, 2488074, 2489652, 2504882, 2515127, 2526480, 2534619, 2543158, 2547047, 2556981, 2563855, 2570888, 2581738, 2595250, 2598546, 2599941, 2609328, 2619262, 2622303, 2626006, 2639829, 2640400, 2646426, 2651182, 2654223, 2663952, 2671031, 2676657, 2680900, 2685873, 2687839, 2688774, 2691005, 2702681, 2712926, 2719306, 2722207, 2722925, 2733182, 2739733, 2742774, 2753857, 2756898, 2757616, 2773706, 2774424, 2775819, 2784358, 2784488, 2787936, 2788247, 2793885, 2798181, 2809534, 2810693, 2814989, 2833397, 2839112, 2841541, 2861033, 2861751, 2881600, 2893789, 2895184, 2903723, 2904434, 2924420, 2932776, 2934354, 2940657, 2949196, 2949584, 2963407, 2969045, 2971946, 2972223, 2978249, 2981504, 2982157, 2986571, 2997710, 2999676, 3000394, 3008169, 3014906, 3037222, 3044366, 3046826, 3049339, 3051893, 3056760, 3068949, 3076392, 3083490, 3100298, 3103069, 3114422, 3128115, 3134271, 3134989, 3139285, 3144923, 3148812, 3151797, 3158746
Code used
This is the JavaScript code I use to find purely-consistent EDOs by odd limit.
Original
function et_error(interval, et)
{
return [1200, et * 100].map(x => Math.round(x * 100 * (Math.round(et * Math.log2(interval)) / et - Math.log2(interval))) / 100).concat(Math.round(et * Math.log2(interval)) % et);
}
function min_et(h, max_err_pct, max_edos)
{
var a = 0, i = 1, j = 0, start = Date.now(), output = new Array();
h = Math.round(Math.abs(h));
h = h + 1 - (h % 2);
while (j <= max_edos)
{
a = 1;
for (var k = 3; k <= h; k += 2)
{
if (Math.abs(et_error(k, i)[1]) > max_err_pct)
{
a = 0;
}
}
if (a == 1)
{
j++;
console.log(i + " | " + (Date.now() - start)/1000 + "s");
}
i++;
}
}
Current
(Note: This code was written with the assistance of Claude Opus 5, an artificial intelligence tool.)
/**
* Generates a list of equal divisions of the octave that approximate the harmonic series well.
*
* An EDO qualifies when every odd harmonic from 3 to `h` falls within `thresh` of one of its steps, measured as a fraction of
* a step. Even harmonics are skipped: they are octave transpositions of odd ones, and the octave is exact in any EDO.
*
* Searches upward without an upper bound, logging each hit with the elapsed time, and returns once `max_edos` have been
* found. Qualifying EDOs always exist, but they thin out fast, so high `h` can take a very long time to find.
*
* @param {Number} h - Highest harmonic to check. Internally this value is rounded up to the current or next highest odd
* number. This means inputting 32 and 33 will both check through 33. Anything below 3 accepts every EDO.
* Usually this is set to one less than a power of two (e.g. 7, 15, 31, or 63)
* @param {Number} max_edos - How many EDOs to find before stopping.
* @param {Number} [start=1] - Lowest EDO to consider; "1 equal division of the octave" is simply whole-octave steps.
* @param {Number} [thresh=0.25] - Tolerance as a fraction of a step. Defaults to 0.25
* @returns {Number[]} - The list of EDOs found, in ascending order.
*/
function min_et(h, max_edos, start = 1, thresh = 0.25)
{
h = Math.round(Math.abs(h));
h = h + 1 - (h % 2);
start = Math.max(1, Math.round(start));
// Odd primes <=h
let comp = new Int16Array(h + 1), primes = [];
for (let p = 3; p <= h; p += 2)
{
if (comp[p])
{
continue;
}
primes.push(p);
for (let q = p * p; q <= h; q += 2 * p)
{
comp[q] = 1;
}
}
let m = primes.length, out = [];
if (m === 0)
{
for (let n = start; out.length < max_edos; n++)
{
out.push(n);
}
return out;
}
// Per-prime tolerance: p, p^2, p^3, ... p^t collapse to |e_p| < thresh/t
let logs = new Float64Array(m), tol = new Float64Array(m);
for (let i = 0; i < m; i++)
{
logs[i] = Math.log2(primes[i]);
let t = 0;
for (let q = primes[i]; q <= h; q *= primes[i])
{
t++;
}
tol[i] = thresh / t;
}
// Composites with >= 2 distinct factors, bucketed by largest factor
let mixed = Array.from({length: m}, () => []);
for (let k = 9; k <= h; k += 2)
{
let n = k, top = -1, d = 0;
let term = [];
for (let i = 0; i < m && n > 1; i++)
{
let p = primes[i];
if (n % p)
{
continue;
}
let e = 0;
while (n % p === 0)
{
n /= p;
e++;
}
term.push(i, e);
top = i;
d++;
}
if (d >= 2)
{
mixed[top].push(Int32Array.from(term));
}
}
// 3-gap data for the 3-limit filter
let err = new Float64Array(m);
let a = logs[0], b = tol[0], L = 2 * b; // Target arc has length L
let jm = 0, dm = 0, jn = 0, dn = 0;
for (let j = 1; ; j++)
{
let t = j * a;
t -= Math.floor(t);
if (!jm && t < L)
{
jm = j; dm = t;
}
if (!jn && t > 1 - L)
{
jn = j; dn = 1 - t;
}
if (jm && jn)
{
break;
}
}
let jmn = jm + jn, dmn = dm - dn, lim = L - dm;
let N = start, x = start * a + b; x -= Math.floor(x);
while (x >= L)
{
N++;
x += a - 1;
if (x >= 1)
{
x -= 1;
}
}
// Search
let t0 = Date.now();
let steps = 0;
while (out.length < max_edos)
{
err[0] = x - b;
let ok = true;
for (let i = 1; i < m; i++)
{
let y = N * logs[i], e = y - Math.round(y);
if (e >= tol[i] || e <= -tol[i])
{
ok = false;
break;
}
err[i] = e;
let g = mixed[i];
for (let t = 0; t < g.length; t++)
{
let term = g[t];
let s = 0;
for (let q = 0; q < term.length; q += 2)
{
s += term[q + 1] * err[term[q]];
}
s -= Math.round(s);
if (s >= thresh || s <= -thresh)
{
ok = false;
break;
}
}
if (!ok)
{
break;
}
}
if (ok)
{
out.push(N);
console.log(N + " | " + (Date.now() - t0) / 1000 + "s");
}
// Jump to the next N that passes the 3-limit test
if (x < lim)
{
N += jm;
x += dm;
}
else if (x >= dn)
{
N += jn;
x -= dn;
}
else
{
N += jmn; x += dmn;
}
if ((++steps & 0xFFFFF) === 0)
{
x = N * a + b;
x -= Math.floor(x);
}
}
return out;
}