Chapter 5 流程控制与逻辑运算
If 语句
规范的表达式写作:
if (逻辑判断式) then
......
else
......
end if
如果只有单行命令的话还可以简写为 if (逻辑判断式) write(*,*) "Hello World!"
特别注意在Fortran 90里面关于等于和不等于的判断表达式分别为 ==
和 \=
逻辑判断语句的连接:
连接语句 | 运算规则 |
---|---|
.and. | 交集 |
.or. | 并集 |
.not. | 逻辑反向,若后面表达式不成立则整个表达式成立 |
.eqv. | 两个表达式逻辑结构一致则表达式成立 |
.neqv. | 两个表达式逻辑结构不一致则表达式成立 |
多重判断与嵌套
多重判断的写法为:
if (condition 1) then
......
else if (condition 2) then
......
else if (condition 3) then
......
else if (condition 4) then
......
else
......
end if
需要注意的是,如果判断满足条件1,则不会再对条件2等进行判断,会直接跳出循环,只会执行第一个满足条件的执行模块。
嵌套的写法为:
if (condition 1) then
......
if (condition 2) then
......
else if (condition 3) then
......
else
......
end if
end if
浮点数及字符的逻辑运算
对于浮点数的逻辑判断应该预留一点误差比如判断 SQRT(3.0)**2-3.0 == 0.0
则很有可能判断为错,则与有效数位的计算方式有关,在实际编程中应该预留一点误差 abs(SQRT(3.0)**2-3.0 - 0.0) < e
其中 e
为常数参数,设置为一个比较小的值。
select case 语句
在Fortran中使用select case语句会有一些限制:
- 只能用整数,字符及逻辑变量,不能使用浮点数及复数
- 每个case中所使用的数值必须是固定的常量,不能用变量
select case (variable)
case (num 1)
......
case (num 2)
......
case default
......
end select
GOTO 语句
在Fortran中由于可以对行表明行号,于是也可以使用 goto
语句直接跳到相应的行,但如果没有碰到goto
则会按照顺序继续往下。关于if
与 goto
有一个联用的技巧,附上示例:
C = A - B
! 这里如果 C<0 则goto 10,如果C=0 则goto 20,如果C>0 则goto 30
if (C) 10,20,30
10 write(*,*) 'A<B'
goto 40
20 write(*,*) 'A=B'
goto 40
30 write(*,*) 'A>B'
goto 40
40 stop
end
但是这种奇技淫巧还是不建议使用。
Chapter 6 循环
Do 循环
在Fortran里面Do循环的用法跟一般语言里面的for是一样的
do counter = 1, 10, 2
......
end do
这里面counter
为计数器,表示从1开始,步长为2,如果有
counter
≤
10
\text{counter}\leq 10
counter≤10则进入循环,否则退出循环。最后的步长默认为1,也可以是负数,但如果是负数的话需要额外注意循环的终止条件。用于设置计数器初值、上限及增值的数值可以是变量,不过这些变量的值只会在进入循环前被读取一次,在循环中改变他们并不会对循环发生作用。
Do while 循环
Fortran里面的Do while语句替代的是C语言中的while语句,用法基本一致
do while(逻辑判断)
......
end do
循环的流程控制
CYCLE 与 EXIT
cycle
是指跳出本次循环进入下一次循环,总的循环次数并不会改变;exit
则是跳出整个循环结构
署名循环
在Fortran里面可以对循环署名,然后配合 cycle
exit
等的使用让循环更加方便,可以看一段示例代码:
loop1: do i=1,3
loop2: do j=1,3
if ( i==3 ) exit loop1 ! 跳离loop1循环
if ( j==2 ) cycle loop2 ! 重做loop2循环
write(*, "('(',i2,',',i2,')')" ) i, j
end do loop2
end do loop1
这样的输出结果则是 (1,1) (1,3) (2,1) (2,3)
四组数据
Chapter 7 数组
基本使用
Datatype name(size)
作为数组的一般声明方法,其中Datatype
为数组的类型,可以是整数型浮点型也可以是自定义的类型,size
则是数组的大小,需要注意这里必须是整型。再给出几组声明示例:
integer a(10) ! solution 1
integer, dimension(10) :: a ! solution 2
integer a ! 来自于Fortran77 的做法 先声明为整型
dimension a(10) !solution 3
Type(person) :: a(10) ! 声明自定义数据类型person的数组
二维数组的定义方式与之类似:
integer a(10,10) ! solution 1
integer, dimension(10,10) :: a ! solution 2
进一步可以声明并调用高维数组(Fortran77最高只支持7维):
integer a(D1,D2,...,Dn) ! n 维数组
a(I1,I2,...,In) ! 使用n维数组
PS:其实可以在声明数组时修改索引,比如:
integer a(0:5) ! a(0)~a(5)共6个元素
integer a(-3:3) ! a(-3)~a(3)共7个元素
数组内容的设置
Fortran里面给数值赋予初值的方法很多,可以用DATA
赋值:
DATA A /1,2,3,4,5/
INTEGER A(5)
DATA A /5*3/ ! 在此指有5个3
还有一种“隐含式”循环功能
DATA (A(I), I=2,4) /2,3,4/
这里是设置A(2)=2, A(2)=3, A(4)=4
当然对于隐含的循环还可以修改步长(A(I), I=2,10,2)
在Fortran 90里面可以省略掉 DATA
的描述,直接设置初值
integer :: a(5)=(/1,2,3,4,5/)
注意这里的括号和除号之间不能有空格,还可以借助隐含式的功能
integer :: a(5) = (/1,(I, I=2,4),5/)
同样还可以设置二维数组
integer :: m(2,2)
data((m(r,c), r=1,2),c=1,2) /1,2,3,4/
注意对于隐含式而言是先进行内部的循环再进行外部的循环。
Fortran还可以对整个数组赋一个值 integer :: a(5)=5
假设数组 a,b
是两个规模一样的数组,则下列操作都是对于数组中每个元素的操作,最后得到的结果也为同样规模的数组
c = a + b
c = a - b
c = a * b
c = a / b
c = sin(a)
c = a > b !此时为逻辑数组
对于部分数组的操作主要是通过冒号来进行
a(3:5) ! 取a(3) a(4) a(5)
a(3:) ! 取a(3)及之后的所有元素
a(1:5:2)! 取a(1) a(3) a(5)
a(1:10) = a(10:1:-1) ! 对a进行翻转
在Fortran 95里面新增加了功能 where
是取出部分数组进行设置,要注意的是 where
与 do
的用法基本一致但是前者的代码更简洁而且支持并行;还有就是where
的程序模块里面只能出现跟数组有关的命令且涉及到的数组必须是同样维度的!!!
在实际运用过程中where
的用法跟if
类似,可以嵌套可以命名:
where(a<2)
b=1
elsewhere(a>5)
b=2
elsewhere
b=3
end where
同样是新增加功能的还有forall
可以看成是隐含式循环来使用数组的方法,具体用法为:
forall (triplet1[, triplet2 [, triplet3 ...] ], mask)
...... ! triplet1 用于赋值数组坐标范围的值
...... ! mask 用来做条件判断
end forall
数组的存储
在Fortran里面数组都是一整块的存储空间,多维数组而言则是遵循列优先法则排列,或者称为最高维优先的原则,对于A(i,j)
i所在的就是行(低维),j所在的就是列(高维),在存储的时候会优先存储低维的数据,之后再存储高维的数据,比如对于3x3的数组顺序为:
A
(
1
,
1
)
=
>
A
(
2
,
1
)
=
>
A
(
3
,
1
)
=
>
A
(
1
,
2
)
=
>
A
(
2
,
2
)
=
>
.
.
.
.
.
.
A(1,1)=>A(2,1)=>A(3,1)=>A(1,2)=>A(2,2)=>......
A(1,1)=>A(2,1)=>A(3,1)=>A(1,2)=>A(2,2)=>......
而这个在C语言里面是恰巧相反的这点非常重要,因为在读取数据的时候是根据cache line一次读取若干个相邻数据,如果相邻调用的数据在存储上也是相邻的,则能大大提高效率。
可变大小的数组
integer, allocatable :: a(:) ! 声明一个可变大小的数组
在声明之后还不能使用还需要配置内存空间
allocate(a(100), stat=error) ! error 为0表示allocate数组成功
相应的还有释放内存空间
deallocate(a)