Movatterモバイル変換


[0]ホーム

URL:


Jump to content
WikibooksThe Free Textbook Project
Search

Fortran/Fortran procedures and functions

From Wikibooks, open books for an open world
<Fortran
Thelatest reviewed version waschecked on4 April 2022. There are2 pending changes awaiting review.
Fortran controlFortran
Fortran procedures and functions
complex types
Wikipedia has related information atFortran.

Functions and Subroutines

[edit |edit source]

In most programs, a block of code is often re-used at several places. In order to minimize duplicating code and facilitate maintaining the code, such blocks of code should be placed within a function or subroutine. A Fortranfunction is similar to a mathematical function, which takes one or many parameters as inputs and returns a single output value. A Fortransubroutine is a block of code that performs some operation on the input variables, and as a result of calling the subroutine, the input variables are modified.

An expression containing a function call:

! func1 is a function defined elsewhere.! It takes an integer as an input and returns another integer as the output.a=func1(b)

A call to a subroutine:

! sub1 is a subroutine defined elsewhere.! sub1 performs some operation on input variables e and f.callsub1(e,f)! Now e or f, or both (or neither) may be modified.

Many programming languages do not distinguish between functions and subroutines (e.g. C/C++, Python, Java). Pure functional programming languages (e.g. Haskell) only allow functions, because subroutines can, in some case, modify input variables as side-effects, which can complicate the code.

Functions are simpler than subroutines. A function must return a single value, and can be invoked from within expressions, like awrite statement, inside an if declarationif (function) then, etc. A subroutine does not return a value, but can return many values via its arguments and can only be used as a stand-alone command (using the keywordcall).

Function

[edit |edit source]

In Fortran, one can use afunction to return a value or an array of values. The following program calls a function to compute the sum of the square and the cube of an integer.

functionfunc(i)result(j)integer,intent(in)::i! inputinteger::j! outputj=i**2+i**3end functionprogrammainimplicit noneinteger::iinteger::funci=3print*,"sum of the square and cube of",i,"is",func(i)end program

Theintent (in) attribute of argumenti means thati cannot be changed inside the function and in contrast, the return valuej has automaticintent (out). Note that the return type offunc needs to be declared. If this is omitted, some compilers will not compile. Open64 will compile the resulting code with warning, but the behavior is ill-defined.

An alternative formulation (F77 compatible) is

FUNCTIONfunc_name(a,b)INTEGER::func_nameINTEGER::aREAL::bfunc_name=(2*a)+bRETURNEND FUNCTIONPROGRAMcowsIMPLICIT NONEINTEGER::func_namePRINT*,func_name(2,1.3)END PROGRAM

The return type of thefunc_name still needs to be declared, as above. The only difference is how the return type offunc_name is referenced withinfunc_name. In this case, the return variable has the same name as the function itself.

Recursion

[edit |edit source]

Recursive functions can be declared , in a way such as the one shown below, in order for the code to compile.

recursive functionfact(i)result(j)integer,intent(in)::iinteger::jif(i==1)thenj=1elsej=i*fact(i-1)end ifend functionfact

Subroutine

[edit |edit source]

Asubroutine can be used to return several values through its arguments. It is invoked with acall statement. Here is an example.

subroutinesquare_cube(i,isquare,icube)integer,intent(in)::i! inputinteger,intent(out)::isquare,icube! outputisquare=i**2icube=i**3end subroutineprogrammainimplicit none    externalsquare_cube! external subroutineinteger::isq,icubcallsquare_cube(4,isq,icub)print*,"i,i^2,i^3=",4,isq,icubend program

Intent

[edit |edit source]

When declaring variables inside functions and subroutines that need to be passed in or out, intent may be added to the declaration. The default is no intent checking - which can allow erroneous coding to be undetected by the compiler.

intent (in) - the value of the dummy argument may be used, but not modified, within the procedure.

intent (out)- the dummy argument may be set and then modified within the procedure, and the values returned to the caller.

intent (inout) - initial values of the dummy argument may be both used and modified within the procedure, and then returned to the caller.

More on Functions vs. Subroutines

[edit |edit source]

Different function result definitions

[edit |edit source]

Functions can define the data type of their result in different forms: either as a separate variable or by the function name.

See the examples below

functionf1(i)result(j)!! result's variable:  separately specified!! result's data type: separately specifiedinteger,intent(in)::iinteger::jj=i+1end functionintegerfunctionf2(i)result(j)!! result's variable:  separately specified!! result's data type: by prefixinteger,intent(in)::ij=i+2end functionintegerfunctionf3(i)!! result's variable:  by function name!! result's data type: by prefixinteger,intent(in)::if3=i+3end functionfunctionf4(i)!! result's variable:  by function name!! result's data type: separately specifiedinteger,intent(in)::iinteger::f4f4=i+4end functionprogrammainimplicit noneinteger::f1,f2,f3,f4print*,'f1(0)',f1(0)! output: 1print*,'f2(0)',f2(0)! output: 2print*,'f3(0)',f3(0)! output: 3print*,'f4(0)',f4(0)! output: 4end program

External

[edit |edit source]

Procedures must be included by moduleuse or by specifying them asexternal procedures.external supplies only animplicit interface which is inferior as the compiler doesn't know the number of arguments and neither their data types. Thus, it cannot yield warnings at compile time (in contrast to an explicit interface given from a moduleuse, c.f.Fortran/OOP in Fortran).

