- 第一章 Fortran 语言程序设计初步
- 第二章 改变程序流程
- 第三章 循环结构
- 第四章 数据结构
- 第五章 数组
- 第六章 过程和模块
- 第七章 输入输出和文件
5.2.2 运算
a) 基本运算
允许把整个数组或数组片段作为一个单独的对象进行运算。例如当数组 A,B,C 有相同大小和形状时,C=A+B 语句实现对数组所有元素的并行加法运算。所有的算术运算符(+,-,*,/,**)、逻辑运算符(如.AND.,.OR.,.NOT.) 和所有关系运算符(如.LT.,.EQ.,.GT.),还有很多内在函数都可以接受数组名称作为参数并对数组元素逐一运算。
例:INTEGER, DIMENSION(100):: even,odd,plu,min,tim,div,squ
even=(/(2*i,i=0,49)/); odd=(/(2*i+1,i=0,49)/)
plu=even+odd
min=even-odd
tim=even*odd
div=even/odd
squ=even**2
可以使用数组名作为参数的内在函数称为基本内在函数。
例:REAL A(5),B(5),C(5)
INTEGER D(5)
DATA PI/3.14159265/
A=(/(REAL(I)*PI/180.,I=1,5)/)
B=COS(A); C=SQRT(A); D=CEILING(A*180.)
其中 COS,SQRT 和 CEILING 都是基本内在函数。当两个以上数组出现在赋值语句或表达式中时,数组的形状应该相同(称为相容)。例如数组 A(2,3),B(2,3),C(2:3,6:8) 都是相容的,而数组 D(4,5),E(5,4),F(5,2,2) 都是不相容的。
例:X(1:10)=X(10:1:-1) !使用三元下标颠倒数组 X
如果数组片段指定的部分相容,则它也可以用于表达式和赋值。这样,不相容的数组也可以互相使用。例如,一个较小的完整数组可以和一个相容的大数组的片段进行运算:
例:REAL A(5),B(4,7)
A=20.; B=5.; A=A-B(2,1:5)
b) 数组与数组
两个数组作算术操作的结果仍是一个形状相同的数组,它的每个位置上元素的值是参与操作的相同位置上一对元素操作后的结果值。例如有数组 A、数组 B,形状如下:
,
则执行赋值语句 C=A+B 后,数组 C 的值即为
。
对于其它内部操作,如+、-、*、/、**等,操作结果也是一个形状相同的数组。它的每个位置上的元素值是参与操作的数组相同位置上的一对元素(不管它们的下标是否相同)作相同操作的结果。
c) 数组与标量
数组表达式允许数组与标量作算术运算。当 A、B 为形状相同的数组时,赋值语句 A=B+2 是合法的。表达式是数组 B 与标量值 2 相加,这时可以把标量看作形状与 B 相同的数组,其每一元素的值都是 2,而后与 B 数组和加,其结果为:
,
也即数组与标量操作相当于数组内每一元素与该标量操作。
d) 数组内在函数
数组表达式中允许对数组求基本函数,其函数值仍是一个形状相同的数组,它的每个位置上的元素值就是被操作数组对应位置元素取该函数值,例如 A、B 为形状相同的一维数组,则语句 B=SQRT(A) 表示:B(1)=SQRT(A(1))、B(2)=SQRT(A(2)),…。
F90 中增加了许多新的数组专用内在函数,使得数组的运算更加灵活方便。下面是一部分新增的数组内在函数。
矩阵乘积函数:MATMUL(A,B)
描述:执行数值或逻辑型矩阵 A 与 B 的矩阵乘法。
说明:矩阵 A 和 B 必须是秩为 1 或 2 的数值型或逻辑型的有值数组,且 A 与 B 的类型必须相同,A,B 中至少有一个秩是 2。A 与 B 的矩阵乘积规则和结果值与数学上的定义相同,A 的最后一维的长度必须和 B 的第一维的长度相同。
向量点乘函数:DOT_PRODUCT(A,B)
描述:执行数值或逻辑型向量 A 与 B 的点积乘法。
说明:向量 A 和 B 必须是秩为 1(即向量) 的数值型或逻辑型的有值数组,且 A 与 B 的类型必须相同。向量 A 与 B 点乘的结果是标量,其规则和结果值与数学上的定义相同。
例:DOT_PRODUCT((/1,2,3/),(/2,3,4/)) 的值为 20。
数组归约函数:包括 SUM、PR0DUCT、MAXVAL、MINVAL、COUNT、ANY 和 ALL 函数。
★ 元素求和函数:SUM(ARRAY[,DIM][,MASK])
描述:沿着维 DIM,对在 MASK 真值中的数组 ARRAY 的所有元素求和。
说明:ARRAY 是被求和的数组名。DIM 用于指明选哪一维来求函数值。当“DIM=1”时分别按列求和,“DIM=2”时分别按行求和。MASK 是屏蔽表达式,不满足条件的元素则被屏蔽,不参加求函数值。
例:SUM((/4,5,6/)) 的值是 15。
例:SUM(C,MASK=C>0.0) 是对 C 的所有正元素值的求和。
例:若,则 SUM(A,DIM=1) 的值是[3,5,7],SUM(A,DIM=2) 的值是[9,6]。
★ 元素连乘求积函数:PRODUCT(ARRAY[,DIM][,MASK])
描述:沿着维 DIM,对在 MASK 真值中的数组 ARRAY 的所有元素求连乘积。
例:PRODUCT((/4,5,6/)) 的值是 120。
例:PRODUCT(C,MASK=C>0.0) 是对 C 的所有正元素值的求连乘积。
例:若,则 PRODUCT(A,DIM=1) 的值是[2,6,12],SUM(A,DIM=2) 的值是[24,6]。
数组查询函数:包括 SIZE、SHAPE、ALLOCATED、LBOUND 和 UBOUND 函数。
★ 求数组大小函数:SIZE(ARRAY[,DIM])
描述:求数组 ARRAY 沿着维 DIM 的长度或数组元素的总数目。
★ 求数组形状函数:SHAPE(ARRAY)。
描述:求数组或标量的形状。
数组的构造函数:包括 MERGE、PACK,UNPACK 和 SPREAD 函数。
描述:数组构造函数用于从已有数组的元素构造出新数组。
★ 合并数组函数:MERGE(TSOURCE,FSOURCE,MASK)
描述:在 MASK 的控制下,合并数组 TSOURCE 和 FSOURCE。
说明:数组 TSOURCE 可以是任一类型,数组 FSOURCE 必须与 TSOURCE 具有相同的类型和类型参数。MASK 必须是逻辑型数组。若 MASK 为真,则结果是 TSOURCE,若为假,则结果是 FSOURCE。
例:MERGE(1.,0.,R<0) 的结果是:当 R=-2,取值为 1.0;当 R=2,取值为 0.0。
例:若,
,
,则 MERGE(A,B,M)=
。
★ 压缩数组函数:PACK(ARRAY,MASK[,VECTOR])
描述:在 MASK 控制下,将数组 ARRAY 压缩成向量数组。
说明:ARRAY 可是任意类型的数组。MASK 必须是逻辑型数组并与 ARRAY 相容。VECTOR(可选) 必须为向量数组,且与 ARRAY 具有相同的类型和类型参数。结果是秩为 1 的数组,其类型和类型参数与 ARRAY 相同;若 VECTOR 存在,结果大小等于 VECTOR 的大小,否则其大小是 MASK 中真元素的个数 t,若 MASK 为标量且为真值,这时结果的大小与 ARRAY 相同。结果的值按数组中元素排序,ARRAY 中的第 i 个元素对应于 MASK 的第 i 个真元素。若 VECTOR 存在,且大小 n>t,则结果中第 i 个元素值为 VECTOR(i),i=t+1,…,n。
例:若,其非 0 元素可由 PACK 函数收集,PACK(A,MASK=A.NE.0) 的结果为[9,7],PACK(A,A.NE.0,VECTOR=(/1,2,3,4,5,6/)) 的结果值为[9,7,3,4,5,6]。
★ 拷贝数组函数:SPREAD(SOURCE,DIM,NCOPIES)
描述:将数组 SOURCE 沿着 DIM 方向拷贝 NCOPIES 次后扩展成一新的数组。
说明:当 DIM=1 时,即沿着第一维下标变化的方向扩展,也即向下扩展。DIM=2 时,沿着第二维下标变化方向扩展即向右扩展。
例:若,片段 A(2,2:4)=[2.2,2.3,2.4],
则 SPREAD(A(2,2:4),1,3) 为,SPREAD(A(1:3,1),2,3) 为
。
例:SPREAD("B",1,4) 为数组(/"B","B","B","B"/)。
数组重构形函数:RESHAPE(SOURCE,SHAPE[,PAD][,ORDER])
数组运算函数:包括 TRANSPOSE、EOSHIFT 和 CSHIFT 三个函数。
★ 矩阵转置函数:TRANSPOSE(MATRIX)
描述:将秩为 2 的数组转置。
例:若 A 是数组,则 TRANSPOSE(A) 为
★ 去端移动函数:EOSHIFT(ARRAY,SHIFT[,BOUNDARY][,DIM])
描述:对秩为 1 的数组表达式作去端移位,或沿着维 DIM 对秩为>1 的数组表达式在所有秩为 1 的完整数组片段上作去端移位。在一个数组片段的一端被移出的元素被丢弃,并在另一端移入相同的 BOUNDARY 的值。不同的片段可以有不同的 BOUNDARY 值,并可在不同的方向上移动不同的位数。SHIFT 为正值去端左移,为负值去端右移。
例:若 A 是数组[2,4,6,8,10],则 EOSHIFT(A,SHIFT=3) 去端左移 3 位的结果是[8,10,0,0,0];而用 EOSHIFT(A,SHIFT=-2,BOUNDARY=36) 去端右移 2 位的结果为[36,36,2,4,6]。
一个秩为 2 的数组的各行可以移动相同或不同数量的元素,边界元素也可以相同或不同。
例:若 B 是数组,
则 EOSHIFT(B,SHIFT=1,BOUNDARY='*',DIM=2) 为,EOSHIFT(B,SHIFT=-1,DIM=1) 为
EOSHIFT(B,SHIFT=(/1,-1,0/),BOUNDARY=(/'*','?','/'/),DIM=2) 为
★ 循环替换函数:CSHIFT(ARRAY,SHIFT[,DIM])
描述:将秩为 1 的数组的所有元素或高维数组的指定维上的元素进行循环移动。在一端上移走的元素被插到另一端。SHIFT=正值时被移向左端,负值移向右端。
例:若 A 是数组[1,2,3,4,5,6],则 CSHIFT(A,SHIFT=2) 是[3,4,5,6,1,2];而用 CSHIFT(A,SHIFT=-2) 是[5,6,1,2,3,4]。
数组定位函数:有 MAXLOC 和 MINLOC 两个函数。
★ 最大值元素定位函数:MAXLOC(ARRAY[,DIM][,MASK])
描述:根据 MASK 的真值条件确定 ARRAY 的所有元素中或沿维 DIM 中第一个最大值元素出现的位置。
例:MAXLOC(/3,8,5,8/) 的值为[2]。
例:若 A 是数组,则 MAXLOC(A,MASK=A.LT.5) 为[1,1],MAXLOC(A,DIM=1) 为[1,2,3,2],MAXLOC(A,DIM=2) 为[1,4,3]。
要注意的是,表达式中数组进行操作后,不再保留原来的下标形式,由系统将它们按线下界为 1 重新排列。这样,参与操作的两个数组原来的下标是否相同,可以不必考虑。但在引用某些与下标有关的函数时.要记住此时的函数值以整理过的新下标值出现。例如定义一个数组 A 及其初值如下:
INTEGER, DIMENSION(0:6),PARAMETER :: A=(/3,7,0,-2,3,6,-1/)
因值 7 是 A 中元素的最大值,元素的下标是 A(1),即数组 A 中最大值元素的下标为 1。但内部函数 MAXLOC 的返回值是 2 而不是 1,即返回的不是原来的下标值,而是以 1 为维下界整理过的下标值。
F90 数组运算内在函数表
函数名称 | 描述 |
ALL(mask[,dim]) | 判断全部数组值在指定维上是否都满足 mask 的条件 |
ANY(mask[,dim]) | 判断是否有数组值在指定维上满足 mask 的条件 |
COUNT(mask[,dim]) | 统计在指定维上满足 mask 的条件的元素个数 |
CSHIFT(array,shift[,dim]) | 进行指定维上的循环替换 |
DOT_PRODUCT(vector_a,vector_b) | 进行两个向量的点乘 |
EOSHIFT(array,shift[,boundary][,dim]) | 在指定维上替换掉数组末端,复制边界值到数组末尾 |
LBOUND(array[,dim]) | 返回指定维上的下界 |
MATMUL(matrix_a,matrix_b) | 进行两个矩阵(二维数组) 的乘积 |
MAXLOC(array[,dim][,mask]) | 返回数组的全部元素或指定维元素当满足 mask 条件的最大值的位置 |
MAXVAL(array[,dim][,mask]) | 返回在指定维上满足 mask 条件的最大值 |
MERGE(tsource,fsource,mask) | 按 mask 条件组合两个数组 |
MINLOC(array[,dim][,mask]) | 返回数组的全部元素或指定维元素当满足 mask 条件的最小值的位置 |
MINVAL(array[,dim][,mask]) | 返回在指定维上满足 mask 条件的最小值 |
PACK(array,mask[,vector]) | 使用 mask 条件把一个数组压缩至 vector 大小的向量 |
PRODUCT(array[,dim][,mask]) | 返回在指定维上满足 mask 条件的元素的乘积 |
RESHAPE(source,shape[,pad][,order]) | 使用顺序 order 和补充 pad 数组元素来改变数组形状 |
SHAPE(source) | 返回数组的形状 |
SIZE(array[,dim]) | 返回数组在指定维上的长度 |
SPREAD(source,dim,ncopies) | 通过增加一维来复制数组 |
SUM(array[,dim][,mask]) | 返回在指定维上满足 mask 条件的元素的和 |
TRANSPOSE(matrix) | 转置二维数组 |
UBOUND(array[,dim]) | 返回指定维上的上界 |
UNPACK(vector,mask,field) | 把向量在 mask 条件下填充 field 的元素解压至数组 |
e) 数组的输入输出
数组的输入输出可以用隐 DO 循环指定每维循环变量,也可单给出数组名、数组元素或数组片段。
一维数组:
一维数组的输入输出比较简单,它在机内存贮时作线性排列,依次读入(输出)的数逐一按下标值递增赋给(打印)各元素:
例:INTEGER :: a(10)
READ *, (a(i), i=1,10) ← 可以 1 行输入 10 个值,也可输入 1 个值(隐 DO 循环)
READ *, a ← 同上 (数组名)
DO i=1,10
READ *,a(i) ← 1 行只能输入 1 个值,输入 2 个以上被忽略
END DO
READ *, a(3),a(4:6) ← 输入数组元素和数组片段:a(3),a(4),a(5),a(6)
PRINT '(10I5)',(a(i),i=1,10) ← 1 行打印 10 个值 (隐 DO 循环)
PRINT '(10I5)',a ← 同上 (数组名)
PRINT '(5I5)',a(1:5) ← 1 行打印 5 个值 (数组片段)
DO i=1,10
PRINT '(I5)',a(i) ← 1 行打印 1 个值,共打 10 行
END DO
二维数组:
二维数组的输入输出读写语句使用与一维情况时一样,数组元素输入输出的顺序是按前面提到的数组的存储顺序来进行的。由于二维数组的顺序是首先按列存放,因此对于输入数组的 A,执行语句 READ *,A 时,则读入数据的顺序是 A(1,1)->A(2,1)->A(3,1) => A(1,2)->A(2,2)->A(3,2) => A(1,3)->A(2,3)->A(3,3)。按列存贮方式与我们数学上按行处理的习惯不一致,在给数组各元素赋值时,先输入第一列元素的值,再输入第二、第三列的值这样机内收到的矩阵才是正确的。
如一定要按行方式输入矩阵值,可以通过交换隐 DO 循环内外层循环变量的方法来实现。如 READ *,A 与 READ *,((A(I,J),I=1,3),J=1,3) 是等价的,交换内外层循环变量后:READ *,((A(J,I),I=1,3),J=1,3) 或 READ *,((A(I,J),J=1,3),I=1,3),这时输入顺序是按行的:A(1,1)->A(1,2)->A(1,3) => A(2,1)->A(2,2)->A(2,3) => A(3,1)->A(3,2)->A(3,3)。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论