Skip to content

Commit 1b86c2a

Browse files
feat: add Zeckendorf representation algorithm
1 parent 1d88e87 commit 1b86c2a

2 files changed

Lines changed: 83 additions & 0 deletions

File tree

‎Maths/ZeckendorfRepresentation.js‎

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/**
2+
* @function zeckendorfRepresentation
3+
* @description Zeckendorf's theorem states that every positive integer
4+
* can be uniquely represented as a sum of non-consecutive Fibonacci numbers.
5+
* This function returns those Fibonacci numbers.
6+
* @param {number} n - A positive integer
7+
* @returns {number[]} - Array of Fibonacci numbers that sum to n
8+
* @see https://en.wikipedia.org/wiki/Zeckendorf%27s_theorem
9+
* @example zeckendorfRepresentation(11) => [8, 3]
10+
* @example zeckendorfRepresentation(100) => [89, 8, 3]
11+
*/
12+
const zeckendorfRepresentation = (n) => {
13+
if (!Number.isInteger(n) || n < 1) {
14+
throw new TypeError('Input must be a positive integer')
15+
}
16+
const fibs = [1, 2]
17+
while (fibs[fibs.length - 1] < n) {
18+
const len = fibs.length
19+
fibs.push(fibs[len - 1] + fibs[len - 2])
20+
}
21+
const result = []
22+
let remaining = n
23+
for (let i = fibs.length - 1; i >= 0 && remaining > 0; i--) {
24+
if (fibs[i] <= remaining) {
25+
result.push(fibs[i])
26+
remaining -= fibs[i]
27+
}
28+
}
29+
return result
30+
}
31+
32+
export { zeckendorfRepresentation }
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { zeckendorfRepresentation } from '../ZeckendorfRepresentation.js'
2+
3+
describe('zeckendorfRepresentation', () => {
4+
test('zeckendorfRepresentation(1) returns [1]', () => {
5+
expect(zeckendorfRepresentation(1)).toEqual([1])
6+
})
7+
8+
test('zeckendorfRepresentation(2) returns [2]', () => {
9+
expect(zeckendorfRepresentation(2)).toEqual([2])
10+
})
11+
12+
test('zeckendorfRepresentation(3) returns [3]', () => {
13+
expect(zeckendorfRepresentation(3)).toEqual([3])
14+
})
15+
16+
test('zeckendorfRepresentation(11) returns [8, 3]', () => {
17+
expect(zeckendorfRepresentation(11)).toEqual([8, 3])
18+
})
19+
20+
test('zeckendorfRepresentation(100) returns [89, 8, 3]', () => {
21+
expect(zeckendorfRepresentation(100)).toEqual([89, 8, 3])
22+
})
23+
24+
test('result sums to original number', () => {
25+
const result = zeckendorfRepresentation(50)
26+
const sum = result.reduce((acc, n) => acc + n, 0)
27+
expect(sum).toBe(50)
28+
})
29+
30+
test('no two consecutive Fibonacci numbers in result', () => {
31+
const fibs = [1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
32+
const result = zeckendorfRepresentation(100)
33+
for (let i = 0; i < result.length - 1; i++) {
34+
const idx1 = fibs.indexOf(result[i])
35+
const idx2 = fibs.indexOf(result[i + 1])
36+
expect(Math.abs(idx1 - idx2)).toBeGreaterThan(1)
37+
}
38+
})
39+
40+
test('throws TypeError for zero', () => {
41+
expect(() => zeckendorfRepresentation(0)).toThrow(TypeError)
42+
})
43+
44+
test('throws TypeError for negative input', () => {
45+
expect(() => zeckendorfRepresentation(-11)).toThrow(TypeError)
46+
})
47+
48+
test('throws TypeError for float input', () => {
49+
expect(() => zeckendorfRepresentation(11.5)).toThrow(TypeError)
50+
})
51+
})

0 commit comments

Comments
 (0)