diff --git a/algorithm.js b/algorithm.js index ae4268a..2841188 100644 --- a/algorithm.js +++ b/algorithm.js @@ -234,14 +234,13 @@ const algorithm = { delete algorithm.data[2][key]; } } - const sequence = sequences[sequences.current]; const colorScheme = colors[colors.current]; const color = n => ({ value: n, color: n === undefined ? undefined : colorScheme(n) }); // set first three rows for (let x = left; x <= right; x++) { algorithm.data[0][x] = color(0n); algorithm.data[1][x] = color(1n); - algorithm.data[2][x] = color(BigInt(sequence(x))); + algorithm.data[2][x] = color(BigInt(sequences.getFromCurrent(x))); } // shrink height for (let key in algorithm.data) { diff --git a/events.js b/events.js index d942bdc..5f14636 100644 --- a/events.js +++ b/events.js @@ -105,6 +105,7 @@ const events = { const element = ui.sections.sequence.select; const option = element[element.selectedIndex]; sequences.current = option.value; + sequences.resetData(); if (option.dataset.param) { element.dataset.requiresParam = ""; sequences.param = option.dataset.param; diff --git a/index.html b/index.html index e7e9a01..5494ce6 100644 --- a/index.html +++ b/index.html @@ -53,6 +53,7 @@

Number Walls

+ diff --git a/sequences.js b/sequences.js index 1eae421..cd91fe6 100644 --- a/sequences.js +++ b/sequences.js @@ -1,6 +1,19 @@ const sequences = { current: undefined, param: undefined, + // must be an object to allow negative indeces + data: {}, + getFromCurrent(n) { + if (n in sequences.data) { + return sequences.data[n]; + } + const currentFunction = sequences[sequences.current]; + sequences.data[n] = currentFunction(n); + return sequences.data[n]; + }, + resetData() { + sequences.data = {}; + }, custom: () => 0, round(n) { return Math.round(sequences.param * n); @@ -31,29 +44,30 @@ const sequences = { return Number(solution == Math.floor(solution)); }, fibonacci(n) { - // no floating point precision issues up to 60 - if (Math.abs(n) < 60) { - return BigInt(Math.round((Math.pow(0.5 * (1 + Math.sqrt(5)), n) - Math.pow(0.5 * (1 - Math.sqrt(5)), n)) / Math.sqrt(5))); + if (n < 0) { + n = Math.abs(n); } - // get access to already calculated numbers - const previous = algorithm.data[2]; - // recursive definition backward and forward - if (n - 2 in previous && n - 1 in previous) { - return previous[n - 2].value + previous[n - 1].value; + if ((n == 1) || (n==2)) { + return 1; } - if (n + 2 in previous && n + 1 in previous) { - return previous[n + 2].value - previous[n + 1].value; + if (n == 0) { + return 0; } - // start from last two reliably in constant time computable terms and use the recursive formula - let a = sequences.fibonacci(58), b = sequences.fibonacci(59); - for (let i = 59; i < Math.abs(n); i++) { - [a, b] = [b, a + b]; + return sequences.getFromCurrent(n-1) + sequences.getFromCurrent(n-2); + }, + hofstadterQ(n) { + // undefined for n < 1 + if (n < 1) { + return 0; } - // rule for negative numbers - if (n < 0 && n % 2 == 0) { - b = -b; + if ((n == 1) || (n==2)) { + return 1; } - return b; + const firstTermIndex = n - sequences.getFromCurrent(n-1); + const secondTermIndex = n - sequences.getFromCurrent(n-2); + const firstTerm = sequences.getFromCurrent(firstTermIndex); + const secondTerm = sequences.getFromCurrent(secondTermIndex); + return firstTerm + secondTerm; }, dakotaB(n) { if (n == 0) return 0; @@ -64,5 +78,5 @@ const sequences = { }, dakotaC: n => n == 0 ? 1 : sequences.dakotaB(2 * n) - 2 * sequences.dakotaB(2 * n - 1) + 3, dakotaF: n => n == 1 ? [0, 1] : n == 2 ? [1, -1] : n == 3 ? [0, -1] : [1, 0], - dakota: n => n < 0 ? 0 : sequences.dakotaF(sequences.dakotaC(Math.floor(n / 2)))[n % 2] + dakota: n => n < 0 ? 0 : sequences.dakotaF(sequences.dakotaC(Math.floor(n / 2)))[n % 2], } \ No newline at end of file