@@ -180,6 +180,33 @@ fn matrix_multiply(multiplier: &[Vec<u128>], multiplicand: &[Vec<u128>]) -> Vec<
180
180
result
181
181
}
182
182
183
+ /// Binary lifting fibonacci
184
+ ///
185
+ /// Following properties of F(n) could be deduced from the matrix formula above:
186
+ ///
187
+ /// F(2n) = F(n) * (2F(n+1) - F(n))
188
+ /// F(2n+1) = F(n+1)^2 + F(n)^2
189
+ ///
190
+ /// Therefore F(n) and F(n+1) can be derived from F(n>>1) and F(n>>1 + 1), which
191
+ /// has a smaller constant in both time and space compared to matrix fibonacci.
192
+ pub fn binary_lifting_fibonacci ( n : u32 ) -> u128 {
193
+ // the state always stores F(k), F(k+1) for some k, initially F(0), F(1)
194
+ let mut state = ( 0u128 , 1u128 ) ;
195
+
196
+ for i in ( 0 ..u32:: BITS - n. leading_zeros ( ) ) . rev ( ) {
197
+ // compute F(2k), F(2k+1) from F(k), F(k+1)
198
+ state = (
199
+ state. 0 * ( 2 * state. 1 - state. 0 ) ,
200
+ state. 0 * state. 0 + state. 1 * state. 1 ,
201
+ ) ;
202
+ if n & ( 1 << i) != 0 {
203
+ state = ( state. 1 , state. 0 + state. 1 ) ;
204
+ }
205
+ }
206
+
207
+ state. 0
208
+ }
209
+
183
210
/// nth_fibonacci_number_modulo_m(n, m) returns the nth fibonacci number modulo the specified m
184
211
/// i.e. F(n) % m
185
212
pub fn nth_fibonacci_number_modulo_m ( n : i64 , m : i64 ) -> i128 {
@@ -251,6 +278,7 @@ pub fn last_digit_of_the_sum_of_nth_fibonacci_number(n: i64) -> i64 {
251
278
252
279
#[ cfg( test) ]
253
280
mod tests {
281
+ use super :: binary_lifting_fibonacci;
254
282
use super :: classical_fibonacci;
255
283
use super :: fibonacci;
256
284
use super :: last_digit_of_the_sum_of_nth_fibonacci_number;
@@ -398,6 +426,24 @@ mod tests {
398
426
) ;
399
427
}
400
428
429
+ #[ test]
430
+ fn test_binary_lifting_fibonacci ( ) {
431
+ assert_eq ! ( binary_lifting_fibonacci( 0 ) , 0 ) ;
432
+ assert_eq ! ( binary_lifting_fibonacci( 1 ) , 1 ) ;
433
+ assert_eq ! ( binary_lifting_fibonacci( 2 ) , 1 ) ;
434
+ assert_eq ! ( binary_lifting_fibonacci( 3 ) , 2 ) ;
435
+ assert_eq ! ( binary_lifting_fibonacci( 4 ) , 3 ) ;
436
+ assert_eq ! ( binary_lifting_fibonacci( 5 ) , 5 ) ;
437
+ assert_eq ! ( binary_lifting_fibonacci( 10 ) , 55 ) ;
438
+ assert_eq ! ( binary_lifting_fibonacci( 20 ) , 6765 ) ;
439
+ assert_eq ! ( binary_lifting_fibonacci( 21 ) , 10946 ) ;
440
+ assert_eq ! ( binary_lifting_fibonacci( 100 ) , 354224848179261915075 ) ;
441
+ assert_eq ! (
442
+ binary_lifting_fibonacci( 184 ) ,
443
+ 127127879743834334146972278486287885163
444
+ ) ;
445
+ }
446
+
401
447
#[ test]
402
448
fn test_nth_fibonacci_number_modulo_m ( ) {
403
449
assert_eq ! ( nth_fibonacci_number_modulo_m( 5 , 10 ) , 5 ) ;
0 commit comments