Python:计算一个巨大的Fibonacci数模数m

时间:2016-10-17 21:38:48

标签: python-3.x fibonacci modulo

# 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时,我需要花费很多时间。你有更好的解决方案吗?

7 个答案:

答案 0 :(得分:3)

ifPresent

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

答案 1 :(得分:2)

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

  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)

答案 2 :(得分:1)

这是我的解决方案,如果你发现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))

答案 3 :(得分:0)

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

编辑:只需谷歌搜索&#34;斐波那契模数&#34;给你这两个作为前两个结果。

答案 4 :(得分:0)

对于任何整数m>=2,模数m的序列fn是周期的-Pisano周期。 因此,无需存储和查找fn。而是找到给定m的重复模式。

答案 5 :(得分:0)

这就是我计算pisano周期的方式。(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);
}

答案 6 :(得分:0)

我在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))