diff --git a/README.md b/README.md index 56d46ead..b0f178b5 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ a set of rules that precisely define a sequence of operations. * **Math** * `B` [Bit Manipulation](src/algorithms/math/bits) - set/get/update/clear bits, multiplication/division by two, make negative etc. * `B` [Factorial](src/algorithms/math/factorial) - * `B` [Fibonacci Number](src/algorithms/math/fibonacci) + * `B` [Fibonacci Number](src/algorithms/math/fibonacci) - classic and closed-form versions. * `B` [Primality Test](src/algorithms/math/primality-test) (trial division method) * `B` [Euclidean Algorithm](src/algorithms/math/euclidean-algorithm) - calculate the Greatest Common Divisor (GCD) * `B` [Least Common Multiple](src/algorithms/math/least-common-multiple) (LCM) diff --git a/src/algorithms/math/fibonacci/README.md b/src/algorithms/math/fibonacci/README.md index f4a5df83..5efb3543 100644 --- a/src/algorithms/math/fibonacci/README.md +++ b/src/algorithms/math/fibonacci/README.md @@ -17,4 +17,4 @@ The Fibonacci spiral: an approximation of the golden spiral created by drawing c ## References -[Wikipedia](https://en.wikipedia.org/wiki/Fibonacci_number) +- [Wikipedia](https://en.wikipedia.org/wiki/Fibonacci_number) diff --git a/src/algorithms/math/fibonacci/__test__/fibonacciClosedForm.test.js b/src/algorithms/math/fibonacci/__test__/fibonacciClosedForm.test.js deleted file mode 100644 index 5f4283b8..00000000 --- a/src/algorithms/math/fibonacci/__test__/fibonacciClosedForm.test.js +++ /dev/null @@ -1,23 +0,0 @@ -import fibonacciClosedForm from '../fibonacciClosedForm'; - -describe('fibonacciClosedForm', () => { - it('should calculate fibonacci correctly', () => { - expect(fibonacciClosedForm(1)).toBe(1); - expect(fibonacciClosedForm(2)).toBe(1); - expect(fibonacciClosedForm(3)).toBe(2); - expect(fibonacciClosedForm(4)).toBe(3); - expect(fibonacciClosedForm(5)).toBe(5); - expect(fibonacciClosedForm(6)).toBe(8); - expect(fibonacciClosedForm(7)).toBe(13); - expect(fibonacciClosedForm(8)).toBe(21); - expect(fibonacciClosedForm(20)).toBe(6765); - expect(fibonacciClosedForm(30)).toBe(832040); - expect(fibonacciClosedForm(50)).toBe(12586269025); - expect(fibonacciClosedForm(70)).toBe(190392490709135); - expect(fibonacciClosedForm(71)).toBe(308061521170129); - expect(fibonacciClosedForm(72)).toBe(498454011879264); - expect(fibonacciClosedForm(73)).toBe(806515533049393); - expect(fibonacciClosedForm(74)).toBe(1304969544928657); - expect(fibonacciClosedForm(75)).toBe(2111485077978050); - }); -}); diff --git a/src/algorithms/math/fibonacci/__test__/fibonacciNth.test.js b/src/algorithms/math/fibonacci/__test__/fibonacciNth.test.js index 4a098eba..573f25c6 100644 --- a/src/algorithms/math/fibonacci/__test__/fibonacciNth.test.js +++ b/src/algorithms/math/fibonacci/__test__/fibonacciNth.test.js @@ -19,5 +19,7 @@ describe('fibonacciNth', () => { expect(fibonacciNth(73)).toBe(806515533049393); expect(fibonacciNth(74)).toBe(1304969544928657); expect(fibonacciNth(75)).toBe(2111485077978050); + expect(fibonacciNth(80)).toBe(23416728348467685); + expect(fibonacciNth(90)).toBe(2880067194370816120); }); }); diff --git a/src/algorithms/math/fibonacci/__test__/fibonacciNthClosedForm.test.js b/src/algorithms/math/fibonacci/__test__/fibonacciNthClosedForm.test.js new file mode 100644 index 00000000..e29fc44b --- /dev/null +++ b/src/algorithms/math/fibonacci/__test__/fibonacciNthClosedForm.test.js @@ -0,0 +1,31 @@ +import fibonacciNthClosedForm from '../fibonacciNthClosedForm'; + +describe('fibonacciClosedForm', () => { + it('should throw an error when trying to calculate fibonacci for not allowed positions', () => { + const calculateFibonacciForNotAllowedPosition = () => { + fibonacciNthClosedForm(76); + }; + + expect(calculateFibonacciForNotAllowedPosition).toThrow(); + }); + + it('should calculate fibonacci correctly', () => { + expect(fibonacciNthClosedForm(1)).toBe(1); + expect(fibonacciNthClosedForm(2)).toBe(1); + expect(fibonacciNthClosedForm(3)).toBe(2); + expect(fibonacciNthClosedForm(4)).toBe(3); + expect(fibonacciNthClosedForm(5)).toBe(5); + expect(fibonacciNthClosedForm(6)).toBe(8); + expect(fibonacciNthClosedForm(7)).toBe(13); + expect(fibonacciNthClosedForm(8)).toBe(21); + expect(fibonacciNthClosedForm(20)).toBe(6765); + expect(fibonacciNthClosedForm(30)).toBe(832040); + expect(fibonacciNthClosedForm(50)).toBe(12586269025); + expect(fibonacciNthClosedForm(70)).toBe(190392490709135); + expect(fibonacciNthClosedForm(71)).toBe(308061521170129); + expect(fibonacciNthClosedForm(72)).toBe(498454011879264); + expect(fibonacciNthClosedForm(73)).toBe(806515533049393); + expect(fibonacciNthClosedForm(74)).toBe(1304969544928657); + expect(fibonacciNthClosedForm(75)).toBe(2111485077978050); + }); +}); diff --git a/src/algorithms/math/fibonacci/fibonacciClosedForm.js b/src/algorithms/math/fibonacci/fibonacciClosedForm.js deleted file mode 100644 index c5ce46bf..00000000 --- a/src/algorithms/math/fibonacci/fibonacciClosedForm.js +++ /dev/null @@ -1,11 +0,0 @@ -/** - * Calculate fibonacci number at specific position using closed form function. - * - * @param n n-th number of fibonacci sequence (must be number from 1(inclusive) to 75(inclusive)) - * @return {number} - */ -export default function fibonacciClosedForm(n) { - const sqrt5 = Math.sqrt(5); - const phi = (1 + sqrt5) / 2; - return Math.floor((phi ** n) / sqrt5 + 0.5); -} diff --git a/src/algorithms/math/fibonacci/fibonacciNthClosedForm.js b/src/algorithms/math/fibonacci/fibonacciNthClosedForm.js new file mode 100644 index 00000000..28681533 --- /dev/null +++ b/src/algorithms/math/fibonacci/fibonacciNthClosedForm.js @@ -0,0 +1,23 @@ +/** + * Calculate fibonacci number at specific position using closed form function (Binet's formula). + * @see: https://en.wikipedia.org/wiki/Fibonacci_number#Closed-form_expression + * + * @param {number} position - Position number of fibonacci sequence (must be number from 1 to 75). + * @return {number} + */ +export default function fibonacciClosedForm(position) { + const topMaxValidPosition = 75; + + // Check that position is valid. + if (position < 1 || position > topMaxValidPosition) { + throw new Error(`Can't handle position smaller than 1 or greater than ${topMaxValidPosition}`); + } + + // Calculate √5 to re-use it in further formulas. + const sqrt5 = Math.sqrt(5); + // Calculate φ constant (≈ 1.61803). + const phi = (1 + sqrt5) / 2; + + // Calculate fibonacci number using Binet's formula. + return Math.floor((phi ** position) / sqrt5 + 0.5); +}