* Sum of the digits of `|m|` in the given base, in a single O(digits) pass * (via native `toString(base)` for base 2..36, else a `checkDeadline`- * guarded mod/divide loop for larger bases) — see `bigintDigitsLSB` for the * same base-36 cutoff rationale. Avoids materializing an intermediate digit
( m: bigint, base: bigint, deadline: number | undefined )
| 94 | * For base 2..36 this delegates to bigint's native `toString(base)` — a |
| 95 | * linear-time, digit-by-digit reinterpretation of the binary representation |
| 96 | * — instead of the naive repeated-mod-and-divide loop, which is O(digits²): |
| 97 | * quadratic enough to turn a several-hundred-thousand-digit input into a |
| 98 | * many-second hang (WP-2.18). For base > 36 (not supported by `toString`), |
| 99 | * falls back to the mod/divide loop, guarded by `checkDeadline`. |
| 100 | */ |
| 101 | function bigintDigitsLSB( |
| 102 | m: bigint, |
| 103 | base: bigint, |
| 104 | deadline: number | undefined |
| 105 | ): bigint[] { |
| 106 | if (m === 0n) return [0n]; |
| 107 | if (base <= 36n) { |
| 108 | const s = m.toString(Number(base)); |
| 109 | const digits = new Array<bigint>(s.length); |
| 110 | for (let i = 0; i < s.length; i++) { |
| 111 | if ((i & 0xffff) === 0) checkDeadline(deadline); |
| 112 | digits[s.length - 1 - i] = charToDigit(s.charCodeAt(i)); |
| 113 | } |
| 114 | return digits; |
| 115 | } |
| 116 | const digits: bigint[] = []; |
| 117 | let x = m; |
| 118 | // Unlike the base<=36 loop above, each step here is a bigint mod/div |
| 119 | // against an arbitrary (possibly itself huge) `base` — its cost is not a |
| 120 | // fixed small constant, so check the deadline every iteration rather than |
| 121 | // amortizing over a stride. |
| 122 | while (x > 0n) { |
| 123 | checkDeadline(deadline); |
| 124 | digits.push(x % base); |
no test coverage detected