@@ -180,6 +180,33 @@ fn matrix_multiply(multiplier: &[Vec<u128>], multiplicand: &[Vec<u128>]) -> Vec<
180180 result
181181}
182182
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+
183210/// nth_fibonacci_number_modulo_m(n, m) returns the nth fibonacci number modulo the specified m
184211/// i.e. F(n) % m
185212pub 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 {
251278
252279#[ cfg( test) ]
253280mod tests {
281+ use super :: binary_lifting_fibonacci;
254282 use super :: classical_fibonacci;
255283 use super :: fibonacci;
256284 use super :: last_digit_of_the_sum_of_nth_fibonacci_number;
@@ -398,6 +426,24 @@ mod tests {
398426 ) ;
399427 }
400428
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+
401447 #[ test]
402448 fn test_nth_fibonacci_number_modulo_m ( ) {
403449 assert_eq ! ( nth_fibonacci_number_modulo_m( 5 , 10 ) , 5 ) ;
0 commit comments