1- const list = [ ]
2-
3- const FibonacciIterative = ( nth ) => {
4- const sequence = [ ]
5-
6- if ( nth >= 1 ) sequence . push ( 1 )
7- if ( nth >= 2 ) sequence . push ( 1 )
8-
9- for ( let i = 2 ; i < nth ; i ++ ) {
10- sequence . push ( sequence [ i - 1 ] + sequence [ i - 2 ] )
1+ // https://en.wikipedia.org/wiki/Generalizations_of_Fibonacci_numbers#Extension_to_negative_integers
2+ const FibonacciIterative = ( num ) => {
3+ const isNeg = num < 0
4+ if ( isNeg ) num *= - 1
5+ const sequence = [ 0 ]
6+
7+ if ( num >= 1 ) sequence . push ( 1 )
8+ if ( num >= 2 ) sequence . push ( isNeg ? - 1 : 1 )
9+
10+ for ( let i = 2 ; i < num ; i ++ ) {
11+ sequence . push (
12+ isNeg ? sequence [ i - 1 ] - sequence [ i ] : sequence [ i ] + sequence [ i - 1 ]
13+ )
1114 }
1215
1316 return sequence
1417}
1518
16- const FibonacciRecursive = ( number ) => {
19+ const FibonacciGenerator = function * ( neg ) {
20+ let a = 0
21+ let b = 1
22+ yield a
23+ while ( true ) {
24+ yield b ;
25+ [ a , b ] = neg ? [ b , a - b ] : [ b , a + b ]
26+ }
27+ }
28+
29+ const list = [ ]
30+ const FibonacciRecursive = ( num ) => {
31+ const isNeg = num < 0
32+ if ( isNeg ) num *= - 1
1733 return ( ( ) => {
1834 switch ( list . length ) {
1935 case 0 :
20- list . push ( 1 )
21- return FibonacciRecursive ( number )
36+ list . push ( 0 )
37+ return FibonacciRecursive ( num )
2238 case 1 :
2339 list . push ( 1 )
24- return FibonacciRecursive ( number )
25- case number :
40+ return FibonacciRecursive ( num )
41+ case num + 1 :
2642 return list
2743 default :
28- list . push ( list [ list . length - 1 ] + list [ list . length - 2 ] )
29- return FibonacciRecursive ( number )
44+ list . push ( list . at ( - 1 ) + list . at ( - 2 ) )
45+ return FibonacciRecursive ( num )
3046 }
31- } ) ( )
47+ } ) ( ) . map ( ( fib , i ) => fib * ( isNeg ? ( - 1 ) ** ( i + 1 ) : 1 ) )
3248}
3349
3450const dict = new Map ( )
35-
3651const FibonacciRecursiveDP = ( stairs ) => {
37- if ( stairs <= 0 ) return 0
38- if ( stairs === 1 ) return 1
52+ const isNeg = stairs < 0
53+ if ( isNeg ) stairs *= - 1
54+
55+ if ( stairs <= 1 ) return stairs
3956
4057 // Memoize stair count
41- if ( dict . has ( stairs ) ) return dict . get ( stairs )
58+ if ( dict . has ( stairs ) ) return ( isNeg ? ( - 1 ) ** ( stairs + 1 ) : 1 ) * dict . get ( stairs )
4259
43- const res =
44- FibonacciRecursiveDP ( stairs - 1 ) + FibonacciRecursiveDP ( stairs - 2 )
60+ const res = FibonacciRecursiveDP ( stairs - 1 ) + FibonacciRecursiveDP ( stairs - 2 )
4561
4662 dict . set ( stairs , res )
4763
48- return res
64+ return ( isNeg ? ( - 1 ) ** ( stairs + 1 ) : 1 ) * res
4965}
5066
5167// Algorithms
@@ -59,12 +75,16 @@ const FibonacciRecursiveDP = (stairs) => {
5975// a function of the number of input bits
6076// @Satzyakiz
6177
62- const FibonacciDpWithoutRecursion = ( number ) => {
63- const table = [ ]
78+ const FibonacciDpWithoutRecursion = ( num ) => {
79+ const isNeg = num < 0
80+ if ( isNeg ) num *= - 1
81+ const table = [ 0 ]
6482 table . push ( 1 )
65- table . push ( 1 )
66- for ( let i = 2 ; i < number ; ++ i ) {
67- table . push ( table [ i - 1 ] + table [ i - 2 ] )
83+ table . push ( isNeg ? - 1 : 1 )
84+ for ( let i = 2 ; i < num ; ++ i ) {
85+ table . push (
86+ isNeg ? table [ i - 1 ] - table [ i ] : table [ i ] + table [ i - 1 ]
87+ )
6888 }
6989 return table
7090}
@@ -76,24 +96,31 @@ const copyMatrix = (A) => {
7696}
7797
7898const Identity = ( size ) => {
99+ const isBigInt = typeof size === 'bigint'
100+ const ZERO = isBigInt ? 0n : 0
101+ const ONE = isBigInt ? 1n : 1
102+ size = Number ( size )
79103 const I = Array ( size ) . fill ( null ) . map ( ( ) => Array ( size ) . fill ( ) )
80104 return I . map ( ( row , rowIdx ) => row . map ( ( _col , colIdx ) => {
81- return rowIdx === colIdx ? 1 : 0
105+ return rowIdx === colIdx ? ONE : ZERO
82106 } ) )
83107}
84108
85109// A of size (l x m) and B of size (m x n)
86- // product C will be of size (l x n)
110+ // product C will be of size (l x n).
111+ // both matrices must have same-type numeric values
112+ // either both BigInt or both Number
87113const matrixMultiply = ( A , B ) => {
88114 A = copyMatrix ( A )
89115 B = copyMatrix ( B )
116+ const isBigInt = typeof A [ 0 ] [ 0 ] === 'bigint'
90117 const l = A . length
91118 const m = B . length
92119 const n = B [ 0 ] . length // Assuming non-empty matrices
93120 const C = Array ( l ) . fill ( null ) . map ( ( ) => Array ( n ) . fill ( ) )
94121 for ( let i = 0 ; i < l ; i ++ ) {
95122 for ( let j = 0 ; j < n ; j ++ ) {
96- C [ i ] [ j ] = 0
123+ C [ i ] [ j ] = isBigInt ? 0n : 0
97124 for ( let k = 0 ; k < m ; k ++ ) {
98125 C [ i ] [ j ] += A [ i ] [ k ] * B [ k ] [ j ]
99126 }
@@ -110,18 +137,25 @@ const matrixMultiply = (A, B) => {
110137// A is a square matrix
111138const matrixExpo = ( A , n ) => {
112139 A = copyMatrix ( A )
140+ const isBigInt = typeof n === 'bigint'
141+ const ZERO = isBigInt ? 0n : 0
142+ const TWO = isBigInt ? 2n : 2
113143
114144 // Just like Binary exponentiation mentioned in ./BinaryExponentiationIterative.js
115- let result = Identity ( A . length ) // Identity matrix
116- while ( n > 0 ) {
117- if ( n % 2 !== 0 ) result = matrixMultiply ( result , A )
118- n = Math . floor ( n / 2 )
119- if ( n > 0 ) A = matrixMultiply ( A , A )
145+ let result = Identity ( ( isBigInt ? BigInt : Number ) ( A . length ) ) // Identity matrix
146+ while ( n > ZERO ) {
147+ if ( n % TWO !== ZERO ) result = matrixMultiply ( result , A )
148+ n /= TWO
149+ if ( ! isBigInt ) n = Math . floor ( n )
150+ if ( n > ZERO ) A = matrixMultiply ( A , A )
120151 }
121152 return result
122153}
123154
124- const FibonacciMatrixExpo = ( n ) => {
155+ const FibonacciMatrixExpo = ( num ) => {
156+ const isBigInt = typeof num === 'bigint'
157+ const ZERO = isBigInt ? 0n : 0
158+ const ONE = isBigInt ? 1n : 1
125159 // F(0) = 0, F(1) = 1
126160 // F(n) = F(n-1) + F(n-2)
127161 // Consider below matrix multiplication:
@@ -134,23 +168,28 @@ const FibonacciMatrixExpo = (n) => {
134168 // or F(n, n-1) = A * A * F(n-2, n-3)
135169 // or F(n, n-1) = pow(A, n-1) * F(1, 0)
136170
137- if ( n === 0 ) return 0
171+ if ( num === ZERO ) return num
172+
173+ const isNeg = num < 0
174+ if ( isNeg ) num *= - ONE
138175
139176 const A = [
140- [ 1 , 1 ] ,
141- [ 1 , 0 ]
177+ [ ONE , ONE ] ,
178+ [ ONE , ZERO ]
142179 ]
143- const poweredA = matrixExpo ( A , n - 1 ) // A raised to the power n-1
180+
181+ const poweredA = matrixExpo ( A , num - ONE ) // A raised to the power n-1
144182 let F = [
145- [ 1 ] ,
146- [ 0 ]
183+ [ ONE ] ,
184+ [ ZERO ]
147185 ]
148186 F = matrixMultiply ( poweredA , F )
149- return F [ 0 ] [ 0 ]
187+ return F [ 0 ] [ 0 ] * ( isNeg ? ( - ONE ) ** ( num + ONE ) : ONE )
150188}
151189
152190export { FibonacciDpWithoutRecursion }
153191export { FibonacciIterative }
192+ export { FibonacciGenerator }
154193export { FibonacciRecursive }
155194export { FibonacciRecursiveDP }
156195export { FibonacciMatrixExpo }
0 commit comments