Python 探讨斐波拉契数列模素数的周期问题

Posted Travis Wang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python 探讨斐波拉契数列模素数的周期问题相关的知识,希望对你有一定的参考价值。

Python 探讨斐波拉契数列模素数的周期问题之目录


前言

定义    \\; 斐波拉契数列又称黄金分割数列,是指数列 1、1、2、3、5、8、13、21、34、55 …,通过递推的方式可准确定义为 F 0 = 0 ,    F 1 = 1 ,    F n = F n − 1 + F n − 2 ,    ( n ≥ 2 , n ∈ N ∗ ) F_0=0, \\; F_1=1, \\; F_n=F_n-1+F_n-2, \\; (n \\geq 2, n ∈ N^*) F0=0,F1=1,Fn=Fn1+Fn2,(n2,nN)

ω = 1 + 5 2 \\omega =\\frac1+\\sqrt52 ω=21+5 ω ˉ = 1 − 5 2 \\bar\\omega =\\frac1-\\sqrt52 ωˉ=215 ,则有斐波拉契数列的通项公式: F n = 1 5 ( ω n + ω ˉ n ) F_n = \\frac1\\sqrt5 \\left( \\omega^n + \\bar\\omega^n \\right) Fn=5 1(ωn+ωˉn)

性质    \\; 斐波拉契数列前一项与后一项之比的极限为黄金分割比,即有 lim ⁡ n → + ∞ F n F n + 1 = 5 − 1 2 \\lim_n \\to +\\infty \\fracF_nF_n+1 = \\frac\\sqrt5-12 n+limFn+1Fn=25 1


一、生成斐波拉契数列

按照递推公式即可写出如下代码:

def fibonacci(n):
    a, b = 0, 1
    for i in range(n):
        a, b = b, a + b
        yield a

使用 list(fibonacci(10)) 便输出 [1, 1, 2, 3, 5, 8, 13, 21, 34, 55] 。

二、创建素数列表

此步方法比较多,大家可以自己发挥,最后使用 primes(20) 要能输出小于 20 20 20 的全体素数 [2, 3, 5, 7, 11, 13, 17, 19] 。本文中至少要求我们能快速生成 10000 10000 10000 以内的素数即可,这是容易实现的,代码不再展示。

三、搜索周期数列的循环节

3.1 斐波拉契数列模 p p p 的周期

关于一般周期数列循环节的讨论,原本是比较麻烦的,但由于斐波拉契数列模素数 p p p 的周期很有规律,因此可以简单进行编程处理。

首先解释一下循环节的含义,循环节是指周期数列里一个最小正周期里的子数列。比如周期数列 [1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, …] 里的循环节为 [1, 2, 3] 。

周期数列的周期往往是指该数列循环节的长度,比如上面的周期数列,其周期为 3 3 3

斐波拉契数列模素数 p p p 之后形成的新的数列是一个周期数列,我们对于该周期数列的循环节和周期都是十分感兴趣的。

在此,我们给出一个重要结论:

定理    \\; F n \\ F_n \\ Fn 为斐波拉契数列, p p p 为大于 5 5 5 的素数,数列 F \\mathscrF F 为斐波拉契数列 F n \\ F_n \\ Fn 模素数 p p p 后的新数列,则当 p = 1 , 4 m o d    5 p = 1, 4 \\mod 5 p=1,4mod5 时, F \\mathscrF F 的周期为 p − 1 p-1 p1 p − 1 p-1 p1 的因子;当 p = 2 , 3 m o d    5 p = 2, 3 \\mod 5 p=2,3mod5 时, F \\mathscrF F 的周期为 2 p + 2 2p+2 2p+2 2 p + 2 2p+2 2p+2 的因子。

上述定理的证明详见论文 The Period of the Fibonacci Sequence Modulo j 中的定理5定理6

上述定理告述我们,斐波拉契数列模 p p p 的周期最多为 2 p + 2 2p+2 2p+2 。因此对于模 10000 10000 10000 以内的素数,最大的一个素数为 9973 9973 9973,其周期最多为 19948 19948 19948 。算法仅要求两个周期的匹配即可,故需要至少前 19948 ⋅ 2 = 39896 19948 \\cdot 2 = 39896 199482=39896 个斐波拉契数。本文我们取前 40000 40000 40000 个斐波拉契数,让他们皆模 p p p 产生周期数列 F \\mathscrF F

3.2 循环节的搜寻代码

我们按照上述要求,编写循环节搜寻的 Python 代码:

lstt = [7,1,4,2,8,5,0,7,1,4,2,8,5,0,7,1,4,2]
t = len(lstt)//2
s = 0

for k in range(2, t+1):
    if lstt[0:k]==lstt[k:2*k]:
        print(lstt[0:k])
        print(f'循环节长度为:len(lstt[0:k])')
        print(f'不同元素个数为:len(set(lstt[0:k]))', '\\n')
        s +=1
        break

输出结果如下:

[7, 1, 4, 2, 8, 5, 0]
循环节长度为:7
不同元素个数为:7 

3.3 完整实现斐波拉契数列模 p p p 循环节

a = primes(10000)
b = list(fibonacci(40000))

s = 0
u = 0
r = 0
lst_1 = []
lst_2 = []

for i in a:
    lst = []
    for j in b:
        lst.append(j % i)
    # 计算数列中的循环节
    t = len(lst)//2
    for k in range(2, t+1):
        if lst[0:k]==lst[k:2*k]:
            print(lst[0:k])
            print(f'循环节长度为:len(lst[0:k])')
            print(f'p=i 时循环节的不同元素个数为:len(set(lst[0:k]))')
            if len(lst[0:k])==2*i+2:
                print(f'最小正周期等于 2p+2', '\\n')
                lst_1.append(i)
                u +=1
            elif len(lst[0:k])==i-1:
                print(f'最小正周期等于 p-1', '\\n')
                lst_2.append(i)
                r +=1
            else:
                print('\\n')
            s +=1
            break

print(f'一共有 s 个循环节被输出')
print(f'一共有 len(a) 个素数被讨论') 
print(f'一共有 u 个模数 p 满足最小正周期等于 2p+2')
print(f'满足最小正周期等于 2p+2 的 p 为:lst_1')
print(f'一共有 r 个模数 p 满足最小正周期等于 p-1')
print(f'满足最小正周期等于 p-1 的 p 为:lst_2'以上是关于Python 探讨斐波拉契数列模素数的周期问题的主要内容,如果未能解决你的问题,请参考以下文章

斐波拉契数列(用JavaScript和Python实现)

实现斐波拉契数列的四种方式python代码

python斐波拉契数列

动态规划-斐波拉契数列笔记

Python生成器—— 斐波拉契数列

Python入门:生成器应用-斐波拉契数列