blueyi's notes

Follow Excellence,Success will chase you!

0%

Fortran 95快速学习笔记

仅仅实现能看懂Fortran代码,简单实现,所以主要是与C/C++进行对比语法差异,基于Fortran95/2003版本,Fortran的各版本保持着向下兼容。

Hello World

1
2
3
4
5
6
7
8
!后面的基本语法处一一解释其含义
PROGRAM First_Fortran
IMPLICIT NONE
WRITE(*,*), &
'Hello World'
PAUSE !暂停程序,enter后继续
STOP
END PROGRAM First_Fortran

基本语法

1.Fortran对大小写不敏感。使用语句行来表示语句的开始和结束而不是分号。
2.长语句需要分两行时需要在第一行的行尾使用&来结束
3.可以使用1~99999之间的任意数字放在行Fortran语句行的行首作为该语句的语句标号,可以在程序的其他地方通过该数字引用这条语句,语句标号必须是惟一的。
4.感叹号!开始到行尾的字符为注释,将被编译忽略。注释可以放在程序的任何位置。
5.PROGRAM语句对编译器指定程序的名字,名字命名类似C,但必须以字母开头,该语句必须放在第一个语句行,相当于指定程序的执行入口。
6.WRITE表示向输出写入数据,两个参数与READ中的意思相同。eg:

1
WRITE (*,*) output_list !output_list是输出项列表,多个数据项应使用逗号隔开

WRITE的表控输出语句等价于PRINT *, output_list
7.READ为从输入读取数据,其中的第一个参数指明从哪个输入/输出单元读入数据,星号表示标准输入,第二个参数指明读入数据的格式,星号表示使用表控输入,即意味着为变量列表中的变量类型决定输入数据需要的格式。eg:

1
READ (*,*) input_list !将数据读入的变量列表中

每一条READ将始终从一个新行开始读取,如果上一行输入有剩余则会自动被清除
8.STOP告诉计算机停止运行,END PROGRAM告诉编译器程序中不再有语句需要编译,当STOP紧挨着END PROGRAM语句时,它是可选的。
9.Fortran程序书写风格:

  • 1.保留字都大写
  • 2.程序的变量用小写字母表示
  • 3.常量名最好也使用大写,如PI(3.14159)
  • 4.名字中的下划线出现在两个字之间
    10.Fortran的语句分为可执行语句(executable)和不可执行语句(unexecutable),声明即是不可执行语句,应放在程序的开头
    11.IMPLICIT NONE语句表示使Fortran中默认提供输入值类型的功能失效,该语句应该出现在PROGRAM语句之后和类型声明语句之前。默认输入值类型是指在Fortran中,变量可以不经定义直接使用,而变量的类型是以变量名的第一个字母来区分的,例如IMPLICIT real*8(A-H,O-Z)即表壳A到H开头的变量类型都是浮点型。使用IMPLICIT NONE之后而所有变量必须在使用之前定义。

基本数据类型及其运算

1.Fortran有5个内置的数据类型,其中三个对数字有效(INTEGER, REAL, COMPLEX),一个逻辑相关(LOGICAL),另一个是字符串(CHARACTER)。
2.字符文本可以使用单引号’,也可以使用双引号”
3.有两种方式可以定义变量的类型:默认式和显式。如果在程序中没有明确指定变量类型,那么就是默认式定义变量类型,默认方式为:任何以字母I,J,K,L,M或N开头变量名都假定为INTEGER,其他字母开头的变量名假定为REAL,注意Fortran对大小写不敏感。例如默认情况inc的变量为整形,big为实型。
IMPLICIT NONE语句将使默认变量类型功能失效。
显式声明方式为INTEGER :: var1 [, var2, var3, ...],其中[]表示其中的内容可选,只声明不初始化的话双冒号也是可选的。
4.字符串的声明方式:

1
2
3
CHARACTER(len=10) :: first, last !声明两个长度为10的字符变量
CHARACTER :: initial !声明一个长度为1的字符变量
CHARACTER(15) :: id !id长度为15

5.使用PARAMETER属性创建常数类型,方式为type, PARAMETER :: name=value [, name2=value2, ...]其中type的类型可以是整形,实型,逻辑型或字符型。eg:

1
REAL , PARAMETER :: PI = 3.141593

