背景
《斐波那契数列:定义自然法则的数学》 一书提到,斐波那契数列的个位数字会按照固定的周期重复出现。我们可以自己动手来探索这个周期的长度是多少。
正文
斐波那契数列
F1=1,F2=1,对满足 n≥3 的 n 而言,Fn=Fn−1+Fn−2。满足这样的规则的数列,我们称其为斐波那契数列。
基本的分析
为了方便讨论,我们记 an=(Fnmod10,Fn+1mod10)。⬅️ 这里的小括号只是表示一对数字,没有特别的含义。
对比较小的 n,Fn,Fnmod10,an 的值列举如下
| n | Fn | Fnmod10 | an |
|---|
| 1 | 1 | 1 | (1,1) |
| 2 | 1 | 1 | (1,2) |
| 3 | 2 | 2 | (2,3) |
| 4 | 3 | 3 | (3,5) |
| 5 | 5 | 5 | (5,8) |
| 6 | 8 | 8 | (8,3) |
| 7 | 13 | 3 | (3,1) |
| 8 | 21 | 1 | (1,4) |
| 9 | 34 | 4 | (4,5) |
| 10 | 55 | 5 | (5,9) |
| 11 | 89 | 9 | (9,4) |
| 12 | 144 | 4 | (4,3) |
| 13 | 233 | 3 | (3,7) |
| 14 | 377 | 7 | (7,0) |
| 15 | 610 | 0 | (0,7) |
| 16 | 987 | 7 | (7,7) |
| 17 | 1597 | 7 | (7,4) |
| 18 | 2584 | 4 | (4,1) |
| 19 | 4181 | 1 | (1,5) |
| 20 | 6765 | 5 | (5,6) |
生成上方表格的 Python3 代码如下 ⬇️
print(r'| $n$ | $F_n$ | $F_n\bmod 10$| $a_n$ |')
print('| --- | --- | --- | --- |')
curr, next = 1, 1
for i in range(1, 21):
print(f'| ${i}$ | ${curr}$ | ${curr%10}$ | $({curr%10},{next%10})$ |')
curr, next = next, (curr + next)
对任意自然数 k 来说,0≤(kmod10)≤9 总是成立,所以 an 的可能取值只有 10×10=100 个(有的值可能取不到)。根据鸽笼原理,a1,a2,⋯,a101 这 101 个值必然有重复的(因为 an 的可能取值只有 100 个)。假设第一个重复出现的值为 adup 且 adup=adup−t。那么从 adup 开始,会有什么规律?
分析下标更大的项
注意到
an=(Fnmod10,Fn+1mod10)
an+1=(Fn+1mod10,Fn+2mod10)
Fn+2=Fn+1+Fn
所以
an+1=(Fn+1mod10,(Fn+1+Fn)mod10)
=(an[1],(an[0]+an[1])mod10)
也就是说,从 an 可以直接得出 an+1。
既然 adup=adup−t,那么必然有 ⬇️
- adup+1=adup−t+1
- adup+2=adup−t+2
- adup+3=adup−t+3
- ⋯
所以一旦发现了第一个重复值 adup,之后所有的值都会周期性出现(t 是它的一个周期)。那么随之而来的问题就是 dup 具体是多少。
分析下标更小的项
刚才提到从 an 可以直接得出 an+1,那么如果知道 an+1,能否反推出 an 呢?我们试一试 ⬇️
an=(Fnmod10,Fn+1mod10)
=((Fn+2−Fn+1)mod10,Fn+1mod10)
=((an+1[1]−an+1[0])mod10,an+1[0])
看来从 an+1 也可以直接得出 an。
有趣的部分来了。考虑到 adup=adup+t,根据刚才提到的 “从 an+1 也可以直接得出 an” 可知以下 dup 个等式都成立 ⬇️
- adup=adup+t
- adup−1=adup+t−1
- adup−2=adup+t−2
- ⋯
- a1=a1+t
所以 a1+t 会是第一个重复的值,它的值和 a1 相等。如此说来,我们只要找到第一个和 a1 相等的 an(n≥2),就可以得出周期 t=n−1 了。
代码实战
我们可以将上述思路用 Python3 来实现 ⬇️ (请将代码保存为 find_period.py)
appeared_fib_pairs = set()
fib_pair = (1, 1)
n = 1
while True:
if fib_pair in appeared_fib_pairs:
break
appeared_fib_pairs.add(fib_pair)
print(f'{n}: {fib_pair}')
next_fib_pair = (fib_pair[1], (fib_pair[0] + fib_pair[1]) % 10)
fib_pair = next_fib_pair
n += 1
用以下命令可以运行 find_period.py
python3 find_period.py
完整的运行结果如下
1: (1, 1)
2: (1, 2)
3: (2, 3)
4: (3, 5)
5: (5, 8)
6: (8, 3)
7: (3, 1)
8: (1, 4)
9: (4, 5)
10: (5, 9)
11: (9, 4)
12: (4, 3)
13: (3, 7)
14: (7, 0)
15: (0, 7)
16: (7, 7)
17: (7, 4)
18: (4, 1)
19: (1, 5)
20: (5, 6)
21: (6, 1)
22: (1, 7)
23: (7, 8)
24: (8, 5)
25: (5, 3)
26: (3, 8)
27: (8, 1)
28: (1, 9)
29: (9, 0)
30: (0, 9)
31: (9, 9)
32: (9, 8)
33: (8, 7)
34: (7, 5)
35: (5, 2)
36: (2, 7)
37: (7, 9)
38: (9, 6)
39: (6, 5)
40: (5, 1)
41: (1, 6)
42: (6, 7)
43: (7, 3)
44: (3, 0)
45: (0, 3)
46: (3, 3)
47: (3, 6)
48: (6, 9)
49: (9, 5)
50: (5, 4)
51: (4, 9)
52: (9, 3)
53: (3, 2)
54: (2, 5)
55: (5, 7)
56: (7, 2)
57: (2, 9)
58: (9, 1)
59: (1, 0)
60: (0, 1)
可见 an 的周期是 60,而 an[0] 就是斐波那契数列的个位数字,也就是说斐波那契数列的个位数字以 60 为周期,循环出现。