日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【Fortran】过程设计之一(子例程SUBROUTINE)

發(fā)布時間:2023/12/20 编程问答 56 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【Fortran】过程设计之一(子例程SUBROUTINE) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

目錄

    • 前言
    • Fortran子例程(SUBROUTINE)
      • 1) 使用方式
      • 2) 子例程示意
      • 3) INTENT屬性
      • 4) 傳遞數(shù)組給子例程
      • 4) 傳遞可分配數(shù)組給子例程
      • 5) 傳遞字符變量給子例程
      • 6) 子例程作為參數(shù)傳遞
      • 7) 其它注意事項


前言

程序單元包括主程序、子例程、模塊、函數(shù)子程序。

Fortran中,大型程序可以拆分成多個獨立運行和調(diào)試的子任務(wù),即程序單元(亦稱為外部過程)。
Fortran中有兩種外部過程:子例程和函數(shù)子程序。這種機制的優(yōu)點是:

  • 子任務(wù)單獨測試,相互之間不影響;
  • 避免重復(fù)造輪子,調(diào)用即可;
  • 將實現(xiàn)某一功能的代碼封裝起來,避免不經(jīng)意修改導(dǎo)致代碼錯誤而不自知。

Fortran子例程(SUBROUTINE)

1) 使用方式

子例程(亦可稱為子程序)是一個Fortran過程,通過CALL語句進行調(diào)用,并通過參數(shù)表獲取輸入數(shù)值和返回結(jié)果。
定義語句格式:

SUBROUTINE subroutine_name( argument_list_dum ) ! 定義子例程名和相關(guān)參數(shù)表(聲明部分)...(執(zhí)行部分)... RETURN END SUBROUTINE [ subroutine_name ] ! []表示可選

注意事項

  • subroutine_name由字母、數(shù)字和下劃線組成 ,最大長度可達(dá)63個字符,第一個字符為字母;
  • argument_list_dum,形參,一系列變量和/或數(shù)組,從調(diào)用程序傳遞給子例程;
  • 子例程是一個獨立的程序單元,開始于SUBROUTINE,結(jié)束于END SUBROUTINE,其中的局部變量名和語句標(biāo)號(“行號”)可以在其它地方復(fù)用(不用擔(dān)心重名);
  • 實際上沒有給形參分配內(nèi)存。

調(diào)用語句格式:
CALL subroutine_name( argument_list_act )
注意事項

  • 任何可執(zhí)行程序單元都可以調(diào)用子例程,但不能調(diào)用自身(除非定義為遞歸類型);
  • argument_list_act,實參。實參的個數(shù)、順序與類型必須和形參的個數(shù)、順序與類型相匹配。
  • 主程序和子例程之間采用地址傳遞進行參數(shù)傳遞,具體過程是:由于主程序中的實參有具體的內(nèi)存存儲位置,當(dāng)調(diào)用子例程時,主程序?qū)⑸啥鄠€指針來指向各個實參所對應(yīng)的存儲位置,并將指針傳遞給子例程,子例程調(diào)用的是參數(shù)的內(nèi)存位置,而非實參數(shù)據(jù)本身。

2) 子例程示意

已知三角形的兩條直邊,計算斜邊。要求計算過程用子例程,主程序直接輸入相應(yīng)數(shù)據(jù)后直接調(diào)用。

PROGRAM calc_hypotenuse_test ! 主程序 IMPLICIT NONE REAL :: s1 REAL :: s2 REAL :: hypotWRITE(*,*) '測試計算斜邊的子例程' WRITE(*,*)'輸入第一條直邊的長度:' READ(*,*) s1 WRITE(*,*)'輸入第二條直邊的長度:' READ(*,*) s2CALL calc_hypotenuse( s1, s2 , hypot ) ! 調(diào)用子例程WRITE( *, 100 ) hypot 100 FORMAT('斜邊長度為:' , F10.4)STOP END PROGRAM calc_hypotenuse_test SUBROUTINE calc_hypotenuse(side_1 , side_2 , hypotenuse) ! 子例程 IMPLICIT NONE REAL , INTENT(IN)::side_1 ! 第一條直邊長度,輸入,INTENT用法見下述 REAL , INTENT(IN)::side_2 ! 第二條直邊長度,輸入 REAL , INTENT(OUT)::hypotenuse ! 斜邊長度,輸出REAL::temp ! 聲明局部變量 temp = side_1**2 + side_2**2 hypotenuse = SQRT( temp ) END SUBROUTINE calc_hypotenuse