6.**表示指数运算。
7.Fortran95/2003中含有5个强制类型转换函数:

  • INT(X) 将REAL类型的X转换其整数部分
  • NINT(X) 返回REAL类型的X的四舍五入结果
  • CEILING(X) 大于或等于X的最小整数值,X为REAL
  • FLOOR(X) 小于或等于X的最大整数值,X为REAL
  • REAL(I) 将整数转换为实数
    8.变量不会被默认初始化
    9.逻辑数据类型只有两个可能的值:true和false,分别对应的内置逻辑常数是.TRUE..FALSE.(注意两连的句点),逻辑变量声明方式LOGICAL :: var1, [, var2, var3, ...],所有声明都应该放在第一条执行语句之前,PROGRAM语句之后。
    10.关系运算符中/=表示不等于,对应的旧形式为.NE.,所有运算符:
    1
    2
    新形式:==   /=	    >    >=    <    <= 
    旧形式:EQ. .NE. .GT. .GE. .LT. .LE.

11.组合逻辑运算符:

  • .AND. 逻辑与
  • .OR. 逻辑或
  • .NOT. 逻辑非
  • .EQV. 逻辑等值,相同为真
  • .NEQV. 逻辑非等值,不相同为真

12.当逻辑变量出现在以READ开头的语句中时,相应的输入值必须以T或F开头的一个或一组字符,相应的值被设置为.TRUE..FALSE,输入其他字符开头将产生运行时错误。当逻辑变量或表达式出现在以WRITE开头的语句中时,相应输出将为单个字符T或F。
13.字符串声明与赋值:

1
2
CHARACTER(len=3) :: str
str = 'f'

当字符串长度小于变量长度时,默认使用空格填充
14.Fortran中的数组首元素是从1而不是0开始,子串抽取与python一样。例如若str=’12345’,则str(2:4)为234
15.连接操作符//可以将两个子串连接成一个大串。
16.可以在定义类型里手动指定变量所占用的字节大小。方法如下:TYPE(kind) :: var,其中kind为正整数,表示该变量所占字节数,如果不指定默认为长整型4或浮点型的8。例如INTEGER(4) :: var,var为占用4个字节的整型。Fortran90之前的编译器声明方式为INTEGER*4 var
16.real(8) var var = 0.0_8 表示为var初始化值为0.0,且占8个字节。

控制语句

1.IF语句与C中类似,形式如下:

1
2
3
4
5
6
7
8
9
10
11
[名称: ]IF (logical_expr) THEN
statement 1
statement 2
ELSE IF (logical_expr_2) THEN [名称]
statement 1
statement 2
ELSE [名称]
statement 1
statement 2
...
END IF [名称]

其中IF THEN必须在同一行,且其下面一行必须紧跟可执行语句,ELSE,ELSE IF和END IF也必须独占一行,END IF前面面不能有行号
其中名称是可选的,但如果IF前面有名称那么END IF后面也必须有,且同名
当IF语句块中只有一行语句时,等价于IF (logical_expr) expression
2.当嵌套使用IF语句时,最好为其命名
3.SELECT CASE语句类似于C中每个case都带有break语句的switch,用法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[name: ]SELECT CASE (case_expr)
CASE (case1) [name]
statement 1
statement 2
...
CASE (case2, case3, case4) [name]
statement 1
statement 2
...
CASE DEFAULT [name]
statement 1
statement 2
...
END SELECT [name]

其中case_expr可以是任意的整数、字符或逻辑表达式。对应的每个子case必须是整数、字符或逻辑数值,或数值范围,所有子case必须相互独立。其中数值范围是指以冒号隔开的一个范围,与python中的范围表示方式一样,如(1:10)表示1~10。

4.DO循环:

1
2
3
4
5
DO 
...
IF (logical_expr) EXIT
...
END DO

5.DO WHILE循环:

1
2
3
4
5
DO WHILE (logical_expr)
statement 1
...
statement n
END DO

6.迭代DO循环,类型C中的for循环:

1
2
3
4
5
DO index=istart,end,incr
statement 1
...
statement n
END DO

其中index是一个整数变量,作为循环计数器使用,整数istart,iend和incr分别表示计数起始值,结束值和步长,它们可以是常量、变量或表达式,当incr省略时,步长默认为1。如果index*incr <= iend*incr

7.控制语句中的CYCLE相当于C中的continue,EXIT相当于C中的break。
8.循环语句也可以被命名,规则与IF命名一样。

IO操作

1.格式化的WRITE输出:

1
2
WRITE (*,100) i, result
100 FORMAT (' The result for iteration ', I3, ' is ', F7.3)

