1. 程式人生 > 其它 >Fortran學習筆記:03 陣列(Array)

Fortran學習筆記:03 陣列(Array)

Fortran學習筆記目錄
書接上回:Fortran學習筆記:02 流控制語句

陣列(Array)

定義陣列

一維陣列

program main
    implicit none
    integer :: i
    integer :: a(10)
    do i=1,10,1
        a(i)=i*i;
    end do
    do i=1,10,1
        write(*,*) "i=",i,"i*i=",a(i)
    end do
end

陣列申明格式:

Datatype name(size)

注意,size必須為常數,陣列索引預設從1開始

多維陣列

最多可以宣告7維陣列,宣告格式

integer :: a(D1,D2,D3,...,Dn)	!n維陣列

其他陣列宣告方式

沒有特別賦值的情況下,陣列的預設索引是從1開始的,例如

integer :: a(3) 		!包含a(1),a(2),a(3)

自定義範圍宣告

integer :: a(0:2) 		!一維陣列包含a(0),a(1),a(2)
integer :: b(2:3,-1:1)	!二維陣列b(2~3,-1~1)都可以使用

賦初值

直接賦初值

integer :: a(row,col)=0
program main
    implicit none
    integer ,parameter:: row=10
    integer ,parameter:: col=10
    integer :: a(row,col)=0
    integer :: i,j
    do i=1,row,1
        do j=1,col,1
            write(*,*) a(i,j)
        end do
    end do
end

對陣列的操作

Fortran 95擁有強大的陣列操作方法,簡化許多for迴圈操作

等號賦值

integer :: a(10),b(10)
!!陣列賦值!!
a=10
!等效於
do i=1,10,1
	a(i)=10
end do
!!陣列複製!!
b=a
!等效於
do i=1,10,1
	b(i)=a(i)
end do

矩陣基本運算

\(+,-,*,/\)基本四則運算與Matlab中點乘、點除方法相同,均為陣列對應元素進行四則運算

陣列操作 意義
\(a=b+c\) \(a(i,j)=b(i,j)+c(i,j)\)矩陣對應位置數值相加
\(a=b-c\) \(a(i,j)=b(i,j)-c(i,j)\)
矩陣對應位置數值相減
\(a=b*c\) \(a(i,j)=b(i,j)*c(i,j)\)矩陣對應位置數值相乘
\(a=b/c\) \(a(i,j)=b(i,j)/c(i,j)\)矩陣對應位置數值相除以
program main
    implicit none
    integer ,parameter:: row=10
    integer ,parameter:: col=10
    integer :: a(row,col)
    real :: b(row,col),c(row,col)
    integer :: i,j
    a=10
    b=.5
    c=a*b
    do i=1,row,1
        do j=1,col,1
            write(*,*) c(i,j)
        end do
    end do
end

矩陣切片運算

可以通過對矩陣中部分資料進行賦值操作,Matlab中矩陣切片方式繼承了Fortran語言這一形式。

a(3,5)=5			!a(3),a(4),a(5)數值設定為5
a(3:)=5				!a(3)之後的數值設定為5
a(3:5)=(/3,4,5/)	!a(3),a(4),a(5)數值分別設為3,4,5
a(1:3)=b(4:6)		!a,b賦值
a(1:5:2)=3			!a(1),a(3),a(5)賦值為3,1~5增量為2
a(1:10)=a(10:1:-1)	!翻轉a

integer :: a(5),b(5,5)
a(:)=b(:,2)			!b中第二列賦值給a

integer :: a(5,5),b(5,5,5)
a(:,:)=b(:,:,1)

注意在進行陣列操作時,需要保證兩邊陣列數目一致

WHERE 語句

where是Fortran95新增的功能,可以通過邏輯判斷,對陣列部分元素進行操作。例如以下例子,可以將a中<3的陣列元素賦值給b

program main
    implicit none
    integer :: i
    integer :: a(5)=(/(i,i=1,5)/)
    integer :: b(5)=0
    where(a<3)
        b=a
    end where
    write(*,*) "a=",a
    write(*,*) "b=",b
    stop
end
 !輸出
 a=           1           2           3           4           5
 b=           1           2           0           0           0

where也可以作巢狀,elsewhere(邏輯判斷)

