【程序设计】3.1 [做循环] 单层循环

 

3.1 单层循环

目前为止,我们写的代码都是从前向后执行一遍就结束了。if 语句可能导致某些代码被跳过而不执行,程序的总体流向仍然是向前向后的,没有一句代码会被执行多次。

事实上,计算机最擅长做的是重复劳动,就是一遍遍地执行同样的代码。显然,我们不应该把代码重复地抄写多遍,这就需要程序语言有循环的能力。

我们来计算 1+2+…+100:


A

B

1

=0


2

for 100

>A1=A1+A2

只有这么两行就可以了,程序执行完,A1 格值就变成我们要的答案:5050。

几乎所有程序语言用于循环语句的关键字都是 for,SPL 也不例外。

A2 格里的 for 100 表示将把 A2 的代码块重复执行 100 次,这里 A2 的代码块只有 B2 一格,也就是会把 B2 执行 100 次。执行过程中,A2 本身的格值,会从 1 开始、每执行一次后加 1,最后变成 100。

A2 这种有 for 的格子,称为循环格。A2 的代码块,也就是要被重复执行的代码,称为 A2 的循环体。而 A2 本身又称为这个循环的循环变量,它会从 1 开始变到循环次数。

再来看这段代码,我们之前理解过 x=x+1 这样的语句,这里循环体中 A1=A1+A2 是类似的,就是每次在当前的 A1 基础上再加上当时的 A2,而 A2 会从 1 开始增加到 100,这样 A1 也就会加 1、加 2、…,一直加 100,也就完成了 1+2+…+100 的运算。

我们还可以用这种结构来计算 1+3+5+…+199,即前 100 个奇数。


A

B

1

=0


2

for 100

>A1=A1+(2*A2-1)

这次还是 100 个数相加,所以循环 100 次,循环变量 A2 仍然是从 1 变化到 100,但要加的数不再是直接的循环变量,要通过循环变量计算出来(2*A2-1)。

再做一个稍复杂的运算,根据泰勒公式:imagepng 来计算自然对数底数 e 的近似值,我们加前 20 项看看:


A

B

1

=1

=1

2

for 20

>B1=B1*A2

3


>A1=A1+1/B1

4

=exp(1)-A1


这里需要引入一个辅助变量 B1,用于存储第 n 项的阶乘值 n!,它也是在循环中逐步计算出来的。最后结果累加在 A1 中,用 A4 的表达式来看看我们计算的结果和实际值差多少,函数 exp(1) 将计算出 e(的 1 次方)。

这个代码的循环次数不能太多,因为 n! 会变得很大,很快就会超出浮点数的范围。

斐波那契数列是这样的一种数列:第 1 和第 2 项都是 1,从第 3 项起,每一项都等于前两项之后,写出来是 1,1,2,3,5,8,…。这是有名的兔子序列,有兴趣可以去搜索它的来历,这里不赘述。

现在我们来计算斐波那契数列的第 n 项,n>2。


A

B

1

=1

=1

2

20


3

for A2-2

=A1+B1

4


>A1=B1

5


>B1=B3

B1 中就是我们需要的结果。A2 是我们希望计算的项数,就是 n。

for 语句中的循环次数,不一定总是个常数,还可以是个计算表达式 A2-2。因为最初两项已经有了,所以只要计算 n-2 次即可。这个循环体中没有用到循环变量了,A3 只是起到控制循环次数的作用。

在 B3 中把下一项计算出来,然后再分别填入 A1 和 B1 替代原来的项。这样,每循环一次,A1 和 B1 就相当于在婓波那契数列中向后移动了一次,从第 1、2 项变成第 2、3 项,再变成第 3、4 项,…,循环结束时,会变成第 n-1、n 项,B1 就是我们需要的结果。

这个代码还可以少写一行,不用中间的变量:


A

B

1

=1

=1

2

20


3

for A2-2

>B1=A1+B1

4


>A1=B1-A1

其中的逻辑,自己调试一下去想明白吧。

我们在上一节学过了 goto 语句,其实还可以用 goto 和 if 配合制造出 for 语句的效果,比如第一个 1+2+…+100 的例子:


A

B

1

=0

=1

2

if B1<=100

>A1+=B1

3


>B1+=1

4


goto A2

这里 A1+=B1 就相当于 A1=A1+B1,类似地,B1+=1 相当于 B1=B1+1,这是 C 语言的简化写法,SPL 中延用了这种风格,x+=y 相当于 x=x+y。同样减法、乘法、除法都可以这样写,不过还是加法最常用。

使用 if 和 goto 来制造循环,需要人为定义一个循环变量,就是这里的 B1,先要对循环变量赋一个初值 1。然后用 if 语句来判断循环是否结束,如果没结束则执行循环体,执行完了还要自己把循环变量做一次加 1 的动作,然后再用 goto 回跳回去再执行。如果循环结束的条件成立了,if 语句就不再执行循环体了。

显然,for 语句写出来的循环要比 if…goto 结构要简单,还不容易出错(万一漏掉了把循环变量加 1 的动作,if…goto 制造的循环就永远不会结束了)。而且这样的 goto 违背了前面说的不要向前跳的原则。所以我们一般不会使用 if…goto 来制造循环。

【程序设计】 前言及目录
【程序设计】2.3 [做判断] 注释和跳转
【程序设计】3.2 [做循环] 多层循环