意思是输出i和result,使用100做为语句标号,相当于一个大的占位符,用于代替WRITE语句的第二个控制输出方式的参数,输出结果即是字符串正常输出,带有占位符的地方,使用对应值替换。例如I3表示以占用3个字符宽度的方式输出INTEGER类型的i,F7.3表示以占用7个字符宽度且保留小数点后3位方式输出REAL类型的result。

2.以下三个输出结果是等价:

1
2
3
4
5
6
7
8
WRITE (*, 100) i, x	    !使用FORMAT控制格式
100 FORMAT (1X, I6, F10.2)

CHARACTER (len = 20) :: string !使用字符变量控制格式
string = '(1X, I6, F10.2)'
WRITE (*, string) i, x

WRITE (*, '(1X, I6, F10.2)') i, x !在字符常量中的格式

3.老式的Fortran编译器的格式控制字符中的第一个字符将起到控制输出格式的作用,所以上面1例中FORMAT的内容以空格开头,但在Fortran2003之后的版本中并没有这个限制。具体控制字符的作用如下:

  • 1 跳转到新页
  • 空格 单行间距
  • 0 双行间距
    • 没有间距(在前一行上打印)

下面的两句是等价的,都表示在新的一页的开头打印输出

1
2
WRITE (*,"('1', 'Count = ', I3)") icount
WRITE (*,"('1Count = ', I3)") icount

4.控制格式描述的符号如下:

  • c 列号
  • d 实数输入或输出小数位右边的位数
  • m 要显示的最小位数
  • n 要跳过的空格数
  • r 重复计数——一个描述符或一组描述符的使用次数
  • w 域宽——输入或输出使用的字符数

5.常见的输出控制格式:

  • 整数输入——I描述符的一般格式为rIwrIw.m
  • 实数输出——F描述符一般格式为rFw.d
  • 实数输出——E描述符一般格式为rEw.d
  • 真正的科学计数输出——ES描述符一般格式为rESw.d
  • 逻辑输出——L描述符一般格式为rLw
  • 字符输出——A描述符一般格式为rArAw
  • X描述符用于在缓冲区中插入间距,用法为nX
  • T描述符用于在缓冲区中跳过特定列,用法为Tc,其中c为要转到的列号
  • 改变输出行——斜线(/)描述符,类似C中的\n,用于换行

举例,以下两条语句是等价的:

1
2
320 FORMAT ( 1X, I6, I6, F10.2, F10.2, I6, F10.2, F10.2 )
320 FORMAT ( 1X, I6, 2(I6, 2F10.2) )

当格式控制字符中的宽度无法表示所要输出的数字时,不像C中直接全部输出,Fortran会输出为星号*,例如格式控制字符I1,输出10的时候,会输出一个*

6.输出格式要与输出变量严格对应,否则会有运行时错误
7.READ的读取格式控制与WRITE一一对应
8.Fortran的I/O读写语句的第一个参数就是用于指定读写设备。该位置的星号即表示标准输出或输入,如果使用其他设备则需要指定I/O单元号,单元号必须为整数类型。
9.常用的I/O语句:

  • OPEN 将指定的文件与指定的I/O单元号关联
  • CLOSE 取消指定的文件与指定的I/O单元号的关联
  • READ 从指定的I/O单元读取数据
  • WRITE 向指定的I/O单元写入数据
  • REWIND 移动到文件的开头
  • BACKSPACE 在当前打开的文件中向后移动一个位置

10.OPEN用法为OPEN (open_list),期中open_list包含一组子句,分别指定I/O单元代号、文件名和关于如何存取文件的信息,这些列表使用逗号隔开。
11.open_list中最重要的六项内容:

  • UNIT=int_expr 指明与文件关联的I/O单元代号,int_expr可以是非负的整数值
  • FILE=char_expr 指定要打开的文件名,char_expr是一个包含要打开文件的名称的字符值
  • STATUS=char_expr 指定要打开的文件状态,char_expr为下列值中的一个:'OLD''NEW''REPLACE''SCRATCH''UNKNOW'
  • ACTION=char_expr 指定一个文件是以只读、只写或读写方式打开。char_expr为下列值中的一个:'READ''WRITE''READWRITE',如果没有指定任何操作,则默认以读写方式打开。
  • IOSTAT=int_var 指定一个整数变量名,打开操作的状态可以返回到这个变量中。如果OPEN语句成功执行,则返回给这个整数变量的值为0。
  • IOMSG=chart_var 指定一个字符变量名,如果发生错误,则该错误信息将返回给这个变量。如果OPEN语句成功执行,则该变量的内容不变。
    示例:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    !打开一个名为EXAMPLE.DAT的文件,并将其连接到I/O单元8上
    INTEGER :: ierror
    OPEN (UNIT=8, FILE='EXAMPLE.DAT', STATUS='OLD', ACTION='READ', &IOSTAT=ierror)
    !以自由格式从文件中读取值到x,y,z
    OPEN (UNIT=8, FILE='INPUT.DAT', STATUS='OLD', IOSTAT=ierror)
    READ (8,*) x, y, z
    !以特定的格式向文件OUTPUT.DAT中写入变量x,y,z的值
    OPEN (UNIT=9, FILE='OUTPUT.DAT', STATUS='REPLACE', IOSTAT=ierror)
    WRITE (9,100) x, y, z
    100 FORMAT (' X = ', F10.2, ' Y = ', F10.2, ' Z = ', F10.2)

