/* * Copyright (C) 2026 filifa * * License: 0BSD (https://spdx.org/licenses/0BSD.html) */ function sievePrimes(n) { const isPrime = Array(n); isPrime[0] = false; isPrime[1] = false; for (let i = 2; i < n; i++) { isPrime[i] = true; } for (let i = 2; i < Math.sqrt(n); i++) { if (!isPrime[i]) { continue; } for (let j = i * i; j < n; j += i) { isPrime[j] = false; } } return isPrime; } function numDivisors(p, k) { return k + 1; } function sumDivisors(p, k) { return (p**(k+1) - 1) / (p - 1) } function totient(p, k) { return p**(k-1) * (p - 1); } function radical(p, k) { return p; } function littleOmega(p, k) { return 1; } function bigOmega(p, k) { return k; } function mobius(p, k) { if (k === 1) { return -1; } return 0; } function initArrays(l, r, additive) { const sieve = Array(r - l); const quo = Array(r - l); for (let i = 0; i < r-l; i++) { quo[i] = l + i; if (additive) { sieve[i] = 0; } else { sieve[i] = 1; } } return [sieve, quo]; } function sieveSegment(l, r, f, primes, additive) { const [sieve, quo] = initArrays(l, r, additive); for (let i = 0; i < primes.length; i++) { if (i*i > r) { break; } if (!primes[i]) { continue; } sievePowers(i, l, r, f, sieve, quo, additive); } unusuals(f, sieve, quo, additive); return sieve; } function unusuals(f, sieve, quo, additive) { for (let i = 0; i < quo.length; i++) { const q = quo[i]; if (q === 1) { continue; } if (additive) { sieve[i] += f(q, 1); } else { sieve[i] *= f(q, 1); } } } function sievePowers(p, l, r, f, sieve, quo, additive) { let i = 1; for (let q = p; q < r; q *= p) { const y = f(p, i); sieveMultiples(p, q, l, r, y, sieve, quo, additive); i++; } } function sieveMultiples(p, q, l, r, y, sieve, quo, additive) { const low = Math.ceil(l / q); for (let i = low * q; i < r; i += q) { if (i % (p*q) === 0) { continue; } if (additive) { sieve[i - l] += y; } else { sieve[i - l] *= y; } quo[i - l] /= q } } function getFunc(func) { switch (func.value) { case "num-divisors": return [numDivisors, false]; case "sum-divisors": return [sumDivisors, false]; case "totient": return [totient, false]; case "mobius": return [mobius, false]; case "radical": return [radical, false]; case "little-omega": return [littleOmega, true]; case "big-omega": return [bigOmega, true]; default: throw new Error("function not implemented!"); } } function buildTable(l, r, values) { const table = document.createElement("table"); const caption = document.createElement("caption"); caption.id = "result-caption"; caption.textContent = "Results"; table.appendChild(caption); const tbody = document.createElement("tbody"); table.appendChild(tbody); const ns = Array(r-l); for (let i = l; i < r; i++) { ns[i - l] = i; } const nrow = buildRow("n", l, r, ns); tbody.appendChild(nrow); const vrow = buildRow("f(n)", l, r, values); tbody.appendChild(vrow); return table; } function buildRow(htext, l, r, values) { const row = document.createElement("tr"); const head = document.createElement("th"); head.textContent = htext; row.appendChild(head); for (let i = l; i < r; i++) { if (i === 0) { continue; } const elem = document.createElement("td"); elem.textContent = values[i - l]; row.appendChild(elem); } return row; } function calculate() { const lower = document.querySelector("#lower"); const upper = document.querySelector("#upper"); const func = document.querySelector("#function"); const [f, additive] = getFunc(func); const l = parseInt(lower.value); const r = parseInt(upper.value); const s = Math.floor(Math.sqrt(r)); const primes = sievePrimes(s + 1); const sieve = sieveSegment(l, r, f, primes, additive); const table = buildTable(l, r, sieve); const result = document.querySelector("#result"); while (result.firstChild) { result.removeChild(result.firstChild); } result.appendChild(table); } document.querySelector("#enter").addEventListener("click", () => calculate())