program main
    implicit none
    integer :: i
    integer :: a(5)=(/(i,i=1,5)/)
    integer :: b(5)=0
    where(a<3)
        b=1
    elsewhere(a>4)
        b=2
        elsewhere
            b=3
    end where
    write(*,*) "a=",a
    write(*,*) "b=",b
end
 !輸出
 a=           1           2           3           4           5
 b=           1           1           3           3           2

FORALL語句

forall是Fortran95中新增的功能

program main
    implicit none
    integer :: i
    integer :: a(5)=0

    forall(i=1:5:2)		!1~5,增量為2
        a(i)=5
    end forall
    write(*,*) "a=",a

    forall(i=1:5)
        a(i)=i
    end forall
    write(*,*) "a=",a
    stop
end
 !輸出
 a=           5           0           5           0           5
 a=           1           2           3           4           5

對於二維陣列,有相同的操作

program main
    implicit none
    integer :: i,j
    integer :: a(5,5)=0

    forall(i=1:5:1,j=1:5:1)
        a(i,j)=i+j
    end forall
    
    do i=1,5,1
        write(*,*) a(:,i)
    end do
    stop
end
!輸出
           2           3           4           5           6
           3           4           5           6           7
           4           5           6           7           8
           5           6           7           8           9
           6           7           8           9          10

還可以在forall中新增條件判斷,語法為

forall(索引1,索引2,邏輯判斷)
program main
    implicit none
    integer :: i,j
    integer,parameter :: N = 5
    integer :: a(N,N)=0
    
    forall(i=1:N,j=1:N,i>j)  a(i,j)=1	!上三角
    forall(i=1:N,j=1:N,i==j) a(i,j)=2	!對角線
    forall(i=1:N,j=1:N,i<j)  a(i,j)=3	!下三角
    
    write(*,"(5(5I5,/))") a
    stop
end
!輸出
    2    1    1    1    1
    3    2    1    1    1
    3    3    2    1    1
    3    3    3    2    1
    3    3    3    3    2

forall可以巢狀多層,forall中可以使用where,但是where中不能使用forall,例如

program main
    implicit none
    integer :: i,j
    integer,parameter :: N = 5
    integer :: a(N,N)=0

    forall(i=1:N)
        forall(j=1:N)
            a(i,j)=i+j
        end forall
    end forall
    write(*,"(5(5I5,/))") a
    
    forall(i=1:N)
        where(a(i,:)/=6)
            a(i,:)=0
        end where
    end forall
    write(*,"(5(5I5,/))") a
    stop
end
!輸出
    2    3    4    5    6
    3    4    5    6    7
    4    5    6    7    8
    5    6    7    8    9
    6    7    8    9   10

    0    0    0    0    6
    0    0    0    6    0
    0    0    6    0    0
    0    6    0    0    0
    6    0    0    0    0

陣列的儲存規則

可變大小的陣列

利用allocate與deallocate分配與釋放記憶體

program main
    implicit none
    integer :: students
    integer,allocatable :: a(:)
    integer :: i

    write(*,*) "How many students:"
    read(*,*) students
    allocate(a(students))   !分配記憶體

    write(*,*) "size of array = ",size(a)
    deallocate(a)           !釋放記憶體
    stop
end

測試程式(測試當前計算機所能分配的最大記憶體)

program main
    implicit none
    integer :: size_N=0,error=0
    integer,parameter :: one_mb=1024*1024
    character,allocatable :: a(:)

    do while(.true.)
        size_N=size_N+one_mb
        allocate(a(size_N),stat=error)    !分配記憶體
        if(error/=0) then
            exit
        end if
        write(*,"('Allocate ',I10,'bytes')") size_N
        write(*,"(F10.2,'MB used')") real(size_N)/one_mb
        deallocate(a)                   !釋放記憶體
    end do
    
    stop
end

陣列應用例項

氣泡排序

program main
    implicit none
    integer :: a(5)=(/10,2,5,4,6/)
    integer :: i,j,temp
    write(*,"(5(I5))") a
    do i=1,5
        do j=i+1,5
            if(a(i)>a(j)) then
                temp=a(i)
                a(i)=a(j)
                a(j)=temp
            end if
        end do
    end do
    write(*,"(5(I5))") a
    stop
end program
!輸出
   10    2    5    4    6
    2    4    5    6   10