12.BACKSPACE和REWIND语句的功能相当于修改文件指针所指向的位置

13.READ在按行读取文件时会自动跳过空行

数组

1.Fortran中的数组元素从下标1开始,通过小括号()访问
2.数组声明方式如下:

1
2
3
4
5
6
7
!声明一个含有16个元素的实型数组voltage
REAL, DIMENSION(16) :: voltage
!等价于
REAL :: voltage(16)

!声明一个含有50个长度为20位字符的数组变量last_name
CHARACTER (len=20), DIMENSION(50) :: last_name

DIMENSION属性说明被定义数组的大小
3.通过(/…/) 可以构建常量数组,如(/ 1, 2, 3, 4, 5 /)构建了一个含有5个整型元素的数组常量
4.数组的初始化可以先声明然后使用赋值的方式初始化,或者使用数组构建器初始化,也可以通过给数组名赋值将所有元素初始化同一个值,或者在声明时直接初始化。eg:

1
2
3
4
5
6
7
8
9
10
REAL, DIMENSION(10) :: array1
DO i = 1, 10
array1(i) = REAL(i)
END DO
!等价于
array1 = (/1., 2., 3., 4., 5., ..., 10./)
!等价于
REAL, DIMENSION(10) :: array1 = (/1., 2., 3., 4., 5., ..., 10./)
!将所有的array1初始化为0
array1 = 0

5.可以使用隐式DO循环初始化数组,形式为(arg1, arg2, ..., index = istart, iend, incr),其中arg1, arg2等是每次循环执行时估算的值,隐式DO循环支持嵌套。eg:

1
2
!上面声明并初始化array1的等价形式
REAL, DIMENSION(10) :: array1 = (/ (REAL(i), i=1, 5) /)

6.可以使用以下方式在声明时指定下标取舍范围:

1
2
!该数组的大小为upper_bound - lower_bound + 1
REAL, DIMENSION(lower_bound : upper_bound) :: array

7.声明常量名来作为数组大小:

1
2
INTEGER, PARAMETER :: MAX_SIZE = 1000
REAL :: array1(MAX_SIZE)

8.当两个数组元素类型和大小相同时,对数组名的运算相当于对数组的每个元素分别进行运算,如:

1
2
REAL, DIMENSION(10) :: a, b, c
c = a + b !等价于c(i) = a(i) + b(i)

9.可以使用下标三元组或向量下标的形式来使用数组的部分变量,称为部分数组(section array),三元组的使用方式为subscript_1 : subscript_2 : stride,当stride省略时,表示默认步长为1,当subscript_1省略时默认表示从第一个元素开始,当subscript_2省略时默认到最后一个元素,与python的包前不包后不同,Fortran这种局部数组前后都包。
10.向量下标的使用方式如下:

1
2
3
INTEGER, DIMENSION(5) :: vec = (/1, 6, 4, 1, 9/)
REAL, DIMENSION(10) :: a = (/1., -2., 3., -4., 5., -6., 7., -8., 9., -10./)
!a(vec)的内容是数组[1., -6., -4., 1., 9.]

11.读写数组时可以使用隐式DO循环,形式如下:

1
2
3
4
5
6
7
8
WRITE (unit, format) ( arg1, arg2, ... , index = istart, iend, incr)
READ (unit, format) ( arg1, arg2, ... , index = istart, iend, incr)
!以下打印前5个元素的方法等价
WRITE (*,100) a(1), a(2), a(3), a(4), a(5)
100 FORMAT (1X, 'a = ', 5F10.2)
!等价于
WRITE (*,100), (a(i), i = 1, 5)
100 FORMAT (1X, 'a = ', 5F10.2)