3) INTENT屬性

INTENT屬性在子例程的形參聲明時使用。

INTENT屬性的格式如下:

  • INTENT(IN),形參僅用于向子程序傳遞輸入數(shù)據(jù);
  • INTENT(OUT),形參僅用于將結(jié)果返回給調(diào)用程序;
  • INTENT(INOUT) 或 INTENT(IN OUT),形參既用來向子程序輸入數(shù)據(jù),也用來向調(diào)用程序返回結(jié)果。

屬性特點

  • 對于每一個形參來說,都應(yīng)該聲明一個合適的INTENT屬性;
  • INTENT屬性僅對過程的形參有效,如果用來聲明子例程的局部變量或主程序的變量則會出錯;
  • 對于每一個過程,都應(yīng)該聲明每一個形參的INTENT屬性。形參的INTENT屬性也可以用獨立的語句來聲明,如:INTENT(IN) :: arg1 , arg2,...。

4) 傳遞數(shù)組給子例程

如前所述,調(diào)用參數(shù)實際上是通過傳遞指向該實參的內(nèi)存位置指針來傳遞給子例程。對于實參是一個數(shù)組,其指針是指向數(shù)組中的第一個值。然而,子例程需要同時知道數(shù)組的地址和大小,保證不會發(fā)生越界,才能進行數(shù)組操作。
在子例程中有三種方式來指明形參數(shù)組的大小:

  • 顯式結(jié)構(gòu)形參數(shù)組
    數(shù)組的維度大小需要作為參數(shù)進行傳遞,一維數(shù)組為例:

    SUBROUTINE process(data1 , data2 , n , nvals) INTEGER , INTENT(IN) :: n , nvals ! n為數(shù)組的大小, nvals是數(shù)組操作的個數(shù) REAL , INTENT(IN) , DIMENSION(n)::data1 REAL , INTENT(OUT) , DIMENSION(n)::data2 INTEGER::iDO i = 1 , nvalsdata2( i ) = 3.*data1( i ) ! 將data1數(shù)組的數(shù)值乘以3,賦值為data2數(shù)組 END DOEND SUBROUTINE process

    二維數(shù)組為例:

    SUBROUTINE process1(data1 , data2 , m , n) INTEGER , INTENT(IN) :: m ,n ! m×n為數(shù)組的大小 REAL , INTENT(IN) , DIMENSION(m,n)::data1 REAL , INTENT(OUT) , DIMENSION(m,n)::data2 data2 = 3.*data1 ! 將data1數(shù)組的數(shù)值乘以3,賦值為data2數(shù)組,直接對數(shù)組進行操作END SUBROUTINE process1

    由于形參數(shù)組的大小和結(jié)構(gòu)都已經(jīng)清晰,可以對形參數(shù)組進行數(shù)組操作,以及切片操作。

  • 不定結(jié)構(gòu)形參數(shù)組
    把子例程中的所有形參數(shù)組聲明為不定結(jié)構(gòu)(數(shù)組的每個下標(biāo)用:來代替)的形參數(shù)組,只有當(dāng)子例程具有顯式接口時,才能使用這種數(shù)組。因此,顯示接口能夠給編譯器提供每個數(shù)組的大小、結(jié)構(gòu)等詳細(xì)信息,在調(diào)用的時候不會出錯。

    需注意的是,定義形參數(shù)組時只有它的結(jié)構(gòu)(但用:替代),沒有具體下標(biāo)范圍。因此,在把實參數(shù)組傳遞至形參數(shù)組時,只傳遞了結(jié)構(gòu),并沒有傳遞實參數(shù)組每個維度的下標(biāo)取值范圍。此時,可以用查詢函數(shù)獲取不定結(jié)構(gòu)數(shù)組的結(jié)構(gòu)。

    如果不需要將數(shù)組的每個維度下標(biāo)邊界從調(diào)用程序傳遞給子例程,則不定結(jié)構(gòu)形參數(shù)組比顯式結(jié)構(gòu)形參數(shù)組更方便使用。 二維數(shù)組的例子:

    MODULE module_process CONTAINSSUBROUTINE process2(data1 , data2 )REAL , INTENT(IN) , DIMENSION(:,:)::data1 REAL , INTENT(OUT) , DIMENSION(:,:)::data2 data2 = 3.*data1 ! 將data1數(shù)組的數(shù)值乘以3,賦值為data2數(shù)組,直接對數(shù)組進行操作END SUBROUTINE process2 END MODULE module_process
  • 不定大小形參數(shù)組
    古老且過時的方法,用星號*來聲明形參數(shù)組的長度,表示大小不確定。因此不清楚數(shù)組的實際大小和結(jié)構(gòu),容易運行錯誤,且很難調(diào)試,建議不要使用。例子如下:

    SUBROUTINE process(data1 , data2 , nvals) INTEGER , INTENT(IN) :: nvals ! nvals是數(shù)組操作的個數(shù),因此數(shù)組的數(shù)據(jù)個數(shù)至少要為nvals REAL , INTENT(IN) , DIMENSION(*)::data1 ! 不定大小 REAL , INTENT(OUT) , DIMENSION(*)::data2 ! 不定大小 INTEGER::iDO i = 1 , nvalsdata2( i ) = 3.*data1( i ) ! 將data1數(shù)組的元素乘以3,賦值為data2數(shù)組 END DOEND SUBROUTINE process
  • 4) 傳遞可分配數(shù)組給子例程

    可分配數(shù)組作為參數(shù)傳遞給子例程時,必須要結(jié)合顯式接口。

    注意事項

    • 當(dāng)傳遞的參數(shù)是可分配數(shù)組時,子例程中形參聲明調(diào)用子程序的實參聲明必須都是可分配的;

    • 可分配形參可以使用INTENT屬性,但INTENT屬性的具體參數(shù)可能會影響子例程中的操作:

      • INTENT(IN),在子例程中不允許對輸入可分配數(shù)組進行重分配或者釋放內(nèi)存空間;
      • INTENT(INOUT),調(diào)用子例程時,如果參數(shù)只有數(shù)組這一個,那么實際上會將數(shù)組的狀態(tài)(是否可分配)和相應(yīng)數(shù)據(jù)傳遞至子例程中(實參——>形參),在子例程中可以對形參修改、釋放內(nèi)存、重分配等操作。形參的最終狀態(tài)和數(shù)據(jù)返回至調(diào)用程序中(相應(yīng)實參結(jié)果被修改了)。具體見下例;
      • INTENT(OUT),調(diào)用子例程時,實參在入口處被自動釋放掉,相應(yīng)的數(shù)據(jù)清除掉,可以在子例程中對其進行操作,然后將形參的最終狀態(tài)和數(shù)據(jù)返回至調(diào)用程序中。

    例子
    取自《Fortran for Scientists and Engineers(4th) by Stephen J. Chapman》中的9-5例題,有少量修改,復(fù)制可運行。

    PROGRAM test_allocatable_arguments ! 主程序USE test_module ! 先調(diào)用模塊 IMPLICIT NONEREAL,ALLOCATABLE,DIMENSION(:) :: a_main ! 定義舊版的可分配數(shù)組. INTEGER :: istat ! 分配的狀態(tài)! 指定大小,分配 ALLOCATE( a_main(6), STAT=istat )! 初始化數(shù)組 a_main = [ 1., 2., 3., 4., 5., 6. ]! 輸出調(diào)用前主程序中可分配數(shù)組 WRITE (*,'(A,6F4.1)') ' 調(diào)用子程序前主程序中的數(shù)組:', a_main! 再調(diào)用子例程 CALL test_allocate(a_main)! 輸出調(diào)用后主程序中可分配數(shù)組 WRITE (*,'(A,6F4.1)') '調(diào)用子程序后主程序中的數(shù)組: ', a_main END PROGRAM test_allocatable_arguments MODULE test_module ! 顯式接口CONTAINSSUBROUTINE test_allocate(array) ! 子例程IMPLICIT NONE! 過程中形參變量 REAL,DIMENSION(:),ALLOCATABLE,INTENT(INOUT) :: array ! 作為形參的可分配一維數(shù)組,這是屬于自動分配內(nèi)存的定義! 過程中局部變量INTEGER :: i ! 循環(huán)下標(biāo)INTEGER :: istat ! 分配的狀態(tài)! 判斷數(shù)組的狀態(tài)IF ( ALLOCATED(array) ) THENWRITE (*,'(A)') '子程序分配成功!'WRITE (*,'(A,6F4.1)') '子程序輸入為: ', arrayELSEWRITE (*,*) '子程序沒有被分配'END IF! 釋放可分配數(shù)組的內(nèi)存(因為在聲明部分已經(jīng)分配好了)IF ( ALLOCATED(array) ) THENDEALLOCATE( array, STAT=istat )END IF! 重新分配,按照5個元素的一維數(shù)組ALLOCATE(array(5), STAT=istat )! 往重分配的一維數(shù)組填入數(shù)據(jù)DO i = 1, 5array(i) = 6 - iEND DO! 展示重分配后的數(shù)組結(jié)果WRITE (*,'(A,6F4.1)') '子程序中輸出的數(shù)組 ', arrayEND SUBROUTINE test_allocate END MODULE test_module

    相應(yīng)的結(jié)果為:

    調(diào)用子程序前主程序中的數(shù)組: 1.0 2.0 3.0 4.0 5.0 6.0 子程序分配成功! 子程序輸入為: 1.0 2.0 3.0 4.0 5.0 6.0 子程序中輸出的數(shù)組 5.0 4.0 3.0 2.0 1.0 調(diào)用子程序后主程序中的數(shù)組: 5.0 4.0 3.0 2.0 1.0

    5) 傳遞字符變量給子例程

    當(dāng)一個字符變量被作為子例程的形參時,用*號來聲明字符變量的長度。當(dāng)調(diào)用子例程時,形參的長度將是實參的長度。如:

    SUBROUTINE example( string ) CHARACTER( len = * ) , INTENT(IN) :: string ! *號表示完全復(fù)制實參的長度 WRITE(*,*) 'The lengrh of string : ',LEN(string) ! 可以在子例程內(nèi)部實時返回實參的長度 END SUBROUTINE example

    如自動數(shù)組一般,創(chuàng)建自動字符變量:

    SUBROUTINE sample ( string ) CHARACTER(len=*) :: string CHARACTER(len=len(string)) :: temp ! 一個與形參相同大小的臨時變量,子例程調(diào)用結(jié)束時會被銷毀

    6) 子例程作為參數(shù)傳遞

    當(dāng)子例程a作為實參時,傳遞給過程A(如另一子例程)一個指向該子例程a的指針。執(zhí)行該過程A時,參數(shù)表中的子例程a將作為形參進入到過程A的編譯當(dāng)中。

    要想實現(xiàn)子例程傳遞功能,必須要使用EXTERNAL屬性,將子例程聲明為外部,此時編譯器才會知道參數(shù)表中傳遞的是獨立的已編譯子例程,而不是常規(guī)變量。

    EXTERNAL屬性需要在聲明部分中使用,格式如下:

    TYPE, EXTERNAL ::sub_1 , sub_2 ! TYPE是指具體數(shù)據(jù)類型

    或者

    EXTERNAL ::sub_1 , sub_2

    同時,在過程中需要結(jié)合CALL語句,以調(diào)用過程中子例程形參

    7) 其它注意事項

    • 不要在子例程中使用STOP語句,因為一旦調(diào)用子例程時,會停止程序。如果調(diào)用多個子例程(每個子例程都有STOP語句),則程序永遠(yuǎn)不會執(zhí)行成功;
    • 如果子例程中存在可能引發(fā)錯誤的條件,應(yīng)該對錯誤進行檢測,并設(shè)置正確/錯誤標(biāo)志,返回給調(diào)用程序(即作為形參其中之一),用于實時判斷預(yù)設(shè)條件的執(zhí)行成功與否(即可定義為一種狀態(tài)用于判斷)。

    總結(jié)

    以上是生活随笔為你收集整理的【Fortran】过程设计之一(子例程SUBROUTINE)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。