@@ -158,7 +158,7 @@ fn matrix_multiply(multiplier: &[Vec<u128>], multiplicand: &[Vec<u128>]) -> Vec<
158158 // of columns as the multiplicand has rows.
159159 let mut result: Vec < Vec < u128 > > = vec ! [ ] ;
160160 let mut temp;
161- // Using variable to compare lenghts of rows in multiplicand later
161+ // Using variable to compare lengths of rows in multiplicand later
162162 let row_right_length = multiplicand[ 0 ] . len ( ) ;
163163 for row_left in 0 ..multiplier. len ( ) {
164164 if multiplier[ row_left] . len ( ) != multiplicand. len ( ) {
@@ -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 {
@@ -195,7 +222,7 @@ pub fn nth_fibonacci_number_modulo_m(n: i64, m: i64) -> i128 {
195222fn get_pisano_sequence_and_period ( m : i64 ) -> ( i128 , Vec < i128 > ) {
196223 let mut a = 0 ;
197224 let mut b = 1 ;
198- let mut lenght : i128 = 0 ;
225+ let mut length : i128 = 0 ;
199226 let mut pisano_sequence: Vec < i128 > = vec ! [ a, b] ;
200227
201228 // Iterating through all the fib numbers to get the sequence
@@ -213,12 +240,12 @@ fn get_pisano_sequence_and_period(m: i64) -> (i128, Vec<i128>) {
213240 // This is a less elegant way to do it.
214241 pisano_sequence. pop ( ) ;
215242 pisano_sequence. pop ( ) ;
216- lenght = pisano_sequence. len ( ) as i128 ;
243+ length = pisano_sequence. len ( ) as i128 ;
217244 break ;
218245 }
219246 }
220247
221- ( lenght , pisano_sequence)
248+ ( length , pisano_sequence)
222249}
223250
224251/// last_digit_of_the_sum_of_nth_fibonacci_number(n) returns the last digit of the sum of n fibonacci numbers.
@@ -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;
@@ -328,7 +356,7 @@ mod tests {
328356 }
329357
330358 #[ test]
331- /// Check that the itterative and recursive fibonacci
359+ /// Check that the iterative and recursive fibonacci
332360 /// produce the same value. Both are combinatorial ( F(0) = F(1) = 1 )
333361 fn test_iterative_and_recursive_equivalence ( ) {
334362 assert_eq ! ( fibonacci( 0 ) , recursive_fibonacci( 0 ) ) ;
@@ -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