hakuna
hakuna

Reputation: 6701

Calculate Huge Fibonacci number modulo M in C++

Problem statement : Given two integers n and m, output Fn mod m (that is, the remainder of Fn when divided by m).

Input Format. The input consists of two integers n and m given on the same line (separated by a space). Constraints. 1 ≤ n ≤ 10^18, 2 ≤ m ≤ 10^5

Output Format. Output Fn mod m.

I tried the following program and it didn't work. The method pi is returning the right Pisano period though for any number as per http://webspace.ship.edu/msrenault/fibonacci/fiblist.htm

#include <iostream>

long long pi(long long m) {
    long long result = 2;
    for (long long fn2 = 1, fn1 = 2 % m, fn = 3 % m;
    fn1 != 1 || fn != 1;
        fn2 = fn1, fn1 = fn, fn = (fn1 + fn2) % m
        ) {
        result++;
    }
    return result;
}

long long get_fibonaccihuge(long long n, long long m) {
    long long periodlength = pi(m);
    int patternRemainder = n % periodlength;    

    long long *sum = new long long[patternRemainder];

    sum[0] = 0;
    sum[1] = 1;
    for (int i = 2; i <= patternRemainder; ++i)
    {
        sum[i] = sum[i - 1] + sum[i - 2];
    }   
    return sum[patternRemainder] % m;
}

int main() {
    long long n, m;
    std::cin >> n >> m;
    std::cout << get_fibonaccihuge(n, m) << '\n';
}

The exact program/logic is working well in python as expected. What's wrong withthis cpp program ? Is it the data types ?

Upvotes: 0

Views: 3184

Answers (2)

Muhamed Youssry
Muhamed Youssry

Reputation: 26

This was my solution for this problem, it works well and succeeded in the submission test ...

i used a simpler way to get the pisoano period ( pisano period is the main tricky part in this problem ) ... i wish to be helpful

#include <iostream>
using namespace std;

unsigned long long get_fibonacci_huge_naive(unsigned long long n, unsigned long long m)
{
    if (n <= 1)
        return n;

    unsigned long long previous = 0;
    unsigned long long current = 1;

    for (unsigned long long i = 0; i < n - 1; ++i)
    {
        unsigned long long tmp_previous = previous;
        previous = current;
        current = tmp_previous + current;
    }

    return current % m;
}

long long get_pisano_period(long long m)
{
    long long a = 0, b = 1, c = a + b;
    for (int i = 0; i < m * m; i++)
    {
        c = (a + b) % m;
        a = b;
        b = c;
        if (a == 0 && b == 1)
        {
            return i + 1;
        }
    }
}
unsigned long long get_fibonacci_huge_faster(unsigned long long n, unsigned long long m)
{
    n = n % get_pisano_period(m);
    unsigned long long F[n + 1] = {};
    F[0] = 0;
    F[-1] = 1;

    for (int i = 1; i <= n; i++)
    {
        F[i] = F[i - 1] + F[i - 2];
        F[i] = F[i] % m;
    }
    return F[n];
}

int main()
{
    unsigned long long n, m;
    std::cin >> n >> m;
    std::cout << get_fibonacci_huge_faster(n, m) << '\n';
}

Upvotes: 1

Will Ness
Will Ness

Reputation: 71109

Performing 10^18 additions isn't going to be very practical. Even on a teraflop computer, 10^6 seconds is still 277 hours.

But 10^18 ~= 2^59.8 so there'll be up to 60 halving steps.

Calculate (a,b) --> (a^2 + b^2, 2ab + b^2) to go from (n-1,n)th to (2n-1,2n)th consecutive Fibonacci number pairs in one step.

At each step perform the modulus calculation for each operation. You'll need to accommodate integers up to 3*1010 ≤ 235 in magnitude (i.e. up to 35 bits).

(cf. a related older answer of mine).

Upvotes: 3

Related Questions