12.隐式DO循环可以嵌套使用
13.

Fortran过程控制

1.Fortran的有两种方式实现调用外部过程,分别是子程序(subroutine)和函数之程序(function subprogram)。子程序通过CALL语句调用,并且可以通过调用参数来返回多个结果。函数子程序则通过在表达式中引入函数名来进行调用,它的结果是单个数值,该值用来为表达式赋值,就像数学中的函数那样。

子程序

2.子程序的声明格式如下:

1
2
3
4
5
6
7
8
SUBROUTINE subtine_name(argument_list)
...
(Declaration section)
...
(Execution section)
...
RETURN
END SUBROUTINE [name]

其中argument_list中不能附带参数类型,但在子程序内容的声明部分必须要为相应的参数声明类型
子程序就相当于一个独立的程序,只是可以带参数,所以在声明部分的前面同样需要单独加上IMPLICIT NONE
3.子程序的调用格式如下:

1
CALL subroutine_name(argument_list)

4.子程序的参数传递方式为传址传递,相当于C语言中传递指针,所以子程序会直接修改原变量的值,如果想在子程序内部不对传递进来的参数进行修改,可以在声明部分使用INTENT属性声明,相当于在子程序内容将相应参数修改为const类型,eg:

1
2
3
4
5
6
7
8
9
10
!加法子程序,并改变传递进去的某个变量的值
SUBROUTINE add(a, b, c)
IMPLICIT NONE
REAL :: a
REAL, INTENT(IN) :: b !添加IN发生后b将不能作为左值,且不能被修改
REAL, INTENT(OUT) :: c !添加OUT属性后,c将可以作为左值,且可以被修改
c = a + b
a = 5.0 !调用后原程序对应的变量值将变成5.0,但不能以同样的方式修改b,否则会编译报错
RETURN
END SUBROUTINE add

调用时参数类型必须一致
5.INTENT的所有属性:

  • INTENT(IN) 形参仅用于向子程序传递输入数据
  • INTENT(OUT) 形参仅用于将结果返回给调用程序
  • INTENT(INOUT)/INTENT(IN OUT) 形参即用来向子程序输入数据,也用来将结果返回给调用程序

6.与C中一样,为子程序传递数组时,需要传递数组的大小
7.传递字符变量给子程序时可以使用*声明字符变量的长度,当在子程序内容需要使用到字符串的长度时可以使用LEN()函数来获取字符串长度,声明方式如下:

1
2
SUBROUTINE sample (string)
CHARACTER ( len=* ), INTENT(IN) :: string

模块

8.Fortran可以使用模块来在不同的程序之间共享数据,模块相当于C中的头文件,它可以用来共享数据,同样可以用于共享子程序,声明方式是使用MODULE,引用方法是使用USE module_name。下面例子说明使用其共享数据。eg:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
MODULE shared_data
IMPLICIT NONE
SAVE
INTEGER, PARAMETER :: num_vals = 5
REAL, DIMENSION(num_vals) :: values
END MODULE shared_data

!使用模块
PROGRAM test_module
USE shared_data
IMPLICIT NONE
values = 2
CALL sub
END PROGRAM test_module

!SUBROUTINE
SUBROUTINE sub
USE shared_data
IMPLICIT NONE
WRITE (*,*) values
END SUBROUTINE sub

SAVE语句能够保证在模块中声明的数据被保护在不同的过程间的引用中。
sub子程序中的values将全部为2,因为该变量是与主程序共享的
9.模块中需要定义子程序和函数时必须使用关键字CONTAINS,这些子程序和过程被称作模块过程。eg:

1
2
3
4
5
6
7
8
9
10
11
12
13
MODULE my_subs
IMPLICIT NONE
(Declare shared data here)
CONTAINS
SUBROUTINE sub (a, b, c, k, error)
IMPLICIT NONE
REAL, DIMENSION(3), INTENT(IN) :: a
REAL, INTENT(IN) :: b, c
REAL, INTENT(OUT) :: x
LOGICAL, INTENT(OUT) :: error
...
END SUBROUTINE sub
END MODULE my_subs

函数

1.Fortran函数是这样一个过程:它的结果只能是单个数值、逻辑值、字符串或数组之一。有两种不同类型的函数:内部函数(intrinsic function)和用户自定义的函数(user-defined function,或函数子程序function subprograms)。其中内部函数即是指Fortran自带的SIN(X)、LOG(X)等。
2.自定义Fortran函数的通用格式如下:

