layout: post title: 【转】Fortran数组学习 categories:
原文: 第五章: 数组 数组类型与定义
两种变量:标量+数组. 标量维数为0, 数组维数>=1.
类型相同的一组标量数据的有序集合
数组元素类型必须相同, 这些元素按某种确定方式排列
数组的维数
例
A(10,3,2)
的维数为3, 维长分别为10、3、2, 大小为10×3×2=60, 形状为10乘3乘2, 或表示成(10,3,2), shape(A)的结果是一维数组, 其元素为10, 3, 2. B(2,2,0)
的第三维维长为0, 因而大小为0, 不能用于存储任何数据. C(2, 0:9, -3:-1, int(-sqrt(45./3.)):int(5/2))
为4维数组, 大小为2×10×3×6. 声明时数组的维数必须指定的, 大小和形状是否需要指定视数组的形式而定
real A(10,2,3)
类型说明dimension A(10,2,3)
dimension语句allocatable B(:,:)
allocatable语句pointer C(:,:,:)
pointer语句real, dimension(2,5):: D
类型说明中的dimension属性real, allocatable:: E(:,:,:)
类型说明中的allocatable属性real, pointer:: F(:,:)
类型说明中的pointer属性数组片段:数组中若干元素, 不需连续或遵循某个规则, 指定部分下标列表, 本身也是数组
引用时数组的下标必须用逗号隔开
例
real A(3,3), B(3,3), C(89), R
B(2,2)=4.5; R=7.O; C(int(R)*2+1)=2.O
!给元素B(2,2)和C(15)赋值A(1,2)=B(int(C(15)), int(sqrt(R)))
!元素A(1,2)和元素B(2,2)的值相同real A(2,3,4)
, 则A(1,2,3)是数组元素, 而A(1:2,2,2),A(1,1,4:2:-1),A(1,2:3,(/2,4/))
都是数组片段数组的下标列表有两种:三元下标和向量下标.
三元下标[下界]:[上界][:步长]
用三个值分别代表数组片段的下界, 上界和步长, 以上升或下降的顺序指定数组元素.
例
real A(10)
A(1:5:2)=3.0
!把元素A(1), A(3), A(5)置为3.0A(:5:2)=3.O
!把元素A(1), A(3), A(5)置为3.0, 因为缺省下界为1A(2::3)=3.O
!把元素A(2), A(5), A(8)置为3.0, 因为上界缺省值为10A(7:9)=3.0
!把元素A(7), A(8), A(9)置为3.0, 因为缺省步长为1A(:)=3.0
!和A=3.0
相同, 将A的所有元素置为3.0real B(10)
B(9:2:-2)
是由元素B(9), B(7), B(5)和B(3)组成的数组. B(3:15:6)
是由B(3)和B(9)组成的数组. real A(5,9)
则A(1:4:3,6:8:2)=3.0
等价于 A(1,6)=3.0; A(1,8)=3.0; A(4,6)=3.0; A(4,8)=3.0
向量下标
利用一个一维整数数组(即向量)来指定数组元素
例
real A(10), B(5,5)
integer I(4), J(3)
I=(/5,3,8,2/)
!定义向量IJ=(/3,1,5/)
!定义向量JA(I)=3.O
!设置元素A(5), A(3), A(8), A(2)的值B(2,J)=3.O
!设置元素B(2,3), B(2,1)和B(2,5)的值integer :: a(4)=(/0,1,2,3/), b(3)=(/1,4,3/)
, 则a(b)与a同类型, 与b同形状, 取值为(/0,3,2/).character(1):: symbol(0:1)=(/'F','M'/)
integer:: bit(100)
若bit的元素列为0001101100111..., 则symbol(bit)是用{F,M}字符构成的100字节的字符型数组FFFMMFMMFFMMM.... real A(3,3), B(4)
integer K(4)
K=(/3,1,1,2/)
!K矢量有重复值A=5.0
!设置A的所有元素B=A(3,K)
!数组片段B由下列元素组成:A(3,3),A(3,1),A(3,1),A(3,2)显式形状(Explicit-shape)数组:指定了维数和每一维的维长, 维下界是可省略, Array([维下界:]维上界[,[维下界:]维上界]…)
例:integer M(10,10,10), K(-3:6,4:13,0:9)
自动(Automatic)数组
过程中其后的变量或表达式值的变化不会对数组的上下界产生影响.
例
<pre class="line-numbers" data-start="0"><code class="language-fortran"># Language: fortran subroutine example(N,R1,R2) dimension A(N,5), B(10*N) …… N=IFIX(R1)+IFIX(R2) …… end </code></pre>此例中的A和B都是自动数组. 子程序被调用时, 数组A和B的上界通过传入的变量N来确定, 而以后N的值的变化对A和B的大小不会有影响.
例
<pre class="line-numbers" data-start="0"><code class="language-fortran"># Language: fortran subroutine sub1(M, N) integer M, N, lower common/bound/lower …… integer auto_array1(N) integer auto_array2(lower:N) integer auto_array3(20,N*M/2) …… end subroutine </code></pre>可调(Adjustable)数组
注意多维可调数组的维界表达式必须与调用时的维界相符.
例
<pre class="line-numbers" data-start="0"><code class="language-fortran"># Language: fortran dimension A1(10,35), A2(3,56) …… sum1=the_sum(A1, 10, 35) sum2=the_sum(A2, 3, 56) end function the_sum(A, M, N) dimension A(M, N) sumx=0.0 do j=1,N do i=1,m sumx=sumx+A(i,j) end do end do the_sum=sumx end function </code></pre>其中哑元M,N控制着可调数组的大小.
例
<pre class="line-numbers" data-start="0"><code class="language-fortran"># Language: fortran dimension Array(9,5) L=9 M=5 call sub(Array,L,M) end subroutine sub(X,i,j) dimension X(-i/2:i/2,j) X(i/2,j)=999 j=1 i=2 end </code></pre>可调数组的维界X(-4:4,5)在调用过程时被确定后, 过程内部对维界参数的赋值不会改变维界值.
假定形状(Assumed-shape)数组
注意它与可调数组的区别在于,可调数组属于显型数组(必须指定上界)的范围, 而假定形状数组的上界是不能指定的.
例
<pre class="line-numbers" data-start="0"><code class="language-fortran"># Language: fortran subroutine assumed(a) real a(:,:,:) end </code></pre>此时数组a的秩为3, 但每一维的长度待定. 当过程被调用时a将从传递到过程的数组获得形状
real x(4,7,9)
call assumed(x)
于是a获得了数组维界(4,7,9), 实际数组和假定形状数组的值必须相同.
如果上面过程中数组声明了a(3:,0:,-2:), 以哑元x(4,7,9)调用过程时, 数组a的实际维界是a(3:6,0:6,-2:6).
应用假定形状数组为哑元的过程时必须有显式的接口INTERFACE语句.
例
<pre class="line-numbers" data-start="0"><code class="language-fortran"># Language: fortran interface subroutine sub(m) integer m(:,1:,5:) end subroutine end interface integer L(20,5:25,10) call sub(L) </code></pre>在此例中数组M的维界是(1:20,1:21,5:14).
假定大小(Assumed-size)数组
声明一个假定大小数组时, 最后一个的上界用星号表示. 它的一般形式是:([显型维界,][显型维界,]...[下界:]).
例
<pre class="line-numbers" data-start="0"><code class="language-fortran"># Language: fortran subroutine assume(a) real a(2,2,*) end </code></pre>假定大小数组的秩和形状可以和实际传入的数组不同, 传入的数组只确定它的大小. 实际数组的元素按列传递给假定大小数组, 假定大小数组也按列接收. 接受的过程中假定大小数组的最后一维的长度会改变来接受所有传递进来的数组元素, 于是最终给出数组的大小. 如上例子中的assume子程序, 如果以数组x为哑元来调用的话,
real x(7)
call assume(x)
则数组X的元素与数组A的对应顺序是:
X(1):A(1,1,1)
X(2):A(2,1,1)
X(3):A(1,2,1)
X(4):A(2,2,1)
X(5):A(1,1,2)
X(6):A(2,1,2)
X(7):A(1,2,2)
其中数组A的最后一维没有必要成为完整的维, 所以数组A始终没有确定的形状. 因为假定大小数组没有形状, 所以这样的数组不能仅仅通过名称来向其它过程传递.
假定大小数组可以分解成确定的数组片段. 如上例中的数组A, 可分为三个片段:A(1:2,1:2,1)和A(1:2,1,2)以及A(1,2,2).
假定大小数组的秩是完全确定的维数+1. 上例中数组A的秩为3, 尽管A的第三维不是完整的.
延迟形状(Deferred-shape)数组
用来声明可分配数组, 维数由冒号确定, 但维长只有在分配数组才被确定.
例
real, allocatable:: A(:,:,:)
integer, allocatable, target:: K(:)
可分配数组可由下列方式声明:使用allocatable语句、dimension语句、target语句或在类型声明中使用allocatable属性. 如果迟形数组以dimension语句或target语句声明, 则在其它语句中必须给出allocatable属性.
在迟形数组的大小、形状和维界没有确定之前, 其任何部分都不能被引用, 可分配数组的大小、形状和维界在allocate语句执行时才被确定.
例
integer,allocatable:: A(:,:)
real,allocatable,target:: B(:,:), C(:)
allocate(A(2,3), C(5), B(size(C),12))