「双方向リスト (doubly-linked list)」と、それを使って実装した「両端キュー (deque)」のプログラムです。双方向リストの説明は拙作のページをお読みください。
// // deque.js : 双方向リストとディーキュー // // Copyright (c) 2025 Makoto Hiroi // // Released under the MIT license // https://opensource.org/license/mit/ // // セル class Cell { constructor(x, n, p) { this._item = x; this._next = n; this._prev = p; } get item() { return this._item; } set item(x) { this._item = x; } get next() { return this._next; } set next(x) { this._next = x; } get prev() { return this._prev; } set prev(x) { this._prev = x; } // n 個のセルをたどる nth(n, end = false) { let cp = this; while (n-- > 0) cp = end ? cp.prev : cp.next; return cp; } } // 空リストの生成 function make_empty() { let cp = new Cell(null, null, null); cp.next = cp; cp.prev = cp; return cp; } // 双方向リスト class DList { constructor() { this._top = make_empty(); this._len = 0; } get top() { return this._top; } get length() { return this._len; } set length(x) { this._len = x; } isEmpty() { return this._len == 0; } clear() { let header = this.top; header.prev = header; header.next = header; this._len = 0; } // 参照 nth(n, end = false) { if (n < this.length) { return this.top.nth(n + 1, end).item; } return; } // 書き換え set(n, x, end = false) { if (n < this.length) { this.top.nth(n + 1, end).item = x; return x; } return; } // 挿入 add(n, x, end = false) { if (n <= this.length) { let p = this.top.nth(n, end); let q = end ? p.prev : p.next; if (end) { // q - c - p let c = new Cell(x, p, q); q.next = c; p.prev = c; } else { // p - c - q let c = new Cell(x, q, p); p.next = c; q.prev = c; } this.length++; return x; } return; } // 削除 delete(n, end = false) { if (n < this.length) { let c = this.top.nth(n + 1, end); let x = c.item; let p = c.next; let q = c.prev; // q - c - p q.next = p; p.prev = q; this.length--; return x; } return; } // ジェネレータ *makeGen(end = false) { let cp = this.top; let n = this.length; while (n-- > 0) { cp = end ? cp.prev : cp.next; yield cp.item; } } *[Symbol.iterator]() { yield* this.makeGen(); } // // 探索 // find(pred, end = false) { for (let x of this.makeGen(end)) { if (pred(x)) return x; } return false; } findIndex(pred, end = false) { let i = 0; for (let x of this.makeGen(end)) { if (pred(x)) return i; i++; } return -1; } indexOf(x, end = false) { return this.findIndex(y => x == y, end); } // // 高階関数 // map(fn) { let d = new DList(); for (let x of this) d.add(0, fn(x), true); return d; } filter(pred) { let d = new DList(); for (let x of this) { if (pred(x)) d.add(0, x, true); } return d; } reduce(fn, a, end = false) { for (let x of this.makeGen(end)) { a = fn(a, x); } return a; } forEach(fn, end = false) { for (let x of this.makeGen(end)) fn(x); } // 文字列 toString() { return "(" + [...this].join(",") + ")"; } // スタティックメソッド static from(iter) { let d = new DList(); for (let x of iter) d.add(0, x, true); return d; } static of(...args) { return DList.from(args); } } // 両端キュー class Deque { constructor() { this._que = new DList(); } get que() { return this._que; } isEmpty() { return this.que.isEmpty(); } length() { return this.que.length; } clear() { this.que.clear(); } push_front(x) { return this.que.add(0, x); } pop_front() { return this.que.delete(0); } peek_front() { return this.que.nth(0); } push_back(x) { return this.que.add(0, x, true); } pop_back() { return this.que.delete(0, true); } peek_back() { return this.que.nth(0, true); } toString() { return this.que.toString(); } } export { DList, Deque };
// // test_deque.js : 双方向リストとディーキューのテスト // // Copyright (c) 2025 Makoto Hiroi // // Released under the MIT license // https://opensource.org/license/mit/ // import { DList, Deque } from './deque.js'; var a = new DList(); console.log('%s', a); // () console.log(a.isEmpty()); // true console.log(a.length); // 0 for (let i = 1; i <= 4; i++) { a.add(0, i); } console.log('%s', a); // (4,3,2,1) console.log(a.isEmpty()); // false console.log(a.length); // 4 for (let i = 5; i <= 8; i++) { a.add(0, i, true); } console.log('%s', a); // (4,3,2,1,5,6,7,8) console.log(a.isEmpty()); // false console.log(a.length); // 8 for (let i = 0; i < a.length; i++) console.log(a.nth(i)) for (let i = 0; i < a.length; i++) console.log(a.nth(i, true)) for (let i = 0; i < a.length; i++) a.set(i, a.nth(i) + i); console.log('%s', a); // 4,4,4,4,9,11,13,15 for (let i = 0; i < a.length; i++) a.set(i, a.nth(i, true) + i, true); console.log('%s', a); // 11,10,9,8,12,13,14,15 console.log(a.delete(0)); // 11 console.log(a.delete(3)); // 12 console.log(a.delete(0, true)); // 15 console.log(a.delete(3, true)); // 9 console.log(a.length) // 4 console.log('%s', a); // 10, 8, 13, 14 a.clear(); console.log(a.isEmpty()); // true console.log(a.length); // 0 for (let i = 1; i <= 8; i++) a.add(0, i, true); for (let x of a) console.log(x); // 1,2,3,4,5,6,7,8 for (let x of a.makeGen(true)) console.log(x); // 8,7,6,5,4,3,2,1 console.log(a.find(x => x % 2 == 0)); // 2 console.log(a.find(x => x % 2 == 0, true)); // 8 console.log(a.find(x => x > 8)); // false console.log(a.findIndex(x => x % 2 == 0)); // 1 console.log(a.findIndex(x => x % 2 == 0, true)); // 0 console.log(a.findIndex(x => x > 8)); // -1 console.log(a.indexOf(2)); // 1 console.log(a.indexOf(8, true)); // 0 console.log(a.indexOf(9)); // -1 console.log('%s', a.map(x => x * x)); // 1 4 9 ... console.log('%s', a.filter(x => x % 2 == 0)); // 2,4,6,8 console.log(a.reduce((a, x) => a + x, 0)); // 36 console.log(a.reduce((a, x) => a + x, 0, true)); // 36 a.forEach(console.log); a.forEach(console.log, true); console.log('%s', DList.from([1,2,3,4,5,6,7,8])); console.log('%s', DList.of(1,2,3,4,5,6,7,8)); // 両端キュー console.log("----- Deque -----"); var b = new Deque(); console.log('%s', b); // () console.log(b.isEmpty()); // true console.log(b.length()); // 0 for (let i = 1; i <= 4; i++) b.push_front(i); console.log('%s', b); // (4,3,2,1) console.log(b.isEmpty()); // false console.log(b.length()); // 4 for (let i = 1; i <= 4; i++) console.log(b.pop_front()); // 4 3 2 1 console.log('%s', b); // () console.log(b.isEmpty()); // true console.log(b.length()); // 0 for (let i = 1; i <= 4; i++) b.push_back(i); console.log('%s', b); // (1,2,3,4) console.log(b.isEmpty()); // false console.log(b.length()); // 4 for (let i = 1; i <= 4; i++) console.log(b.pop_back()); // 4 3 2 1 console.log('%s', b); // () console.log(b.isEmpty()); // true console.log(b.length()); // 0 for (let i = 1; i <= 8; i++) b.push_back(i); console.log('%s', b); // (1,2,3,4,5,6,7,8 console.log(b.isEmpty()); // false console.log(b.length()); // 8 console.log(b.peek_front()); // 1 console.log(b.peek_back()); // 8 while (!b.isEmpty()) console.log(b.pop_front()); // 1 2 3 4 ...
$ node test_deque.js () true 0 (4,3,2,1) false 4 (4,3,2,1,5,6,7,8) false 8 4 3 2 1 5 6 7 8 8 7 6 5 1 2 3 4 (4,4,4,4,9,11,13,15) (11,10,9,8,12,13,14,15) 11 12 15 9 4 (10,8,13,14) true 0 1 2 3 4 5 6 7 8 8 7 6 5 4 3 2 1 2 8 false 1 0 -1 1 0 -1 (1,4,9,16,25,36,49,64) (2,4,6,8) 36 36 1 2 3 4 5 6 7 8 8 7 6 5 4 3 2 1 (1,2,3,4,5,6,7,8) (1,2,3,4,5,6,7,8) ----- Deque ----- () true 0 (4,3,2,1) false 4 4 3 2 1 () true 0 (1,2,3,4) false 4 4 3 2 1 () true 0 (1,2,3,4,5,6,7,8) false 8 1 8 1 2 3 4 5 6 7 8
B───D───F /│ │ A │ │ \│ │ C───E───G 図 : 経路図
// // keiro_deque.js : 経路の探索 (deque のサンプル) // // Copyright (c) 2025 Makoto Hiroi // // Released under the MIT license // https://opensource.org/license/mit/ // import { DList, Deque } from './deque.js'; // 1 ----- 3 ----- 5 // / | | // 0 | | // \ | | // 2 ----- 4 ----- 6 // 隣接リスト const adjacent = [ [1, 2], // 0 [0, 2, 3], // 1 [0, 1, 4], // 2 [1, 4, 5], // 3 [2, 3, 6], // 4 [3], // 5 [4] // 6 ]; // 深さ優先探索 function dfs(goal, path) { let p = path.nth(0, true); if (p == goal) { console.log('%s', path); } else { for (let q of adjacent[p]) { if (path.indexOf(q) == -1) { path.add(0, q, true); dfs(goal, path); path.delete(0, true); } } } } // 実行 console.log('----- depth first search -----'); dfs(6, DList.of(0)); // 幅優先探索 function bfs(start, goal) { let q = new Deque(); q.push_back(DList.of(start)); while (!q.isEmpty()) { let xs = q.pop_front(); let x = xs.nth(0, true); if (x == goal) { console.log('%s', xs); } else { for (let y of adjacent[x]) { if (xs.indexOf(y) == -1) { let ys = DList.from([...xs]); ys.add(0, y, true); q.push_back(ys); } } } } } console.log('----- breadth first search -----'); bfs(0, 6); // 反復深化 function dfsi(path, goal, limit) { if (path.length == limit) { if (path.nth(0, true) == goal) { console.log('%s', path); } } else { for (let p of adjacent[path.nth(0, true)]) { if (path.indexOf(p) == -1) { path.add(0, p, true); dfsi(path, goal, limit); path.delete(0, true); } } } } function ids(start, goal) { for (let limit = 1; limit <= adjacent.length; limit++) { console.log(`----- ${limit} -----`); dfsi(DList.of(start), goal, limit); } } console.log('----- ids -----'); ids(0, 6);
$ node keiro_dlist.js ----- depth first search ----- (0,1,2,4,6) (0,1,3,4,6) (0,2,1,3,4,6) (0,2,4,6) ----- breadth first search ----- (0,2,4,6) (0,1,2,4,6) (0,1,3,4,6) (0,2,1,3,4,6) ----- ids ----- ----- 1 ----- ----- 2 ----- ----- 3 ----- ----- 4 ----- (0,2,4,6) ----- 5 ----- (0,1,2,4,6) (0,1,3,4,6) ----- 6 ----- (0,2,1,3,4,6) ----- 7 -----
整列 (sorting) は、ある規則に従ってデータを順番に並べ換える操作です。たとえば、データが整数であれば大きい順に並べる、もしくは小さい順に並べます。一般に、このような操作を「ソート」と呼んでいます。ソートは昔から研究されている分野で、優秀なアルゴリズムが確立しています。
ソートは大きく分けると、内部ソート (internal sort) と外部ソート (external sort) にわかれます。内部ソートはすべてのデータをメモリに読み込んでソートします。外部ソートはメモリにすべて読み込むことができない巨大なデータをソートするときに使われ、外部記憶装置に途中経過を記憶させながらソートします。
JavaScript の配列 (と型付き配列) にはソートを行うメソッド sort() がありますが、私達でもプログラムすることができます。ここでは代表的なソートアルゴリズムをいくつか実装してみましょう。アルゴリズムの詳しい説明は拙作のページをお読みください。
// // sort.js : ソート // // Copyright (c) 2025 Makoto Hiroi // // Released under the MIT license // https://opensource.org/license/mit/ // function make_data(x) { // x は生成するデータの個数 // 乱数 let a = new Float64Array(x); for (let i = 0; i < x; i++) a[i] = Math.random(); // 昇順 let b = new Float64Array(x); for (let i = 0; i < x; i++) b[i] = i + 1.0; // 降順 let c = new Float64Array(x); for (let i = 0; i < x; i++) c[i] = x - i; // 山型 let d = new Float64Array(x); let m = Math.floor(x / 2); for (let i = 0; i < m; i++) d[i] = i + 1.0; for (let i = m; i < x; i++) d[i] = x - i; return [a, b, c, d]; } function check(xs) { for (let i = 0; i < xs.length - 1; i++) { if (xs[i] > xs[i + 1]) throw new Error("sort error"); } } function test(func, xs) { for (let x of xs) { let rs = []; for (let ys of make_data(x)) { let s = new Date().getTime(); func(ys); let e = new Date().getTime(); rs.push(e - s); check(ys); } console.log(x, ":", rs); } } // メソッド sort() の時間計測 function test1(xs) { for (let x of xs) { let rs = []; for (let ys of make_data(x)) { let s = new Date().getTime(); ys.sort(); let e = new Date().getTime(); rs.push(e - s); check(ys); } console.log(x, ":", rs); } } // バブルソート function buble_sort(buff) { let k = buff.length - 1; for (let i = 0; i < k; i++) { for (let j = k; j > i; j--) { if (buff[j - 1] > buff[j]) { let temp = buff[j]; buff[j] = buff[j - 1]; buff[j - 1] = temp; } } } return buff; } // 単純挿入ソート function insert_sort(buff) { let k = buff.length; for (let i = 1; i < k; i++) { let temp = buff[i]; let j = i - 1; for (; j >=0 && temp < buff[j]; j--) { buff[j + 1] = buff[j]; } buff[j + 1] = temp; } return buff; } // シェルソート function shell_sort(buff) { let k = buff.length; let gap = 1; while (gap < Math.floor(k / 9)) gap = gap * 3 + 1; while (gap > 0) { for (let i = gap; i < k; i++) { let temp = buff[i]; let j = i - gap; while (j >= 0 && temp < buff[j]) { buff[j + gap] = buff[j]; j -= gap; } buff[j + gap] = temp; } gap = Math.floor(gap / 3); } return buff; } // クイックソート (単純版) function qsort(buff, low, high) { let pivot = buff[low + Math.floor((high - low)/2)]; let i = low; let j = high; while (true) { while (pivot > buff[i]) i++; while (pivot < buff[j]) j--; if (i >= j) break; let temp = buff[i]; buff[i] = buff[j]; buff[j] = temp; i++; j--; } if (low < i - 1) qsort(buff, low, i - 1); if (high > j + 1) qsort(buff, j + 1, high); } function quick_sort(buff) { qsort(buff, 0, buff.length - 1); return buff; } // 改良版 // 枢軸の選択 (median-of-3) function select_pivot(buff, low, high) { let a = buff[low]; let b = buff[low + Math.floor((high - low) / 2)]; let c = buff[high]; if (a > b) [a, b] = [b, a]; if (b > c) { b = c; if (a > b) b = a; } return b; } const limit = 10; function qsort2(buff, low, high) { let stack = []; while (true) { if ((high - low) <= limit) { if (stack.length == 0) break; [low, high] = stack.pop(); } else { let pivot = select_pivot(buff, low, high) let i = low let j = high while (true) { while (pivot > buff[i]) i++; while (pivot < buff[j]) j--; if (i >= j) break; let temp = buff[i]; buff[i] = buff[j]; buff[j] = temp; i++; j--; } if (i - low > high - j) { stack.push([low, i - 1]); low = j + 1; } else { stack.push([j + 1, high]); high = i - 1; } } } insert_sort(buff) } function quick_sort2(buff) { qsort2(buff, 0, buff.length - 1); return buff; }
> test(buble_sort, [10000,20000,40000,80000]) 10000 : [ 215, 83, 115, 100 ] 20000 : [ 888, 332, 466, 402 ] 40000 : [ 3790, 1315, 1850, 1599 ] 80000 : [ 15422, 5283, 7385, 6336 ] undefined > test(insert_sort, [10000,20000,40000,80000]) 10000 : [ 45, 0, 83, 41 ] 20000 : [ 174, 0, 328, 164 ] 40000 : [ 667, 1, 1318, 662 ] 80000 : [ 2641, 0, 5302, 2643 ] undefined
> test(shell_sort, [10000,20000,40000,80000]) 10000 : [ 7, 1, 0, 1 ] 20000 : [ 4, 0, 1, 1 ] 40000 : [ 8, 3, 2, 3 ] 80000 : [ 18, 5, 6, 5 ] undefined > test(shell_sort, [100000,200000,400000,800000]) 100000 : [ 22, 5, 7, 7 ] 200000 : [ 49, 12, 14, 13 ] 400000 : [ 108, 25, 31, 30 ] 800000 : [ 243, 54, 66, 64 ] undefined
> test(quick_sort, [10000,20000,40000,80000]) 10000 : [ 2, 0, 0, 77 ] Uncaught RangeError: Maximum call stack size exceeded at qsort (REPL4:99:15) at qsort (REPL4:113:22) at qsort (REPL4:113:22) at qsort (REPL4:113:22) at qsort (REPL4:113:22) at qsort (REPL4:113:22) at qsort (REPL4:113:22) at qsort (REPL4:113:22) at qsort (REPL4:113:22)
> test(quick_sort2, [10000,20000,40000,80000]) 10000 : [ 10, 1, 1, 1 ] 20000 : [ 5, 2, 1, 3 ] 40000 : [ 5, 1, 1, 5 ] 80000 : [ 12, 3, 4, 11 ] undefined > test(quick_sort2, [100000,200000,400000,800000]) 100000 : [ 14, 4, 4, 15 ] 200000 : [ 30, 7, 9, 31 ] 400000 : [ 63, 15, 16, 68 ] 800000 : [ 181, 33, 34, 152 ] undefined
> test1([100000, 200000, 400000, 800000]) 100000 : [ 13, 5, 5, 17 ] 200000 : [ 24, 12, 9, 35 ] 400000 : [ 53, 27, 19, 75 ] 800000 : [ 110, 54, 40, 159 ] undefined
> var a = [1, 10, 2, 20, 3, 30] undefined > a.sort() [ 1, 10, 2, 20, 3, 30 ] > a.sort((a, b) => a - b) [ 1, 2, 3, 10, 20, 30 ]
> var b = new Int32Array([1,10,2,20,3,30]) undefined > b Int32Array(6) [ 1, 10, 2, 20, 3, 30 ] > b.sort() Int32Array(6) [ 1, 2, 3, 10, 20, 30 ] > b Int32Array(6) [ 1, 2, 3, 10, 20, 30 ] > b.sort((a, b) => b - a) Int32Array(6) [ 30, 20, 10, 3, 2, 1 ]
約数 (divisor) は整数 n を割り切る整数のことです。たとえば、24 の正の約数は 1, 2, 3, 4, 6, 8, 12, 24 の 8 個あります。ここでは正の約数を考えることにします。
正の約数が 1 と自分自身しかない自然数のことを素数といいます。1 ではない正整数で、素数ではないものを合成数といいます。合成数は素数の積の形に書き表すことができます。これを「素因数分解 (prime factorization)」といいます。
たとえば、6 = 2 * 3, 12 = 22 * 3, 30 = 2 * 3 * 5 と素因数分解することができます。素数の並べ方を除けば、素因数分解はただの一通りしかありません。これを「素因数分解の一意性」といいます。
詳しい説明は拙作のページをお読みください。
// // divisor.js : 約数 // // Copyright (c) 2025 Makoto Hiroi // // Released under the MIT license // https://opensource.org/license/mit/ // // 素因数分解 function factor_sub(n, p){ let c = 0n; while (n % p == 0n) { n /= p; c++; } return [c, n] } function factorization(n) { let ps = []; let wheel = [1n, 2n, 2n, 4n, 2n, 4n, 2n, 4n, 6n, 2n, 6n]; let [i, s] = [0, 3n]; let [x, c, m] = [2n, 0n, n]; while (m >= x * x) { [c, m] = factor_sub(m, x); if (c > 0n) ps.push([x, c]) x += wheel[i] if (++i >= wheel.length) i = s; } if (m > 1n) ps.push([m, 1n]); return ps; } // 約数の個数 function divisor_count(n) { return factorization(n).reduce((a, [p, q]) => a * (q + 1n), 1n); } // 約数の合計値 function divisor_total(n) { return factorization(n).reduce((a, [p, q]) => a * (p ** (q + 1n) - 1n) / (p - 1n), 1n); } // p ** q の約数を求める function divisor_sub(p, q) { let a = []; for (let i = 0n; i <= q; i++) a.push(p ** i); return a; } // 直積集合 function product(xs, ys) { let a = []; for (let x of xs) { for (let y of ys) a.push(x * y); } return a; } // 比較 function compare(a, b) { if (a > b) return 1; if (a == b) return 0 return -1; } // 約数を求める function divisors(n) { let xs = factorization(n); return xs.reduce((a, [p, q]) => product(a, divisor_sub(p, q)), [1n]).sort(compare); } // 完全数 function perfect_number(n) { for (let x = 2n; x <= n; x++) { if (divisor_total(x) - x == x) { console.log('%s', x); } } } // 友愛数 function amicable_number(n) { for (let x = 2n; x <= n; x++) { let m = divisor_total(x) - x; if (m < x && x == divisor_total(m) - m) { console.log('%s %s', m, x); } } } // 約数関数 function divisor_sigma(n, k) { if (k == 0) return divisor_count(n); let xs = factorization(n); return xs.reduce((a, [p, q]) => a * (p ** (k * (q + 1n)) - 1n) / (p ** k - 1n), 1n); } // オイラーのトーシェント関数 (公式) function totient(n) { let xs = factorization(n); return xs.reduce((d, [p, q]) => d * (p - 1n) / p, n); }
> var a = [24n, 12345678n, 123456789n, 1234567890n, 1111111111n] undefined > for (let x of a) console.log(x, factorization(x)); 24n [ [ 2n, 3n ], [ 3n, 1n ] ] 12345678n [ [ 2n, 1n ], [ 3n, 2n ], [ 47n, 1n ], [ 14593n, 1n ] ] 123456789n [ [ 3n, 2n ], [ 3607n, 1n ], [ 3803n, 1n ] ] 1234567890n [ [ 2n, 1n ], [ 3n, 2n ], [ 5n, 1n ], [ 3607n, 1n ], [ 3803n, 1n ] ] 1111111111n [ [ 11n, 1n ], [ 41n, 1n ], [ 271n, 1n ], [ 9091n, 1n ] ] undefined > for (let x of a) console.log(x, divisor_count(x)); 24n 8n 12345678n 24n 123456789n 12n 1234567890n 48n 1111111111n 16n undefined > for (let x of a) console.log(x, divisor_total(x)); 24n 60n 12345678n 27319968n 123456789n 178422816n 1234567890n 3211610688n 1111111111n 1246404096n undefined > for (let x of a) console.log(x, divisors(x)) 24n [ 1n, 2n, 3n, 4n, 6n, 8n, 12n, 24n ] 12345678n [ 1n, 2n, 3n, 6n, 9n, 18n, 47n, 94n, 141n, 282n, 423n, 846n, 14593n, 29186n, 43779n, 87558n, 131337n, 262674n, 685871n, 1371742n, 2057613n, 4115226n, 6172839n, 12345678n ] 123456789n [ 1n, 3n, 9n, 3607n, 3803n, 10821n, 11409n, 32463n, 34227n, 13717421n, 41152263n, 123456789n ] 1234567890n [ 1n, 2n, 3n, 5n, 6n, 9n, 10n, 15n, 18n, 30n, 45n, 90n, 3607n, 3803n, 7214n, 7606n, 10821n, 11409n, 18035n, 19015n, 21642n, 22818n, 32463n, 34227n, 36070n, 38030n, 54105n, 57045n, 64926n, 68454n, 108210n, 114090n, 162315n, 171135n, 324630n, 342270n, 13717421n, 27434842n, 41152263n, 68587105n, 82304526n, 123456789n, 137174210n, 205761315n, 246913578n, 411522630n, 617283945n, 1234567890n ] 1111111111n [ 1n, 11n, 41n, 271n, 451n, 2981n, 9091n, 11111n, 100001n, 122221n, 372731n, 2463661n, 4100041n, 27100271n, 101010101n, 1111111111n ] undefined > perfect_number(10000n) 6n 28n 496n 8128n undefined > amicable_number(100000n) 220n 284n 1184n 1210n 2620n 2924n 5020n 5564n 6232n 6368n 10744n 10856n 12285n 14595n 17296n 18416n 66928n 66992n 67095n 71145n 63020n 76084n 69615n 87633n 79750n 88730n undefined > for (let x of a) console.log(x, divisor_sigma(x, 0n)) 24n 8n 12345678n 24n 123456789n 12n 1234567890n 48n 1111111111n 16n undefined > for (let x of a) console.log(x, divisor_sigma(x, 1n)) 24n 60n 12345678n 27319968n 123456789n 178422816n 1234567890n 3211610688n 1111111111n 1246404096n undefined > for (let x of a) console.log(x, divisor_sigma(x, 2n)) 24n 850n 12345678n 214137553857500n 123456789n 17123257639169500n 1234567890n 2226023493092035000n 1111111111n 1245528410223519376n undefined > for (let x of a) console.log(x, totient(x)) 24n 8n 12345678n 4027392n 123456789n 82260072n 1234567890n 329040288n 1111111111n 981720000n