1
2
3
4
5
6
7
8
9
[TYPE] FUNCTION name (argument_list)
...
(Declaration section must declare type of name)
...
(Execution section)
...
name = expr
RETURN
END FUNCTION [name]

其中,TYPE表示函数的返回值类型,使用IMPLICIT NONE语句时,必须要指名函数的返回类型,如果有使用IMPLICIT NONE语句,那么函数的返回类型将默认使用Fortran的内置规则。RETURN语句只是表示结束本函数,将执行权限归还给调用函数,所以RETURN并不是必须有。函数的返回值是通过给函数名赋值而实现,所以函数中必须至少有一次让函数名出现在赋值语句的左侧来指定函数的返回值。

2.函数的声明可以采用以下两种等价格式之一:

1
2
3
4
INTEGER FUNCTION my_function(i, j)

FUNCTION my_function(i,j)
INTEGER :: my_function

3.函数在被调用时,也必须在调用函数前面对其进行类型声明,声明方式如下:

1
TYPE :: function_name

4.使用函数计算两个实数之和的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
PROGRAM test_func
IMPLICIT NONE
REAL :: func
REAL :: i = 2, j = 5
WRITE(*,*) func(i,j)
PAUSE
END PROGRAM test_func

REAL FUNCTION func(a,b)
IMPLICIT NONE
REAL, INTENT(IN) :: a, b
func = a + b
END FUNCTION func

5.函数的参数传递过程也是传址传递。
6.过程名相当于也是个指针,包含子程序和函数。所以可以将过程作为参数传递给其他过程,类似C中的函数指针。
7.必须在被调用函数(或子程序)和主程序中使用EXTERNEL关键字来声明的用户自定义函数(或过程)才可以当作调用参数传递。EXTERNEL发生的使用方法与其他属性一样,但也有一个自己的专有格式,如下:

1
2
3
REAL, EXTERNEL :: func_1, func_2
!专有格式
EXTERNEL func_1, func_2

多维数组

1.二维数组的声明方式举例:

1
2
3
4
5
6
7
8
!声明一个由3行6列构成的实数数组,总共有18个元素。第一个下标从1~3,第二个下标是1~6
REAL, DIMENSION(3,6) :: sum

!声明一个101行21列的整数数组,总共2121个元素,第一个下标有效值是0~100,第二个是0~20
INTEGER, DIMENSION(0:100, 0:20) :: hist

!声明一个7行10列的数组,总共70个元素。数组的类型是字符型,每个数组元素包含6个字符。第一个下标从-3到3,第二个1到10
CHARACTER (len=6), DIMENSION(-3:3, 10) :: counts

2.Fortran中的数组存储方式是列优先,与CUDA的网络线程分配是类似的,而C/C++则是以行优先。也就是说Fortran中二给数组的内存在分配时是先为第一列分配内存,然后是第二列…
3.二维数组初始化方式:赋值语句、类型声明语句或是Fortran的READ语句。
4.赋值语句初始化二维数组方式:

1
2
3
4
5
6
7
8
INTEGER, DIMENSION(4,3) :: istat
DO i=1,4
DO j=1,3
istat(i,j) = j
END DO
END DO
!等价于下面使用数组构造器生成赋值的数组
istat = RESHAPE((/1,1,1,1,2,2,2,2,3,3,3,3/), (/4,3/))

内置的RESHAPE函数的使用格式为output = RESHAPE(array1, array2),它会改变一个数组的结构。其中array1包含了要被改变结构的数据,array2是一个描述新结构的一维数组。array2中元素的个数是输出数组的维数,其元素值是每个维度的宽度,且array1中元素个数必须与array2所描述的元素个数相同。
由于数组生成器只能产生一维数组,所以需要使用这种方式。上例中就是将一个一维数据,改变成一个4行3列的二维数组,注意数组存储是列优先。

5.声明时直接初始化数组时初始值必须按列序优先排列,即首先是第一列的4个元素,然后第二列。eg:

1
INTEGER, DIMENSION(4,3) :: istat(4,3) = RESHAPE((/1,1,1,1,2,2,2,2,3,3,3,3/), (/4,3/))

6.用READ语句初始化二维数组。如果在一条READ语句的参数列表中出现了没有下标的数组名,那么程序将会按照数组元素在计算机内存中的逻辑顺序为数组的所有元素赋值。eg:

1
2
3
4
5
6
7
8
9
10
11
!如果文件INITIAL.DAT中含有数据1 1 1 1 2 2 2 2 3 3 3 3
INTEGER, DIMENSION(4,3) :: istat
OPEN(7, FILE='INITIAL.DAT', STATUS='OLD',ACTION='READ')
READ(7,*) istat

