Skip to content

Instantly share code, notes, and snippets.

@qntm
Last active November 23, 2025 23:54
Show Gist options
  • Select an option

  • Save qntm/e8e7591960ed8b26b7b2eaec5ebce709 to your computer and use it in GitHub Desktop.

Select an option

Save qntm/e8e7591960ed8b26b7b2eaec5ebce709 to your computer and use it in GitHub Desktop.
How many valid JSON strings are there?
/**
Code for enumerating valid JSON strings.
Bounds checking is the responsibility of the caller.
The case N = 0 is intentionally not handled.
This code attempts to be somewhat readable without significantly impacting performance.
https://qntm.org/jsoncount
https://qntm.org/jsonutf8
*/
import assert from 'node:assert/strict'
// First some constants
const NUM_DIGITS = BigInt(['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'].length)
const NUM_1_BYTE_CHARS = (0x7Fn + 1n) - 0x0020n - BigInt(['\\', '"'].length) // 94
const NUM_2_BYTE_CHARS = (0x7FFn + 1n) - 0x80n // 1920
const NUM_3_BYTE_CHARS = (0xFFFFn + 1n) - 0x800n // 63488
const NUM_4_BYTE_CHARS = (0x10FFFFn + 1n) - 0x10000n // 1048576
const NUM_ESCAPES = BigInt(['"', '\\', '/', 'b', 'f', 'n', 'r', 't'].length) // 8
const NUM_HEX_CHARS = BigInt([
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'A', 'B', 'C', 'D', 'E', 'F',
'a', 'b', 'c', 'd', 'e', 'f'
].length) // 22, not 16
const NUM_HEX_ESCAPES = NUM_HEX_CHARS ** 4n // 234,256, not 65,536
const NUM_ES = BigInt(['E', 'e'].length) // 2
const NUM_SIGNS = BigInt(['-', '+'].length) // 2
// Memoization is incredibly important as the numbers get larger,
// there are many combinations
const memoize = f => {
const known = []
return n => known[n] ??= f(n)
}
// Now for some enumeration.
// Use BigInts throughout because we're going to be exceeding `Number.MAX_SAFE_INTEGER` at N = 5
class Counter {
#numWs
#encoding
constructor (allowWs, encoding) {
this.#numWs = allowWs
? BigInt(['\u0020', '\u000A', '\u000D', '\u0009'].length) // 4
: 0n
this.#encoding = encoding
}
// E.g. "123"
// [1-9][0-9]*
countPositiveIntegers (n) {
return (NUM_DIGITS - 1n) * NUM_DIGITS ** BigInt(n - 1)
}
// E.g. "123.456"
// 0.[0-9]{3}
// [1-9].[0-9][0-9][0-9], [1-9][0-9].[0-9][0-9], [1-9][0-9][0-9].[0-9]
countDecimals (n) {
return NUM_DIGITS ** BigInt(n - 2) +
(NUM_DIGITS - 1n) * NUM_DIGITS ** BigInt(n - 2) * BigInt(n - 2)
}
// E.g. "123e456"
// 0[eE][0-9][0-9][0-9]
// [1-9][eE][0-9][0-9][0-9], [1-9][0-9][eE][0-9][0-9], [1-9][0-9][0-9][eE][0-9]
countExponents (n) {
return NUM_ES * NUM_DIGITS ** BigInt(n - 2) +
(NUM_DIGITS - 1n) * NUM_ES * NUM_DIGITS ** BigInt(n - 2) * BigInt(n - 2)
}
// E.g. "123e+456"
// 0[eE][+-][0-9][0-9][0-9]
// [1-9][eE][+-][0-9][0-9][0-9], [1-9][0-9][eE][+-][0-9][0-9], [1-9][0-9][0-9][eE][+-][0-9]
countSignedExponents (n) {
return NUM_ES * NUM_SIGNS * NUM_DIGITS ** BigInt(n - 3) +
(NUM_DIGITS - 1n) * NUM_ES * NUM_SIGNS * NUM_DIGITS ** BigInt(n - 3) * BigInt(n - 3)
}
// E.g. "123.456e789"
// 0.[0-9][eE][0-9], 1 combination
// [1-9].[0-9][eE][0-9], 1 combination
// 0.[0-9][eE][0-9][0-9], 0.[0-9][0-9][eE][0-9], 2 combinations
// [1-9].[0-9][eE][0-9][0-9], [1-9].[0-9][0-9][eE][0-9], [1-9][0-9].[0-9][eE][0-9], 3 combinations
countDecimalExponents (n) {
return NUM_ES * NUM_DIGITS ** BigInt(n - 3) * BigInt(n - 4) +
(NUM_DIGITS - 1n) * NUM_ES * NUM_DIGITS ** BigInt(n - 3) * (BigInt(n - 4) * BigInt(n - 3) / 2n)
}
// E.g. "123.456E-789"
// 0.[0-9][eE][+-][0-9]
// [1-9].[0-9][eE][+-][0-9]
countDecimalSignedExponents (n) {
return NUM_ES * NUM_SIGNS * NUM_DIGITS ** BigInt(n - 4) * BigInt(n - 5) +
(NUM_DIGITS - 1n) * NUM_ES * NUM_SIGNS * NUM_DIGITS ** BigInt(n - 4) * (BigInt(n - 5) * BigInt(n - 4) / 2n)
}
countNonNegativeNumbers (n) {
let l = 0n
if (n === 1) {
l += 1n // "0"
}
l += this.countPositiveIntegers(n)
if (n >= 3) {
l += this.countDecimals(n)
l += this.countExponents(n)
}
if (n >= 4) {
l += this.countSignedExponents(n)
}
if (n >= 5) {
l += this.countDecimalExponents(n)
}
if (n >= 6) {
l += this.countDecimalSignedExponents(n)
}
return l
}
countNegativeNumbers (n) {
return this.countNonNegativeNumbers(n - 1)
}
countNumbers (n) {
let l = 0n
l += this.countNonNegativeNumbers(n)
if (n >= 2) {
l += this.countNegativeNumbers(n)
}
return l
}
// Highly recursive, memoization is crucial here
countStringInteriors = memoize(n => {
if (n === 0) {
return 1n
}
let l = 0n
if (this.#encoding === 'utf32') {
if (n >= 1) {
l += this.countStringInteriors(n - 1) * (NUM_1_BYTE_CHARS + NUM_2_BYTE_CHARS + NUM_3_BYTE_CHARS + NUM_4_BYTE_CHARS)
}
} else if (this.#encoding === 'utf16') {
if (n >= 1) {
l += this.countStringInteriors(n - 1) * (NUM_1_BYTE_CHARS + NUM_2_BYTE_CHARS + NUM_3_BYTE_CHARS)
}
if (n >= 2) {
l += this.countStringInteriors(n - 2) * NUM_4_BYTE_CHARS
}
} else if (this.#encoding === 'utf8') {
if (n >= 1) {
l += this.countStringInteriors(n - 1) * NUM_1_BYTE_CHARS
}
if (n >= 2) {
l += this.countStringInteriors(n - 2) * NUM_2_BYTE_CHARS
}
if (n >= 3) {
l += this.countStringInteriors(n - 3) * NUM_3_BYTE_CHARS
}
if (n >= 4) {
l += this.countStringInteriors(n - 4) * NUM_4_BYTE_CHARS
}
} else {
throw Error('bad encoding')
}
if (n >= 2) {
l += this.countStringInteriors(n - 2) * NUM_ESCAPES
}
if (n >= 6) {
l += this.countStringInteriors(n - 6) * NUM_HEX_ESCAPES
}
return l
})
countStrings (n) {
return this.countStringInteriors(n - 2)
}
countArrayInteriorsK = memoize(k => {
if (k === 0) {
return n => this.#numWs ** BigInt(n)
}
if (k === 1) {
return n => this.countElements(n)
}
return memoize(n => {
// Try every possible location for the comma after the first element
let l = 0n
for (let i = 1; (k - 1) * 2 - 1 <= n - (i + 1); i++) {
l += this.countElements(i) * this.countArrayInteriorsK(k - 1)(n - (i + 1))
}
return l
})
})
countArrayInteriors = memoize(n => {
// Try every possible number of array elements
let l = 0n
for (let k = 0; k * 2 - 1 <= n; k++) {
l += this.countArrayInteriorsK(k)(n)
}
return l
})
countArrays (n) {
return this.countArrayInteriors(n - 2)
}
// A key is a whitespaced string
countKeys = memoize(n => {
// Try every possible size of key
let l = 0n
for (let w = 0; w < n; w++) {
l += this.countStrings(n - w) * this.#numWs ** BigInt(w) * BigInt(w + 1)
}
return l
})
countMembers = memoize(n => {
// Try every possible location for the colon between the key and value
let l = 0n
for (let i = 2; i + 1 < n; i++) {
l += this.countKeys(i) * this.countElements(n - (i + 1))
}
return l
})
countObjectInteriorsK = memoize(k => {
if (k === 0) {
return n => this.#numWs ** BigInt(n)
}
if (k === 1) {
return n => this.countMembers(n)
}
return memoize(n => {
// Try every possible location for the comma after the first key and value
let l = 0n
for (let i = 4; (k - 1) * 5 - 1 <= n - (i + 1); i++) {
l += this.countMembers(i) * this.countObjectInteriorsK(k - 1)(n - (i + 1))
}
return l
})
})
countObjectInteriors = memoize(n => {
// Try every possible number of key-value pairs
let l = 0n
for (let k = 0; 5 * k - 1 <= n; k++) {
l += this.countObjectInteriorsK(k)(n)
}
return l
})
countObjects (n) {
return this.countObjectInteriors(n - 2)
}
countValues = memoize(n => {
let l = 0n
if (n === 4) {
l += 2n // "null", "true"
}
if (n === 5) {
l += 1n // "false"
}
if (n >= 1) {
l += this.countNumbers(n)
}
if (n >= 2) {
l += this.countStrings(n)
l += this.countArrays(n)
l += this.countObjects(n)
}
return l
})
countElements = memoize(n => {
// Try every possible size of value
let l = 0n
for (let w = 0; w < n; w++) {
l += this.countValues(n - w) * this.#numWs ** BigInt(w) * BigInt(w + 1)
}
return l
})
}
const counter32 = new Counter(true, 'utf32')
const counter32NoWs = new Counter(false, 'utf32')
const counter16 = new Counter(true, 'utf16')
const counter8 = new Counter(true, 'utf8')
assert.equal(counter32.countPositiveIntegers(1), 9n)
assert.equal(counter32.countPositiveIntegers(2), 90n)
assert.equal(counter32.countPositiveIntegers(3), 900n)
assert.equal(counter32.countPositiveIntegers(4), 9000n)
assert.equal(counter32.countDecimals(3), 100n)
assert.equal(counter32.countDecimals(4), 1900n)
assert.equal(counter32.countDecimals(5), 28000n)
assert.equal(counter32.countDecimals(6), 370000n)
assert.equal(counter32.countExponents(3), 200n)
assert.equal(counter32.countExponents(4), 3800n)
assert.equal(counter32.countExponents(5), 56000n)
assert.equal(counter32.countExponents(6), 740000n)
assert.equal(counter32.countSignedExponents(4), 400n)
assert.equal(counter32.countSignedExponents(5), 7600n)
assert.equal(counter32.countSignedExponents(6), 112000n)
assert.equal(counter32.countSignedExponents(7), 1480000n)
assert.equal(counter32.countDecimalExponents(5), 2000n)
assert.equal(counter32.countDecimalExponents(6), 58000n)
assert.equal(counter32.countDecimalExponents(7), 1140000n)
assert.equal(counter32.countDecimalExponents(8), 18800000n)
assert.equal(counter32.countDecimalSignedExponents(6), 4000n)
assert.equal(counter32.countDecimalSignedExponents(7), 116000n)
assert.equal(counter32.countDecimalSignedExponents(8), 2280000n)
assert.equal(counter32.countDecimalSignedExponents(9), 37600000n)
assert.equal(counter32.countNumbers(1), 10n)
assert.equal(counter32.countNumbers(2), 100n)
assert.equal(counter32.countNumbers(3), 1290n)
assert.equal(counter32.countNumbers(4), 16300n)
assert.equal(counter32.countNumbers(5), 198700n)
assert.equal(counter32.countNumbers(6), 2367600n)
assert.equal(counter32.countStringInteriors(0), 1n)
assert.equal(counter32.countStringInteriors(1), 1114078n)
assert.equal(counter32.countStringInteriors(2), 1241169790092n)
assert.equal(counter32.countStringInteriors(3), 1382759957415027800n)
assert.equal(counter32.countStrings(2), 1n)
assert.equal(counter32.countStrings(3), 1114078n)
assert.equal(counter32.countStrings(4), 1241169790092n)
assert.equal(counter32.countStrings(4), 1114078n * 1114078n + 8n)
assert.equal(counter32.countArrayInteriorsK(0)(0), 1n)
assert.equal(counter32.countArrayInteriorsK(0)(1), 4n)
assert.equal(counter32.countArrayInteriorsK(1)(1), 10n)
assert.equal(counter32.countArrayInteriorsK(0)(2), 16n)
assert.equal(counter32.countArrayInteriorsK(1)(2), 183n)
assert.equal(counter32.countArrayInteriorsK(0)(3), 64n)
assert.equal(counter32.countArrayInteriorsK(1)(3), 1116690n)
assert.equal(counter32.countArrayInteriorsK(2)(3), 100n)
assert.equal(counter32.countArrayInteriorsK(0)(4), 256n)
assert.equal(counter32.countArrayInteriorsK(1)(4), 1241178737201n)
assert.equal(counter32.countArrayInteriorsK(2)(4), 3660n) // 183 * 10 + 10 * 183
assert.equal(counter32.countArrayInteriorsK(0)(5), 1024n)
assert.equal(counter32.countArrayInteriorsK(1)(5), 1382769886828373987n)
assert.equal(counter32.countArrayInteriorsK(2)(5), 22367289n)
assert.equal(counter32.countArrayInteriorsK(3)(5), 1000n)
assert.equal(counter32.countArrayInteriorsK(20)(39), 100000000000000000000n)
assert.equal(counter32.countArrayInteriors(0), 1n)
assert.equal(counter32.countArrayInteriors(1), 14n)
assert.equal(counter32.countArrayInteriors(2), 199n)
assert.equal(counter32.countArrayInteriors(3), 1116854n)
assert.equal(counter32.countArrayInteriors(4), 1241178741117n)
assert.equal(counter32.countArrayInteriors(5), 1382769886850743300n)
assert.equal(counter32.countArrays(2), 1n)
assert.equal(counter32.countArrays(3), 14n)
assert.equal(counter32.countArrays(4), 199n)
assert.equal(counter32.countArrays(5), 1116854n)
assert.equal(counter32.countArrays(6), 1241178741117n)
assert.equal(counter32.countArrays(7), 1382769886850743300n)
assert.equal(counter32.countKeys(2), 1n)
assert.equal(counter32.countKeys(3), 1114086n)
assert.equal(counter32.countKeys(4), 1241178702764n)
assert.equal(counter32.countObjectInteriorsK(0)(0), 1n)
assert.equal(counter32.countObjectInteriorsK(0)(1), 4n)
assert.equal(counter32.countObjectInteriorsK(0)(2), 16n)
assert.equal(counter32.countObjectInteriorsK(0)(3), 64n)
assert.equal(counter32.countObjectInteriorsK(0)(4), 256n)
assert.equal(counter32.countObjectInteriorsK(1)(4), 10n) // '{"":0}' through '{"":9}'
assert.equal(counter32.countObjectInteriorsK(0)(5), 1024n)
assert.equal(counter32.countObjectInteriorsK(1)(5), 11141043n) // 1114086 * 10 + 1 * 183
assert.equal(counter32.countObjectInteriors(0), 1n)
assert.equal(counter32.countObjectInteriors(1), 4n)
assert.equal(counter32.countObjectInteriors(2), 16n)
assert.equal(counter32.countObjectInteriors(3), 64n)
assert.equal(counter32.countObjectInteriors(4), 266n)
assert.equal(counter32.countObjectInteriors(5), 11142067n)
assert.equal(counter32.countObjects(2), 1n)
assert.equal(counter32.countObjects(3), 4n)
assert.equal(counter32.countObjects(4), 16n)
assert.equal(counter32.countObjects(5), 64n)
assert.equal(counter32.countObjects(6), 266n)
assert.equal(counter32.countObjects(7), 11142067n)
assert.equal(counter32.countValues(1), 10n) // 10 numbers
assert.equal(counter32.countValues(2), 103n) // 100 numbers, 1 string, 1 array, 1 object
assert.equal(counter32.countValues(3), 1115386n) // 1290 numbers, 1114078 strings, 14 arrays, 4 objects
assert.equal(counter32.countValues(4), 1241169806609n) // 1 null, 1 true, 16300 numbers, 1241169790092 strings, 199 arrays, 16 objects
assert.equal(counter32.countValues(5), 1382759957416343419n) // 1 false, 198700 numbers, 1382759957415027800 strings, 1116854 arrays, 64 objects
assert.equal(counter32.countElements(1), 10n)
assert.equal(counter32.countElements(2), 183n)
assert.equal(counter32.countElements(3), 1116690n)
assert.equal(counter32.countElements(4), 1241178737201n)
assert.equal(counter32.countElements(5), 1382769886828373987n)
assert.equal(counter32NoWs.countPositiveIntegers(1), 9n)
assert.equal(counter32NoWs.countPositiveIntegers(2), 90n)
assert.equal(counter32NoWs.countPositiveIntegers(3), 900n)
assert.equal(counter32NoWs.countPositiveIntegers(4), 9000n)
assert.equal(counter32NoWs.countDecimals(3), 100n)
assert.equal(counter32NoWs.countDecimals(4), 1900n)
assert.equal(counter32NoWs.countDecimals(5), 28000n)
assert.equal(counter32NoWs.countDecimals(6), 370000n)
assert.equal(counter32NoWs.countExponents(3), 200n)
assert.equal(counter32NoWs.countExponents(4), 3800n)
assert.equal(counter32NoWs.countExponents(5), 56000n)
assert.equal(counter32NoWs.countExponents(6), 740000n)
assert.equal(counter32NoWs.countSignedExponents(4), 400n)
assert.equal(counter32NoWs.countSignedExponents(5), 7600n)
assert.equal(counter32NoWs.countSignedExponents(6), 112000n)
assert.equal(counter32NoWs.countSignedExponents(7), 1480000n)
assert.equal(counter32NoWs.countDecimalExponents(5), 2000n)
assert.equal(counter32NoWs.countDecimalExponents(6), 58000n)
assert.equal(counter32NoWs.countDecimalExponents(7), 1140000n)
assert.equal(counter32NoWs.countDecimalExponents(8), 18800000n)
assert.equal(counter32NoWs.countDecimalSignedExponents(6), 4000n)
assert.equal(counter32NoWs.countDecimalSignedExponents(7), 116000n)
assert.equal(counter32NoWs.countDecimalSignedExponents(8), 2280000n)
assert.equal(counter32NoWs.countDecimalSignedExponents(9), 37600000n)
assert.equal(counter32NoWs.countNumbers(1), 10n)
assert.equal(counter32NoWs.countNumbers(2), 100n)
assert.equal(counter32NoWs.countNumbers(3), 1290n)
assert.equal(counter32NoWs.countNumbers(4), 16300n)
assert.equal(counter32NoWs.countNumbers(5), 198700n)
assert.equal(counter32NoWs.countNumbers(6), 2367600n)
assert.equal(counter32NoWs.countStringInteriors(0), 1n)
assert.equal(counter32NoWs.countStringInteriors(1), 1114078n)
assert.equal(counter32NoWs.countStringInteriors(2), 1241169790092n)
assert.equal(counter32NoWs.countStringInteriors(3), 1382759957415027800n)
assert.equal(counter32NoWs.countStrings(2), 1n)
assert.equal(counter32NoWs.countStrings(3), 1114078n)
assert.equal(counter32NoWs.countStrings(4), 1241169790092n)
assert.equal(counter32NoWs.countStrings(4), 1114078n * 1114078n + 8n)
assert.equal(counter32NoWs.countArrayInteriorsK(0)(0), 1n)
assert.equal(counter32NoWs.countArrayInteriorsK(0)(1), 0n)
assert.equal(counter32NoWs.countArrayInteriorsK(1)(1), 10n)
assert.equal(counter32NoWs.countArrayInteriorsK(0)(2), 0n)
assert.equal(counter32NoWs.countArrayInteriorsK(1)(2), 103n)
assert.equal(counter32NoWs.countArrayInteriorsK(0)(3), 0n)
assert.equal(counter32NoWs.countArrayInteriorsK(1)(3), 1115378n)
assert.equal(counter32NoWs.countArrayInteriorsK(2)(3), 100n)
assert.equal(counter32NoWs.countArrayInteriorsK(0)(4), 0n)
assert.equal(counter32NoWs.countArrayInteriorsK(1)(4), 1241169806497n)
assert.equal(counter32NoWs.countArrayInteriorsK(2)(4), 2060n) // 103n * 10n + 10n * 103n
assert.equal(counter32NoWs.countArrayInteriorsK(0)(5), 0n)
assert.equal(counter32NoWs.countArrayInteriorsK(1)(5), 1382759957416341979n)
assert.equal(counter32NoWs.countArrayInteriorsK(2)(5), 22318169n)
assert.equal(counter32NoWs.countArrayInteriorsK(3)(5), 1000n)
assert.equal(counter32NoWs.countArrayInteriorsK(20)(39), 100000000000000000000n)
assert.equal(counter32NoWs.countArrayInteriors(0), 1n)
assert.equal(counter32NoWs.countArrayInteriors(1), 10n)
assert.equal(counter32NoWs.countArrayInteriors(2), 103n)
assert.equal(counter32NoWs.countArrayInteriors(3), 1115478n)
assert.equal(counter32NoWs.countArrayInteriors(4), 1241169808557n)
assert.equal(counter32NoWs.countArrayInteriors(5), 1382759957438661148n)
assert.equal(counter32NoWs.countArrays(2), 1n)
assert.equal(counter32NoWs.countArrays(3), 10n)
assert.equal(counter32NoWs.countArrays(4), 103n)
assert.equal(counter32NoWs.countArrays(5), 1115478n)
assert.equal(counter32NoWs.countArrays(6), 1241169808557n)
assert.equal(counter32NoWs.countArrays(7), 1382759957438661148n)
assert.equal(counter32NoWs.countKeys(2), 1n)
assert.equal(counter32NoWs.countKeys(3), 1114078n)
assert.equal(counter32NoWs.countKeys(4), 1241169790092n)
assert.equal(counter32NoWs.countObjectInteriorsK(0)(0), 1n)
assert.equal(counter32NoWs.countObjectInteriorsK(0)(1), 0n)
assert.equal(counter32NoWs.countObjectInteriorsK(0)(2), 0n)
assert.equal(counter32NoWs.countObjectInteriorsK(0)(3), 0n)
assert.equal(counter32NoWs.countObjectInteriorsK(0)(4), 0n)
assert.equal(counter32NoWs.countObjectInteriorsK(1)(4), 10n) // '{"":0}' through '{"":9}'
assert.equal(counter32NoWs.countObjectInteriorsK(0)(5), 0n)
assert.equal(counter32NoWs.countObjectInteriorsK(1)(5), 11140883n) // 1114078 * 10 + 1 * 103
assert.equal(counter32NoWs.countObjectInteriors(0), 1n)
assert.equal(counter32NoWs.countObjectInteriors(1), 0n)
assert.equal(counter32NoWs.countObjectInteriors(2), 0n)
assert.equal(counter32NoWs.countObjectInteriors(3), 0n)
assert.equal(counter32NoWs.countObjectInteriors(4), 10n)
assert.equal(counter32NoWs.countObjectInteriors(5), 11140883n)
assert.equal(counter32NoWs.countObjects(2), 1n)
assert.equal(counter32NoWs.countObjects(3), 0n)
assert.equal(counter32NoWs.countObjects(4), 0n)
assert.equal(counter32NoWs.countObjects(5), 0n)
assert.equal(counter32NoWs.countObjects(6), 10n)
assert.equal(counter32NoWs.countObjects(7), 11140883n)
assert.equal(counter32NoWs.countValues(1), 10n) // 10 numbers
assert.equal(counter32NoWs.countValues(2), 103n) // 100 numbers, 1 string, 1 array, 1 object
assert.equal(counter32NoWs.countValues(3), 1115378n) // 1290 numbers, 1114078 strings, 10 arrays
assert.equal(counter32NoWs.countValues(4), 1241169806497n) // 1 null, 1 true, 16300 numbers, 1241169790092 strings, 103 arrays
assert.equal(counter32NoWs.countValues(5), 1382759957416341979n) // 1 false, 198700 numbers, 1382759957415027800 strings, 1115478 arrays
assert.equal(counter32NoWs.countElements(1), 10n)
assert.equal(counter32NoWs.countElements(2), 103n)
assert.equal(counter32NoWs.countElements(3), 1115378n)
assert.equal(counter32NoWs.countElements(4), 1241169806497n)
assert.equal(counter32NoWs.countElements(5), 1382759957416341979n)
assert.equal(counter16.countStringInteriors(0), 1n)
assert.equal(counter16.countStringInteriors(1), 65502n)
assert.equal(counter16.countStringInteriors(2), 4291560588n) // 1048584 * 1 + 65502 * 65502
assert.equal(counter16.countStringInteriors(3), 281174485984344n) // 1048584 * 65502 + 65502 * 4291560588
assert.equal(counter8.countStringInteriors(0), 1n)
assert.equal(counter8.countStringInteriors(1), 94n)
assert.equal(counter8.countStringInteriors(2), 10764n) // 94 * 94 + 1928
assert.equal(counter8.countStringInteriors(3), 1256536n) // 94 * 10764 + 1928 * 94 + 63488
assert.equal(counter8.countStringInteriors(4), 145883824n)
for (let n = 1; n <= 100; n++) {
console.log(n, counter8.countElements(n))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment