Calculating a huge fibonacci number modulo m in Python

♀尐吖头ヾ 提交于 2019-12-07 03:25:26

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).

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.

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