!等价于使用嵌套的隐式DO循环实现的例子
!假设INITIAL.DAT中含有数据1 2 3 1 2 3 1 2 3 1 2 3
INTEGER :: i,j
INTEGER, DIMENSION(4,3) :: istat
OPEN(7, FILE='INITIAL.DAT', STATUS='OLD',ACTION='READ')
READ(7,*) ((istat(i,j), j=1,3), i=1,4)

7.二维数组也可以使用下标三元组或下标向量的方式使用部分数组元素。例如a(:,1)表示选用的是数组的第一列,a(1,:)选用数组的第一行,a(1:3, 1:3:5)选用数组的第一到第三行,和第一、三、五列。
8.Fortran最多可支持到7维数组。使用方式与二维一样,分配方式是按列优先。
9.很多函数都支持对整个数组操作,即将一个数组名传递给函数时,相当于对数组中的每一个元素都执行该函数。
10.加掩码的数组赋值:where结构使用方法如下:

1
2
3
4
5
6
7
[name:] WHERE (mask_expr1)
Array Assignment Statement(s) !Block 1
ELSEWHERE (mask_expr2) [name]
Array Assignment Statement(s) !Block 2
ELSEWHERE
Array Assignment Statement(s) !Block 3
END WHERE [name]

这里的每个mask_expr是一个逻辑数组,它和数组执行语句中处理的数组具有同样的结构。该结构使得Block1中的操作或操作集用于mask_expr1为TRUE的所有数组元素上。当mask_expr1为FALSE而mask_expr2为TRUE时,Block2的操作将应用于所有数组元素上,同理操作Block3。Fortran90中不允许有ELSEWHERE子句。例如:

1
2
3
4
5
6
!对数组value中值大于0的元素求对数
WHERE(value > 0.)
logval = LOG(value)
ELSEWHERE
logval = -99999.
END WHERE

11.也可以使用单行WHERE语句:

1
WHERE (mask_expr) Array Assignment Statement

12.Fortran95/2003中FORALL的用法

1
2
3
4
!求nxm数组work中所有元素的倒数  
FORALL(i=1:n, j=1:m, work(i,j)/=0.)
work(i,j) = 1./work(i,j)
END FORALL

FORALL语句中的每个索引都是通过下标三元组的形式的来指定的:subscript_1 : subscript_2 : stride

动态数组

1.动态数组需要在定义是使用ALLOCATABLE属性来说明,然后使用ALLOCATE语句来实际分配内存,使用DEALLOCATE语句来释放分配的内存。例如:

1
2
3
!声明一个100x11的数组,其中第二维下标从0~10
REAL, ALLOCATABLE, DIMENSION(:, :) :: arr
ALLOCATE(arr(100,0:10), STAT=status)

其中STAT=子句是可选的,用于检查返回值状态,如果分配成功,状态为0,如果失败则返回一个基于编译器的正数。
2.可以使用内置函数ALLOCATED()在使用前测试数据是否已经成功分配空间,在没有分配空间之前,对其进行的任何操作都是非法的。用法:

1
2
3
4
5
6
7
REAL, ALLOCATABLE, DIMENSION(:)  :: input_data
...
IF(ALLOCATED(input_data)) THEN
READ(8,*) input_data
ELSE
WRITE(*,*) 'Warning:Array not allocated!'
END IF

3.DEALLOCATE用法:DEALLOCATE(list of arrays to deallocate, STAT=status),例如:

1
DEALLOCATE(arr1, STAT=status) 

派生数据类型-结构体

1.Fortran中的派生数据类型相当于C/C++中的结构体变量,注意只是相当于,因为在其派生数据类型中,只能由基本的内置数据类型或者已定义的用户定义数据类型,但不能包含有函数或子程序,只能用于存放数据。
派生数据类型使用关键字TYPE来定义,定义方式为:

1
2
3
4
TYPE [::] type_name
component definitions
...
END TYPE [type_name]

2.派生数据类型的类型成员通过百分号%来引用,其相当于C/C++中的间接引用运算符->,例如:

1
2
3
4
5
6
7
8
9
10
11
!定义派生数据类型person
TYPE :: person
CHARACTER(len=14) :: first_name
CHARACTER :: middle_initial
CHARACTER(len=14) :: last_name
INTEGER :: age
END TYPE person
!声明类型为person的变量john
TYPE (person) :: john
!将john的age元素设置为28
John%age = 28

