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
+ )
11
14
}
12
15
13
16
return sequence
14
17
}
15
18
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
17
33
return ( ( ) => {
18
34
switch ( list . length ) {
19
35
case 0 :
20
- list . push ( 1 )
21
- return FibonacciRecursive ( number )
36
+ list . push ( 0 )
37
+ return FibonacciRecursive ( num )
22
38
case 1 :
23
39
list . push ( 1 )
24
- return FibonacciRecursive ( number )
25
- case number :
40
+ return FibonacciRecursive ( num )
41
+ case num + 1 :
26
42
return list
27
43
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 )
30
46
}
31
- } ) ( )
47
+ } ) ( ) . map ( ( fib , i ) => fib * ( isNeg ? ( - 1 ) ** ( i + 1 ) : 1 ) )
32
48
}
33
49
34
50
const dict = new Map ( )
35
-
36
51
const 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
39
56
40
57
// 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 )
42
59
43
- const res =
44
- FibonacciRecursiveDP ( stairs - 1 ) + FibonacciRecursiveDP ( stairs - 2 )
60
+ const res = FibonacciRecursiveDP ( stairs - 1 ) + FibonacciRecursiveDP ( stairs - 2 )
45
61
46
62
dict . set ( stairs , res )
47
63
48
- return res
64
+ return ( isNeg ? ( - 1 ) ** ( stairs + 1 ) : 1 ) * res
49
65
}
50
66
51
67
// Algorithms
@@ -59,12 +75,16 @@ const FibonacciRecursiveDP = (stairs) => {
59
75
// a function of the number of input bits
60
76
// @Satzyakiz
61
77
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 ]
64
82
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
+ )
68
88
}
69
89
return table
70
90
}
@@ -76,24 +96,31 @@ const copyMatrix = (A) => {
76
96
}
77
97
78
98
const Identity = ( size ) => {
99
+ const isBigInt = typeof size === 'bigint'
100
+ const ZERO = isBigInt ? 0n : 0
101
+ const ONE = isBigInt ? 1n : 1
102
+ size = Number ( size )
79
103
const I = Array ( size ) . fill ( null ) . map ( ( ) => Array ( size ) . fill ( ) )
80
104
return I . map ( ( row , rowIdx ) => row . map ( ( _col , colIdx ) => {
81
- return rowIdx === colIdx ? 1 : 0
105
+ return rowIdx === colIdx ? ONE : ZERO
82
106
} ) )
83
107
}
84
108
85
109
// 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
87
113
const matrixMultiply = ( A , B ) => {
88
114
A = copyMatrix ( A )
89
115
B = copyMatrix ( B )
116
+ const isBigInt = typeof A [ 0 ] [ 0 ] === 'bigint'
90
117
const l = A . length
91
118
const m = B . length
92
119
const n = B [ 0 ] . length // Assuming non-empty matrices
93
120
const C = Array ( l ) . fill ( null ) . map ( ( ) => Array ( n ) . fill ( ) )
94
121
for ( let i = 0 ; i < l ; i ++ ) {
95
122
for ( let j = 0 ; j < n ; j ++ ) {
96
- C [ i ] [ j ] = 0
123
+ C [ i ] [ j ] = isBigInt ? 0n : 0
97
124
for ( let k = 0 ; k < m ; k ++ ) {
98
125
C [ i ] [ j ] += A [ i ] [ k ] * B [ k ] [ j ]
99
126
}
@@ -110,18 +137,25 @@ const matrixMultiply = (A, B) => {
110
137
// A is a square matrix
111
138
const matrixExpo = ( A , n ) => {
112
139
A = copyMatrix ( A )
140
+ const isBigInt = typeof n === 'bigint'
141
+ const ZERO = isBigInt ? 0n : 0
142
+ const TWO = isBigInt ? 2n : 2
113
143
114
144
// 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 )
120
151
}
121
152
return result
122
153
}
123
154
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
125
159
// F(0) = 0, F(1) = 1
126
160
// F(n) = F(n-1) + F(n-2)
127
161
// Consider below matrix multiplication:
@@ -134,23 +168,28 @@ const FibonacciMatrixExpo = (n) => {
134
168
// or F(n, n-1) = A * A * F(n-2, n-3)
135
169
// or F(n, n-1) = pow(A, n-1) * F(1, 0)
136
170
137
- if ( n === 0 ) return 0
171
+ if ( num === ZERO ) return num
172
+
173
+ const isNeg = num < 0
174
+ if ( isNeg ) num *= - ONE
138
175
139
176
const A = [
140
- [ 1 , 1 ] ,
141
- [ 1 , 0 ]
177
+ [ ONE , ONE ] ,
178
+ [ ONE , ZERO ]
142
179
]
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
144
182
let F = [
145
- [ 1 ] ,
146
- [ 0 ]
183
+ [ ONE ] ,
184
+ [ ZERO ]
147
185
]
148
186
F = matrixMultiply ( poweredA , F )
149
- return F [ 0 ] [ 0 ]
187
+ return F [ 0 ] [ 0 ] * ( isNeg ? ( - ONE ) ** ( num + ONE ) : ONE )
150
188
}
151
189
152
190
export { FibonacciDpWithoutRecursion }
153
191
export { FibonacciIterative }
192
+ export { FibonacciGenerator }
154
193
export { FibonacciRecursive }
155
194
export { FibonacciRecursiveDP }
156
195
export { FibonacciMatrixExpo }
0 commit comments