内容正文:
4.2数值计算
——斐波那契数列
斐波那契数列 P107
斐波那契在《计算之书》中提出了一个有趣的兔子问题:假设一对兔子每个月可以生一对小兔子,一对兔子出生后第2个月就开始生小兔子。则一对兔子一年内能繁殖成多少对?10年呢?
斐波那契数列
月份 兔子对数 合计
1月 1小 1
2月 1大 1
3月
4月
5月
6月
规律:从第3个月起,每个月兔子的对数等于上个月兔子的对数加上上个月兔子的对数。第n个月:n=(n-1)+(n-2)
2
3
5
8
1大+1小
3大+2小
5大+3小
2大+1小
用WPS表格求解斐波那契数列
但是,当计算到第74个月的时候,由于数据范围及表示精度的问题,导致结果出错。
用表格软件计算,只能精确计算到第74个月,无法精确计算10年即第120个月的兔子数量。
按照规律,从第3个月起,每个月的兔子等于前2个月兔子之和,计算每个月的兔子
用编程求解斐波那契数列
分析问题:
1、因为每一项等于前两项之和,所以要有两个变量来保存前两项的数字,初始化前两项值都为1,所以f1=1,f2=1,利用Python的多变量赋值可简写为
f1=f2=1
循环范围?
2、从第3个月开始循环,到第n个月,所以range(3,n+1)
for i in range(3,n+1)
3、每次的f1、f2如何变化?
f=f1+f2
4、返回值应该是什么?
n=2,返回1
n=3,返回2
n=4,返回3
n=5,返回5
返回的结果刚好是f2的值,故return f2
用编程求解斐波那契数列
3、每次的f1、f2如何变化?
月份n 1 2 3 4 5 6 7 8
兔子对数 1 1 2 3 5 8 13 21
f1
f2
f1
f2
f
f1=f2
f2=f
f
f1
f2
这三行语句在不断地重复运行
f
f2
f1
f
def f (n): #自定义函数
f1 = f2 = 1 #第1个月、第2个月初始值,等价于f1=1,f2=1
for i in range (3, ____): #
f=f1+f2
f1=f2
f2=f
return f2
n= int (input('请输入需要计算的月份数:'))
print(“兔子总对数为:”,f(n))
用编程求解斐波那契数列
从第3个月至第n个月依次计算
n+1
第1个月和第2个月兔子对数之和为第3个月兔子对数,f=f1+f2
第2个月和第3个月兔子对数之和为第4个月的兔子对数......,
每个月的兔子对数是前两个月的兔子对数之和,又同时作为下一个月兔子对数的加数。
这种重复反馈的过程称为迭代。
迭代法也称辗转法。是计算机解决问题的一种基本方法。
每一次对过程的重复被称为一次“迭代”。
每一次迭代得到的结果会被用来作为下一次迭代的初始值。
目的:为了接近并达到所需的目标或结果。
迭代法
利用迭代算法解决问题的步骤:
(1)确定迭代变量,如f1、f2;
(2)建立迭代关系式,如f=f1+f2,f1=f2,f2=f;
(3)对迭代过程进行控制,这是编写迭代程序必须考虑的问题,
不能让迭代过程无休止地重复执行下去,如for i in range(3,n+1)。
迭代法总结
递归法
递归:函数自己调用自己,但必须有终止条件,避免陷入死循环。比如镜子里的镜子、俄罗斯套娃
VS 迭代:有限的循环求解,例如for、while等
在数学与计算机领域中,递归函数是指用函数自身来定义该函数的方法。如斐波那契数列“1,1,2,3,5,8,13,……”可以递归定义为:
f(n)=
1 (n=1或n=2)
f(n-1)+f(n-2) (n>2)
用递归法求解斐波那契数列
def f (n):
if n==1 or n==2:# or是逻辑运算符,或的意思
return 1
else:
return f(n-1)+f(n-2)
分析问题:如果n等于1或2时,f(n)=1
【作为递归的终止条件】
否则f(n)=f(n-1)+f(n-2)
比如求f(4)
f(4)=f(3)+f(2)
f(3)=f(2)+f(1)
1 + 1
1
f(n)=
1 (n=1或n=2)
f(n-1)+f(n-2) (n>2)
思路:把复杂的第 n 项,拆成更为简单的子问题,不断往下拆,拆到最简单的初始条件,再往回代计算。
迭代法VS递归法
1、迭代法(正向:从1推到5)
思路:从第一项开始,从前向后,一步一步算,用前面的结果推出后面的结果
S1=1,已知起点
S2=S1+2=3
S3=S2+3=6
S4=S3+4=10
S5=S4+5=15
特点:从前往后、从小到大、逐项累加,依次推出每一项的结果。
Sn=1+2+3+⋯+n
已知S1=1 , Sn=Sn-1+n, 求S5
2、递归法(逆向:从 5 拆到 1,再回头算)
思路:把复杂的第 n 项,拆成前面一项加一个数,不断往下拆,拆到最简单的初始条件,再往回代计算。
比如想算S5,必须先知道S4,
想算S4,必须先知道S3
……
拆到 S1 不能再拆了,再往回代计算
第一步:只拆解,不计算
S5=S4+5
S4=S3+4
S3=S2+3
S2=S1+2
第二步:再从下往回代计算
S2=1+2=3
S3=3+3=6
S4=6+4=10
S5=10+5=15
特点:从后往前拆,大事拆成小事,拆到初始条件,再回头一步步算结果。
课堂练习
将横线处的代码补充完整上机运行
求出n=6时的
拓展:辗转相除法(欧几里得算法)
欧几里得算法又称辗转相除法,是指用于计算两个正整数m, n的最大公约数。
核心原理:对于两个正整数 m,n (m,n>0):
1、用m÷n 得到余数r
2、把原来的除数n当作新被除数m,即m=n; 余数r当作新除数n,即r=n
3、重复相除取余,直到余数 r= 0
4、最后一个不为 0 的除数,就是两数的最大公约数(gcd)
公式简写:gcd(m,n)= gcd(n, m mod n)
表示:求两个数的最大公约数,可以转化成求“较小的数”和“余数”的最大公约数。
用辗转相除法求两个数的最大公约数
m=int(input(“请输入第一个正整数:”))
n=int(input(“请输入第二个正整数:”))
r=m% n
while r!=0: #只要余数r不为0,就继续辗转相除
m=①
n= ②
r=m % n
print(“这两个数的最大公约数为:”, ③ )
n
r
n
m=48 , n=18
①m÷n=48÷18=2 余 12, r=12
m=n=18,n=r=12
→ gcd(48,18) = gcd(18,12)
②m÷n=18÷12=1 余 6, r=6
m=n=12, n=r=6
→gcd(18,12) = gcd(12,6)
③m÷n=12÷6=2 余 0,r=0
→ gcd(12,6) = 6
因为余数为0,算法停止。所以gcd(48,18)=6
求gcd(48,18)
#常规循环求解
课堂练习
m=21 , n=56
①m÷n=21÷56=0 余 21, r=21
m=n=56,n=r=21
→ gcd(21,56)=gcd (56, 21)
②m÷n=56÷21=2 余 14, r=14
m=n=21, n=r=14
→ gcd (56, 21)=gcd (21,14)
③m÷n=21÷14=1 余 7 ,r=7
m=n=14, n=r=7
→ gcd (21,14)=gcd (14, 7)
因为余数为0,算法停止。所以gcd(21,56)=7。
求gcd(21,56)
辗转相除法不要求第一个数m比第二个数n大。
如果第一个数小,第一步其实就是交换位置,把大的数换到前面。
比如 gcd(21, 56),第一步 21 ÷ 56 = 0 余 21,就自动变成了 gcd(56, 21)。
④m÷n=14÷7=2 余 0 ,r=0
迭代法也称辗转法。是计算机解决问题的一种基本方法。
每一次对过程的重复被称为一次“迭代”。
每一次迭代得到的结果会被用来作为下一次迭代的初始值。
目的:为了接近并达到所需的目标或结果。
课堂小结
迭代
确定迭代变量
建立迭代关系式
控制迭代过程
迭代法步骤:
sum,a,b,t=0.0,1,1.0,1.0 #给各参数依次赋值
while b<1000:
sum=sum+__①__
b=__②__
a=__③__
t=a/b
pi = __④__
print("pi的值是{:.20f}".format(pi)) # 输出20位浮点型数值
拓展延伸:求解圆周率近似值
t
b+2
-a
圆周率的近似值,求解关系式为:
4*sum
前两个月的第一个月记为f1,第二个月记为f2
f1=f2
f2=f1+f2
4、返回值应该是什么?
n=1或2,返回1
n=3,返回2
n=4,返回3
n=5,返回5
返回的结果刚好是f2的值,故return f2
用迭代法求解斐波那契数列
3、每次的f1、f2如何变化?
拓展:辗转相除法(欧几里得算法)
欧几里得算法又称辗转相除法,是指用于计算两个正整数m, n的最大公约数。
核心原理:对于两个正整数 m,n (m>n>0):
1、用大数 ÷ 小数,m÷n 得到余数r
2、把原来的除数当作新被除数,余数当作新除数
3、重复相除取余,直到余数 = 0
4、最后一个不为 0 的除数,就是两数的最大公约数(gcd)
公式简写:
gcd(m,n)
m = n n = r
m = n n = r
$