其他常见问题

date_and_time函数的使用

DATE_AND_TIME(DATE, TIME, ZONE, VALUES) gets the corresponding date and time information from the real-time system clock. DATE is INTENT(OUT) and has form ccyymmdd. TIME is INTENT(OUT) and has form hhmmss.sss. ZONE is INTENT(OUT) and has form (+-)hhmm, representing the difference with respect to Coordinated Universal Time (UTC).
使用方法是直接使用CALL调用

Fortran90中的内置子程序

一共有5个内置子程序:DATE_AND_TIME, MVBITS,
RANDOM_NUMBER, RANDOM_SEED, and SYSTEM_ CLOCK. These are referenced in the same way as any other subroutine.None of these intrinsic subroutines may be used as actual arguments

  • DATE_AND_TIME: This subroutine returns date and time information in several INTENT (OUT) arguments.
  • MVBITS: This subroutine copies a sequence of bits from one integer data object to another. It is the only elemental intrinsic subroutine.
  • RANDOM_NUMBER: This subroutine returns a pseudorandom number or an array of pseudorandom numbers as the value of its argument. It is a subroutine rather than a function because its execution has the side effect of changing the value of the underlying random number generator seed; intrinsic functions have no side effects.产生一个0~1之间的REAL伪随机数,或者返回给一个数组,基本调用方式为CALL RANDOM_NUMBER(pesounum),pesounu中即为其返回的伪随机数。
  • RANDOM_SEED: This subroutine allows the value of the random number generator seed value to be initialized or retrieved。就是产生一个伪随机数给RANDOM_NUMBER使用,不带参数时的调用方式为RANDOM_SEED()
  • SYSTEM_CLOCK: This subroutine returns data from the processor’s real-time system clock in various formats in several INTENT (OUT) arguments.

Fortran常见函数

Function Value returned
ABS The absolute value of the argument
ACOS The arc cosine of the argument
ASIN The arc sine of the argument
ATAN The arc tangent of the argument
ATAN2 The angle in radians of a complex argument (X,Y)
CEILING The smallest integer greater than or equal to the argument value
COS The cosine of the argument
COSH The hyperbolic cosine of the argument
DIM The difference of two values, if positive, or zero otherwise
DOT_PRODUCT The dot product of two vectors
DPROD The double precision product of two single precision values
EXP The natural exponential function
FLOOR The greatest integer less than or equal to the argument value
LOG The natural logarithm function
LOG10 The logarithm to the base 10
MATMUL Matrix multiplication
MAX The maximum of a set of values
MIN The minimum of a set of values
MOD The remainder function, having the sign of the first argument
MODULO The remainder function, having the sign of the second argument
SIGN Apply a given sign to a given value
SIN The sine of the argument
SINH The hyperbolic sine of the argument
SQRT The square root of the argument
TAN The tangent of the argument
TANH The hyperbolic tangent of the argument
Function Value returned
ADJUSTL Remove leading blanks (and place them on the right)
ADJUSTR Remove trailing blanks (and place them on the left)
INDEX Find the location of a given substring in a character string
LEN_TRIM Length of a string after trailing blanks have been removed
LGE Greater than or equal to comparison based on ASCII
LGT Greater than comparison based on ASCII
LLE Less than or equal to comparison based on ASCII
LLT Less than comparison based on ASCII
REPEAT Concatenate several copies of a character string
SCAN Scan a string for any one of a given set of characters
TRIM The argument with trailing blank characters removed
VERIFY Location of a character in a string that is not one of a given set
BTEST The bit value of a specified position in an integer argument
IAND Logical AND of two integer arguments
IBCLR Clear a specified bit to zero in the integer argument
IBSET Set a specified bit to one in the integer argument
IEOR Logical exclusive-OR of two integer arguments
IOR Logical inclusive-OR of two integer arguments
ISHFT Logical end-off shift of the bits in the argument
ISHFTC Logical circular shift of the bits in the argument
NOT Logical complement of an integer argument

All of these functions, in all three groups, are generic except for LGE, LGT, LLE, and LLT, and all are elemental except DOT_PRODUCT, MATMUL, REPEAT, and TRIM. Note that the bit computation function cannot produce portable results.

参考资源

1.Fortran_95_2003程序设计(第三版),电子版自行查找,注意是那个140多Mb的
2.强烈推荐这个,很好很强大,虽然没有书签,但可以通过搜索快速定位:Fortran 90 Handbook.pdf

Welcome to my other publishing channels