subroutinesquare_cube(i,isquare,icube)integer,intent(in)::i! inputinteger,intent(out)::isquare,icube! outputisquare=i**2icube=i**3end subroutineintegerfunctionpow4(i)integer,intent(in)::ipow4=i**4end functionprogrammainimplicit none    externalsquare_cube! external subroutine (only implicit interface)integer::pow4! external function (only implicit interface)integer::i,isq,icubi=5callsquare_cube(i,isq,icub)print'(A,4I5)',"i,i^2,i^3,i^4=",i,isq,icub,pow4(i)end program

Pure procedures

[edit |edit source]

Both functions and subroutines can modify their input variables. By necessity, subroutines modify input variables, since they do not return any output value. Functions do not have to, but are allowed, by default, to modify input variables. A function can be turned into a pure function, which does not have anyside-effects through the use of theintent attribute on all input variables, and further enforced through the keywordpure. Thepure keyword imposes additional restrictions, which essentially prevents the function from having anyside-effects.

An example of apure function.

purerealfunctionsquare(x)real,intent(in)::xsquare=x*xend functionprogrammainreal::a,b,squarea=2.0b=square(a)! After invoking the square(.) pure function, we can be sure that! besides assigning the output value of square(a) to b,! nothing else has been changed.end program

Keyword arguments

[edit |edit source]

One can use any order of the input arguments if one specifies them by their dummy name. That is possible as long as the calling procedure has an interface block of the intended procedure (which is automatically created if one includes the function bymodule usage uses modules).

There is also a hybrid method where one specifies some parameters by position and the rest by their dummy name.

An example is given

realfunctionadder(a,b,c,d)real,intent(in)::a,b,c,dadder=a+b+c+dend functionprogrammaininterfacerealfunctionadder(a,b,c,d)real,intent(in)::a,b,c,dend function    end interface    print*,adder(d=1.0,b=2.0,c=1.0,a=1.0)! specify each parameter by dummy nameprint*,adder(1.0,d=1.0,b=2.0,c=1.0)! specify some parameters by dummy names, other by positionend program

Optional arguments

[edit |edit source]

Arguments can be setoptional. The intrinsic functionpresent can be used to check if a specific parameter is set.

An example is given below.

realfunctiontester(a)real,intent(in),optional::aif(present(a))thentester=aelsetester=0.0end ifend functionprogrammaininterfacerealfunctiontester(a)real,intent(in),optional::aend function    end interface    print*,"[no args] tester()   :",tester()! yields: 0.0print*,"[   args] tester(1.0):",tester(1.0)! yields: 1.0end program

Interface block

[edit |edit source]

If a procedure has another procedure as dummy argument then one has to specify its type, just as the type of other parameters. An interface block is used for this case. It consists of the procedure statement with the definitions of its arguments.

Note, that each interface block has its own scope. Thus, if one needs to access outside values one needs to explicitly load them. This can be achieved by theimport, oruse statements.

An example is given below.

functiontester(a)real,intent(in)::areal::testertester=2*a+3end functiontesterprogrammaininterface        functiontester(a)real,intent(in)::areal::testerend functiontesterend interface    print*,"tester(1.0):",tester(1.0)! yields: 5.0end programmain

Save attribute

[edit |edit source]

The value of a variable can be saved in-between procedure calls by explicitly giving thesave attribute.

An example is given below.

subroutinef()implicit noneinteger,save::i=0i=i+1print*,"value i:",iendprogrammainimplicit none    interface        subroutinef()integer,save::i=0end    end interface    callf()! yields: 1callf()! yields: 2callf()! yields: 3end programmain

Generic

[edit |edit source]

It is possible to create generic functions with the same name for different input arguments, similar to theabs function which works for integer, real, and complex data types.

The following example illustrates how to create a functionadd which adds either two integers or character strings.

moduleadd_modimplicit none    private    public::addinterfaceaddprocedureadd_int,add_charend interfaceaddcontains    pure functionadd_int(x,y)integer,intent(in)::x,yinteger::add_intadd_int=x+yend functionadd_intpure functionadd_char(x,y)character(len=*),intent(in)::x,ycharacter(len=len(x)+len(y)),allocatable::add_charadd_char=x//yend functionadd_charend moduleadd_modprogrammainuseadd_modimplicit none  print*,"add ints: ",add(1,2)print*,"add chars: ",add("abc","def")end programmain

Deferred

[edit |edit source]

One can set type-bound procedures of an abstract type asdeferred such that it needs to be reimplemented in derived types.For more information see the section onabstract types.

Elemental

[edit |edit source]

One can create procedures that operate parameters of arbitrary dimension. The keywordelemental is used where one defines the operation on a single object (e.g. integer) and the general case is automatically handled.

An example for the addition of arbitrary long integer dimension is given.

pure elemental functionadd_int(x,y)integer,intent(in)::x,yinteger::add_intadd_int=x+yend functionadd_intprogrammainimplicit none    interface        pure elemental functionadd_int(x,y)integer,intent(in)::x,yinteger::add_intend functionadd_intend interface  print*,"add ints:",add_int(1,2)! yields: 3print*,"add arrays:",add_int([1,2],[2,3])! yields: 3   5end programmain
Retrieved from "https://en.wikibooks.org/w/index.php?title=Fortran/Fortran_procedures_and_functions&oldid=4277936"
Category:

[8]ページ先頭

©2009-2025 Movatter.jp