Calculating a huge fibonacci number modulo m in Python

六眼飞鱼酱① 提交于 2020-01-03 01:41:30

问题


The goal of this problem is to calculate F[n] mod m. Here the inputs are n and m, where n stands for the index of the fibonacci number, say F[0] = 0, F[1] = 1, F[2] = 1, F[3]= 2 and m stands for the number by which F[n] will be divided. The constraints are:

  • n >= 1 and n <= 10^18
  • m >= 2 and m <= 10^5

I have gone this problem so far and been able to generate the exact output of this problem except when I give 100000 as the value of m, it exceeds the time limit. The time limit is 5 seconds. If the value of m is given between and including from 2 to 99999, my program generates the correct output within the time limit. Any kind of help solving this problem would be highly appreciated.

Code:

def fibonacci(n):
    if ( n == 0 ):
        return (0, 1)
    else:
        a, b = fibonacci(n/2)
        c = a * (2* b - a)
        d = a**2 + b**2
        if ( n % 2 ):
            return (d, c + d)
        else:
            return (c, d)


def findRemainders(m):
    remainderList = ["0", "1"]
    i = 2
    while(1):
        firstFib, secondFib = fibonacci(i)
        if ( (firstFib % m) == 0 and (secondFib % m) == 1 ):
            break
        remainderList.append( (firstFib % m) )
        remainderList.append( (secondFib % m) )
        i += 2

    return remainderList


def hugeFibonacciNumberModulo_m( n, m ):
    remainderList = findRemainders(m)
    length_of_period = len(remainderList)
    remainder = (n % length_of_period)
    out = remainderList[remainder]
    return out


inp = map(int, raw_input().split())
n, m = inp[0], inp[1]

if ( (n >= 1 and n <= 10**18) and (m >= 2 and m <= 10**5) ):
    out = hugeFibonacciNumberModulo_m( n, m )
print out

回答1:


I don't understand what you're attempting to do in findRemainders(m) or why you need it. You're already using the Fibonacci-by-doubling algorithm, which is analogous to (and usually derived from) a matrix-exponentiation-by-squaring algorithm. Exponentiation can be modified to efficiently handle modular exponentiation by essentially mod'ing your partial result(s) at each step.

def fibmod(n, m):
    assert 1 <= n <= 10**18, n
    assert 2 <= m <= 10**5, m

    def f(n):
        if n == 0:
            return 0, 1
        else:
            a, b = f(n // 2)
            c = a * (2*b - a) % m
            d = (a**2 + b**2) % m

            if n % 2 == 0:
                return c, d
            else:
                return d, (c + d) % m

    return f(n)[0]

You can break down the expression for c and d even further and apply % m after each intermediate multiplication, addition, and subtraction to prevent overflow (but this isn't really a problem in Python).




回答2:


You can do this very quickly by using modular exponentiation.

Consider the following matrix multiplication:

| 0  1 |     | a |     |  b  |
|      |  x  |   |  =  |     |
| 1  1 |     | b |     | a+b |

You should see straight away that the result of this multiplication is the next iteration of the Fibonacci sequence if a and b are the last two terms. To get the result of performing this multiplication n times, you need to calculate the n-th power of the 2x2 matrix (0,1;1,1) (mod m). This can be done very quickly by raising this matrix to successive powers of 2.

For example, to calculate the 10th power of this matrix:

                   | 0  1 |     | 0  1 |     | 1  1 |
A x A  =  A**2  =  |      |  x  |      |  =  |      |
                   | 1  1 |     | 1  1 |     | 1  2 |

                      | 1  1 |     | 1  1 |     | 2  3 |
A**4 =  (A**2)**2  =  |      |  x  |      |  =  |      |
                      | 1  2 |     | 1  2 |     | 3  5 |

                      | 2  3 |     | 2  3 |     | 13  21 |
A**8 =  (A**4)**2  =  |      |  x  |      |  =  |        |
                      | 3  5 |     | 3  5 |     | 21  34 |

After squaring the matrix three times, we now have the values of A**8 and A**2. Multiply these together and you get A**10:

          | 13  21 |     | 1  1 |     | 34  55 |
A**10  =  |        |  x  |      |  =  |        |
          | 21  34 |     | 1  2 |     | 55  89 |

These numbers will rapidly become enormous in regular arithmetic, but if you perform all your multiplications modulo m, then this isn't a problem. Finally, multiply the vector (0; 1) by the resulting matrix to get your answer (or, equivalently, just pick out the second number in the top row of the matrix).

The number of multiplications required is of the order of log(n), so the time required should be very small, even if m is a trillion or more.

See Wikipedia for more information about modular exponentiation of matrices.



来源:https://stackoverflow.com/questions/40556760/calculating-a-huge-fibonacci-number-modulo-m-in-python

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!