Fibonacci Number modulo M and Pisano Period
Given two number N and M. The task is to find the N-th fibonacci number mod M.
In general let FN be the N-th fibonacci number then the output should be FN % M.
The Fibonacci sequence is a series of numbers in which each no. is the sum of two preceding nos. It is defined by the recurrence relation:
F0 = 0
F1 = 1
Fn = Fn-1 + Fn-2
These nos. are in the following sequence: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, …
Here N can be large.
Examples:
Input: N = 438, M = 900
Output: 44
Input: N = 1548276540, M = 235
Output: 185
Approach:
However, for such values of N, a simple recursive approach to keep calculating N Fibonacci numbers with a time complexity of O(2N) should be avoided. Even an iterative or a Dynamic Programming approach with an algorithm looping for N iterations will not be time-efficient.
This problem can be solved using the properties of Pisano Period.
For a given value of N and M >= 2, the series generated with Fi modulo M (for i in range(N)) is periodic.
The period always starts with 01. The Pisano Period is defined as the length of the period of this series.
To understand it further, let’s see what happens when M is small:
i |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
Fi |
0 |
1 |
1 |
2 |
3 |
5 |
8 |
13 |
21 |
34 |
55 |
89 |
Fi mod 2 |
0 |
1 |
1 |
0 |
1 |
1 |
0 |
1 |
1 |
0 |
1 |
1 |
Fi mod 3 |
0 |
1 |
1 |
2 |
0 |
2 |
2 |
1 |
0 |
1 |
1 |
2 |
For M = 2, the period is 011 and has length 3 while for M = 3 the sequence repeats after 8 nos.
Example:
So to compute, say F2019 mod 5, we’ll find the remainder of 2019 when divided by 20 (Pisano Period of 5 is 20). 2019 mod 20 is 19. Therefore, F2019 mod 5 = F19 mod 5 = 1. This property is true in general.
We need to find the remainder when N is divided by the Pisano Period of M. Then calculate F(N)remainder mod M for the newly calculated N.
Below is the implementation of FN modulo M:
C++
#include <bits/stdc++.h>
using namespace std;
long pisano( long m)
{
long prev = 0;
long curr = 1;
long res = 0;
for ( int i = 0; i < m * m; i++)
{
long temp = 0;
temp = curr;
curr = (prev + curr) % m;
prev = temp;
if (prev == 0 && curr == 1)
res = i + 1;
}
return res;
}
long fibonacciModulo( long n, long m)
{
long pisanoPeriod = pisano(m);
n = n % pisanoPeriod;
long prev = 0;
long curr = 1;
if (n == 0)
return 0;
else if (n == 1)
return 1;
for ( int i = 0; i < n - 1; i++)
{
long temp = 0;
temp = curr;
curr = (prev + curr) % m;
prev = temp;
}
return curr % m;
}
int main()
{
long n = 1548276540;
long m = 235;
cout << (fibonacciModulo(n, m));
return 0;
}
|
Java
import java.io.*;
class GFG{
public static long pisano( long m)
{
long prev = 0 ;
long curr = 1 ;
long res = 0 ;
for ( int i = 0 ; i < m * m; i++)
{
long temp = 0 ;
temp = curr;
curr = (prev + curr) % m;
prev = temp;
if (prev == 0 && curr == 1 )
res= i + 1 ;
}
return res;
}
public static long fibonacciModulo( long n,
long m)
{
long pisanoPeriod = pisano(m);
n = n % pisanoPeriod;
long prev = 0 ;
long curr = 1 ;
if (n == 0 )
return 0 ;
else if (n == 1 )
return 1 ;
for ( int i = 0 ; i < n - 1 ; i++)
{
long temp = 0 ;
temp = curr;
curr = (prev + curr) % m;
prev = temp;
}
return curr % m;
}
public static void main(String[] args)
{
long n = 1548276540 ;
long m = 235 ;
System.out.println(fibonacciModulo(n, m));
}
}
|
Python3
def pisanoPeriod(m):
previous, current = 0 , 1
for i in range ( 0 , m * m):
previous, current \
= current, (previous + current) % m
if (previous = = 0 and current = = 1 ):
return i + 1
def fibonacciModulo(n, m):
pisano_period = pisanoPeriod(m)
n = n % pisano_period
previous, current = 0 , 1
if n = = 0 :
return 0
elif n = = 1 :
return 1
for i in range (n - 1 ):
previous, current \
= current, previous + current
return (current % m)
if __name__ = = '__main__' :
n = 1548276540
m = 235
print (fibonacciModulo(n, m))
|
C#
using System;
class GFG {
public static long pisano( long m)
{
long prev = 0;
long curr = 1;
long res = 0;
for ( int i = 0; i < m * m; i++) {
long temp = 0;
temp = curr;
curr = (prev + curr) % m;
prev = temp;
if (prev == 0 && curr == 1)
res = i + 1;
}
return res;
}
public static long fibonacciModulo( long n, long m)
{
long pisanoPeriod = pisano(m);
n = n % pisanoPeriod;
long prev = 0;
long curr = 1;
if (n == 0)
return 0;
else if (n == 1)
return 1;
for ( int i = 0; i < n - 1; i++) {
long temp = 0;
temp = curr;
curr = (prev + curr) % m;
prev = temp;
}
return curr % m;
}
public static void Main()
{
long n = 1548276540;
long m = 235;
Console.Write(fibonacciModulo(n, m));
}
}
|
Javascript
<script>
function pisano(m)
{
let prev = 0;
let curr = 1;
let res = 0;
for (let i = 0; i < m * m; i++)
{
let temp = 0;
temp = curr;
curr = (prev + curr) % m;
prev = temp;
if (prev == 0 && curr == 1)
res = i + 1;
}
return res;
}
function fibonacciModulo(n,m)
{
let pisanoPeriod = pisano(m);
n = n % pisanoPeriod;
let prev = 0;
let curr = 1;
if (n == 0)
return 0;
else if (n == 1)
return 1;
for (let i = 0; i < n - 1; i++)
{
let temp = 0;
temp = curr;
curr = (prev + curr) % m;
prev = temp;
}
return curr % m;
}
let n = 1548276540;
let m = 235;
document.write(fibonacciModulo(n, m));
</script>
|
Pisano Period of 235 is 160. 1548276540 mod 160 is 60. F60 mod 235 = 185. Using Pisano Period, we now need to calculate Fibonacci nos. iteratively for a relatively lower N than specified in the original problem and then calculate FN modulo M.
Time Complexity: O(M2)
Auxiliary Space: O(1)
Last Updated :
29 Mar, 2022
Like Article
Save Article
Share your thoughts in the comments
Please Login to comment...