【问题标题】:Python: Compute a Huge Fibonacci Number Modulo mPython:计算一个巨大的斐波那契数模 m
【发布时间】:2017-02-27 00:15:03
【问题描述】:
# Uses python3
# Given two integers n and m, output Fn mod m (that is, the remainder of Fn when divided by m
def Huge_Fib(n,m):

    if n == 0 : return 0
    elif n == 1: return 1
    else:
        a,b = 0,1
        for i in range(1,n):
            a, b = b, (a+b) % m
        print(b);

n,m = map(int, input().split());   
Huge_Fib(n,m);

代码运行良好。但是,当我以 n = 99999999999999999, m = 2 运行一个案例时,我需要很长时间。您有更好的解决方案吗?

【问题讨论】:

  • 呃,你期待什么?你有for i in range(1,99999999999999999),这需要一点时间来迭代......
  • 我想在 2-3 秒内运行它。但这需要很多时间@MarcB
  • 没有其他更快的算法吗?

标签: python-3.x fibonacci modulo


【解决方案1】:

您应该查看 Pisano 周期。 https://en.wikipedia.org/wiki/Pisano_periodhttp://webspace.ship.edu/msrenault/fibonacci/fibfactory.htm 应该能让你很好地理解它们是什么。

编辑:只需谷歌搜索“fibonacci modulo”即可将这两个作为前两个结果。

【讨论】:

【解决方案2】:
# Uses python3
# Given two integers n and m, output Fn mod m (that is, the remainder of Fn when divided by m
def Huge_Fib(n,m):

    # Initialize a matrix [[1,1],[1,0]]    
    v1, v2, v3 = 1, 1, 0  
    # Perform fast exponentiation of the matrix (quickly raise it to the nth power)
    for rec in bin(n)[3:]:
        calc = (v2*v2) % m
        v1, v2, v3 = (v1*v1+calc) % m, ((v1+v3)*v2) % m, (calc+v3*v3) % m
        if rec == '1': v1, v2, v3 = (v1+v2) % m, v1, v2
    print(v2);        

n,m = map(int, input().split());   
Huge_Fib(n,m);

这是一个超快的解决方案参考https://stackoverflow.com/a/23462371/3700852

【讨论】:

    【解决方案3】:

    这是我的解决方案,如果你找到了 pisano 周期,你不必经过 99999999999999999 次迭代。

    我还建议您观看此视频:https://www.youtube.com/watch?v=Nu-lW-Ifyec

    # Uses python3
    import sys
    
    def get_fibonacci_huge(n, m):
        if n <= 1:
            return n
    
        arr = [0, 1]
        previousMod = 0
        currentMod = 1
    
        for i in range(n - 1):
            tempMod = previousMod
            previousMod = currentMod % m
            currentMod = (tempMod + currentMod) % m
            arr.append(currentMod)
            if currentMod == 1 and previousMod == 0:
                index = (n % (i + 1))
                return arr[index]
    
        return currentMod
    
    if __name__ == '__main__':
        input = sys.stdin.read();
        n, m = map(int, input.split())
        print(get_fibonacci_huge(n,m))
    

    【讨论】:

      【解决方案4】:

      在下面的代码中,我们使用了斐波那契数列的两个概念:

      1. Pisano 周期遵循斐波那契数列,因此每个重复(模式)都以 0 和 1 开始,一个接一个地连续出现。

      2. fib(n) 仅在 n 除 m 时除 fib(m),这意味着如果 fib(4)%3==0,则 fib(4+4)%3==0,fib(4+ 4+4)%3==0 等等。这有助于我们找到皮萨诺时期。

      要了解皮萨诺时期,我建议您观看此视频:https://www.youtube.com/watch?v=Nu-lW-Ifyec

      #python3
      def pisano_length(m):
          i=2
          while(fib(i)%m!=0):
              i+=1
          if(fib(i+1)%m!=1):
              while(fib(i+1)%m!=1):
                  i+=i
          print("The pisano length for mod {} is: {}".format(m,i))
          return(i)
      def fib(n):
          a,b=0,1
          if(n==0 or n==1):
              return n
          else:
              for i in range(2,n+1):
                  b,a=a+b,b
          return(b)
      #we want to calculate fib(n)%m for big numbers
      n,m=map(int,input().split())
      remainder=n%pisano_length(m)
      print(fib(remainder)%m)
      

      【讨论】:

        【解决方案5】:

        对于任何整数m&gt;=2,fn 模 m 的序列是周期性的 - 皮萨诺周期。 所以不需要存储和查找fn。相反,找到给定 m 的重复模式。

        【讨论】:

          【解决方案6】:

          这就是我通过计算皮萨诺周期来完成的。(Java)

          public static long get_pisano_period(long m) {
              long a = 0, b = 1;
              long c;
              for (int i = 0; i < m * m; i++) {
                  c = (a + b) % m;
                  a = b;
                  b = c;
                  if (a == 0 && b == 1)
                      return i + 1;
              }
              return 0;
          }
          
          public static BigInteger get_fibonacci_huge(long n,long m) {
              long remainder = n % get_pisano_period(m);
          
              BigInteger first = BigInteger.valueOf(0);
              BigInteger second=BigInteger.valueOf(1);
              BigInteger m1=BigInteger.valueOf(m);
              BigInteger res = BigInteger.valueOf(remainder);
          
              for (long i = 1; i < remainder; i++) {
                  res = (first.add(second)).mod(m1);
                  first = second;
                  second = res;
              }
              return res.mod(m1);
          }
          

          【讨论】:

            【解决方案7】:

            我在 Python 3 中解决了这个问题。这是计算以 m 为模的巨大斐波那契数的最快算法。例如,对于 n =2816213588,m = 239,使用的最大时间:0.01/5.00,使用的最大内存:9424896/ 536870912。)

                 def pisanoPeriod(m): 
                    previous, current = 0, 1
                    for i in range(0, m * m): 
                        previous, current = current, (previous + current) % m 
                        # A Pisano Period starts with 01 
                        if (previous == 0 and current == 1): 
                            return i + 1
            
                def calc_fib(n,m):
                    p = pisanoPeriod(m)
                    n = n % p
                    if (n <= 1):
                        return n
                    else:
                      previous,current = 0,1
                      for i in range(2,n+1):
                        previous,current = current,(previous+current)
                    return current%m
            
                n,m =map(int,input().split(" "))
                print(calc_fib(n,m))
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2017-01-29
              • 2013-03-31
              • 1970-01-01
              • 2016-12-11
              • 2017-07-22
              • 2016-08-04
              相关资源
              最近更新 更多