fortran 学习记录2

来源:互联网 发布:局域网域名软件 编辑:程序博客网 时间:2024/05/16 11:45
PROGRAM MainIMPLICIT NONEINTEGER Students !学生人数REAL,ALLOCATABLE ::Mark(:)INTEGER IWRITE(*,'(A)',ADVANCE='NO') 'How many students:'READ*,StudentsALLOCATE(Mark(Students))DO I=1,StudentsWRITE(*,"('No.',I5,'''s mark:')",ADVANCE='NO')IREAD*,Mark(I)END DOPRINT*,MarkDEALLOCATE(Mark)!释放内存END PROGRAM


 

这里WRITE函数参数里面I后面要指定宽度,否则出现nonnegative width required in format。比如指定I5

 

 

PROGRAM PointerIMPLICIT NONEINTEGER,POINTER ::p,qINTEGER,TARGET ::n=5INTEGER ::mp=>nq=>pALLOCATE(p)p=4WRITE(6,'(3I9)')p,q,n!I后面数字为宽度!I前面数字为一行输出的数字个数            DEALLOCATE(p)END

 

PROGRAM LowerTriangularIMPLICIT NONETYPE ROWREAL,DIMENSION(:),POINTER ::REND TYPE        INTEGER,PARAMETER ::N=4TYPE(ROW),DIMENSION(N)::TINTEGER IDO I=1,NALLOCATE(T(I)%R(1:I))T(I)%R(1:I)=1END DO DO I=1,NPRINT*,T(I)%R(1:I)END DO      DO I=1,NDEALLOCATE(T(I)%R)END DOEND


%在fortran中是成员操作符



program mainimplicit noneinteger,dimension(10) ::x,y,zinteger ::i,j,kdo 2 i=1,10        x(i)=ido 2 j=1,10        y(i)=j*10do 2 k=1,10        z(k)=k*100+x(i)+y(j)2 continuedo i=1,10        write(*,*)z(i)end doend

以上代码输出结果位210,310,410,510,。。1110

三个do循环共用了label为2的语句相当于三句end do。这里相当于do循环的三重嵌套



fortran定义字符串变量

字符型变量也可以这样定义

CHARACTER*len  C等价于CHARACTER(len) C

len代表字符的长度


CHARACTER*len  C这样的定义方式使人不由得想起C语言中的指针。

program mainimplicit nonecharacter*5 ch1character(5) ch2ch1="fggg"ch2="chinese"write(*,*) ch1write(*,*) ch2!ch2只输出chine,因为定义的字符串长度为5,过长的部分被截断end



F77程序到F90程序的迁移

http://owen.sj.ca.us/~rk/howto/slides/f90model/slides/modcomm.html

Modules can provide an extremely robust alternative to the Fortran 77 COMMON BLOCK

f77中的common block与equivalence语句

f77的common block用modules来代替

Common statement – use modules


在fortran90文件中

不要使用COMMON 公共块:使用Modules 参数列表代替公共块向子程序传递数据;

不要使用EQUIVALENCE 等价语句:Fortran90 中,由于模块、动态存储、指针、数据结构以及固有函数transfer 的引用,没有必要继续使用EQUIVALENCE 语句;



F77的格式,既为F90/95中的固定格式。

(cite fromhttp://micro.ustc.edu.cn/Fortran/ZJDing/Sec1-3.htm)

续行区:第6列
如果在一行的第6列上写一个非空格和非零的字符,则该行作为其上一行的续行。注意在某些系统中,这个字符可以不限于上面所列的,如 @ } ] ~ 等字符均可使用[e_132_01.f]。F77允许一个语句有19个续行(即一个语句最多可以写成20行)。有的程序中第6列上用“l”,“2”,…表示该行是第1个或第2个续行,但用数字字符容易与第7列的数字形成连续的数字串而引起错觉,故最好使用固定的特殊字符



f77中有goto语句,在f90及以上版本时尽量不要使用,goto语句破坏了语句顺序执行的正常情况,不符合结构化规则


fortran运算符

大于: >或者.gt.

大于等于:>= 或者.ge. 

小于:<或者.lt.

小于等于 .le. 或者<=

相等

.eq. 或者==

不相等

.ne. 或者/=

之前以为fortran不能直接像其他编程语言一样直接使用>,<,>=,<=原来是理解错了



fortran循环的控制

可以使用exit跳出循环,如同C语言的break那样

使用cycle,跳过cycle后面的循环中的语句,跳到循环的下一次迭代的执行

比如下例输出1,2,3,5,6

  1 program main  2       implicit none  3       integer ::i  4       do i=1,6  5         if(i .eq. 4)cycle  6         print*,i  7       end do  8 end



fortran如下错误的解决方案

module文件中定义指定大小的数组

A specification expression object must be a dummy argument, a COMMON block object, or an object accessible through host or use association

 An automatic object must not appear in the specification part of a module

实例如下


比如我在module文件中定义了一个

 integer :: size=100
 integer, dimension(size) :: arr

由于编译器编译的时候size的大小是未知的,所以就会报出以上错误,可以将数组大小的变量定义为parameter即可

比如

integer,parameter ::size=100

integer,dimension(size) ::arr

这与C++中其实是一样的



试图将一个kind=4的real类型实参来调用

子程序参数为kind=8的real类型将会出现严重的错误

或者是用形参为integer类型的用real类型的实参都会出现严重错误

总之调用的实参与形参之间类型要完全匹配

与此相反的是,普通的赋值语句之间类型要求并不是那么严

例子如下

下列子程序中输出的a会出现严重错误

直接赋值给y倒是没有出现太大的错误

可以使用real函数进行转换

比如y=real(x,8)


program main  2       implicit none  3       real(kind=4) ::x=0.6  4       real(kind=8) ::y  5       y=x  6       print*,y  7       call func(x)  8 end  9  10 subroutine func(a) 11 implicit none 12 real(kind=8) a 13 print*,a 14 end



fortran如何在指定字节处读取文件


比如要从输入文件中读取单精度浮点(real(kind=4))的数据

需使用文件的直接读取访问,在open的access属性中指定为direct

首先先把文件中模块单元的长度设为4,在open的recl属性中指定,

然后在read语句中指定在哪一个数据段读取,比如要读取第10000个数据,则指定rec=10000.

例子如下(在fortran90下验证通过)

implicit nonereal(kind=4) ::tempinteger ::iinteger ::pos=160*8print*,posopen(14,file='input.dat',access='direct',recl=4,form='unformatted')do i=1,5read(14,rec=pos+i)tempprint*,tempend doclose(14)end


fortran pause语句

pause语句会暂停当前程序的执行,输入enter键后程序会继续执行

看到有的程序写的pause 1

这个1其实就是程序执行pause语句给出的提示,pause 1会输出1的提示字符

如果pause 'warning'则会输出warning字符



有时在引用模块中的变量的时候,可能局部变量与模块中定义的变量之间存在冲突,

这时可以对模块中的变量改名

引用自:http://micro.ustc.edu.cn/Fortran/ZJDing/Sec6-3.htm

模块内的变量改名:
如果需要对多个模块进行访问,而在不同的模块中可能用到了相同的名字,因此允许USE语句对被访问的实体重新命名,以解决局部实体和模块中访问实体之间的名字冲突问题。要重新命名时,USE语句具有下列形式:
USE 模块名 [,改名列表]
其中,改名列表的形式为:局部名1=>块中名1, 局部名2=>块中名2, …。其中,局部名是使用USE语句的程序单元中用的名字,块中名是待改的模块内部使用的变量名。
如模块中定义的变量名是A、B,程序单元中同名变量A、B与之共享,但若要在程序单元中把变量名改为C、D,则只需在单元内把引用语句写成:
USE模块名, C=>A, D=>B
即可,而无需修改模块。


FORTRAN格式编辑符

do i=1,12
print 100,i,i*12
100 format(' ',i3,' *12=',i3)
end do

format
第一个' '代表开始输出时空一格,i3输出print语句的第一个变量,以右对齐的形式占3列,其他类同
   8 *12=  96
   9 *12=108


100 format(1x,i3,2x,i12)
这里x是空格控制符1x为1个空格,2x为2个空格等等

F格式编辑符号
F7.4
意味着总共7位宽度(含小数点),小数点后有4位
这样小数点前至多有两位

When a number is written out, it is
rounded
是四舍五入地写
real ::f=88.88886
print 101,f
101 format(5x,F7.4)
若用f6.4打印88.88886去掉小数点后四位和小数点,小数点前只能打印一位,而小数点前是有2位的,这样会打印出****
提示出错

if we write out 99.99999 in an F7.4 format
the program will
try to write out 100.0000! This is bad news, since we have not left enough room for
all those digits before the decimal point. What happens? Asterisks will be printed

用F7.4打印99,99999四舍五入后是100.0000而F7.4总共只有7位,去掉小数点和小数点前的4位,只能表示两位,因此输出****


real:E格式编辑符号,用于real数据类型

E科学计数法
所有指数格式的数字显示的时候,有效数字在0.1
至0.9999...之间。
E10.4
代表总共有10位,4代表小数点后有效数字为4位
比如1000
以E10.4打印是 0.1000E+04
以E9.4打印是 .1000E+04
以E8.4则无法表示,显示*
因为E+04占据固定的四位

编辑符重复

在格式输出的时候,有事需要重复使用格式编辑符

比如6F8.2

6代表重复的次数,F8.2以为宽度为8,小数点后为2位,输出的6个数都是F8.2格式



fortran77程序向fortran90的迁移

比如下程序do while处原来是个语句标号

比如30,在30之后的有多条语句在若干条件满足的时候有goto 30的语句

此时可以将30语句改为do while(.true.)

然后goto 30语句改为cycle即可

  1 program main  2       integer ::i  3       i =1  4 do while(.true.)  5       i=i+1  6 if(i<5)then  7       print*,'i=',i-  8     cycle  9 end if 10     print*,'ii=',i 11     cycle 12 end do 13 end-




Fortran单精度浮点数(即4字节real)与双精度浮点数(即8字节real)之间的转换

若把4字节real赋值给一个8字节real,或者运算的时候4字节real与8字节real混合运算不会产生问题。也可以用real函数进行转换。

但是如何调用subroutine的时候,把4字节的real赋值给参数中的8字节real或者把8字节的real赋值给4字节的real就会产生重大错误。

因为fortran中subroutine的参数传递是按引用传递(pass by reference)。传递的是参数的地址,所以参数类型不一致时会产生较大错误

以下文字引用自

http://www.stanford.edu/class/me200c/tutorial_77/12_arrays2.html

Fortran subprogram calls are based on call by reference. This means that the calling parameters are not copied to the called subprogram, but rather that the addresses of the parameters (variables) are passed. This saves a lot of memory space when dealing with arrays. No extra storage is needed as the subroutine operates on the same memory locations as the calling (sub-)program. However, you as a programmer have to know about this and take it into account.

program main  3 implicit none  4 real(kind=4) ::a  5 real(kind=8) ::b  6   7       a=0.1  8       b=0.2  9       print*,a,b 10       b=a 11       print*,b 12       a=b 13       print*,a 14       a=b*0.5 15       print*,a 16       b=a*2 17       print*,b 18       b=0.1 19       print*,b 20       a=0.1 21       b=0.2 22  23       call test1(b,a) 24  25 end- 26  27 subroutine test1(a,b) 28 implicit none 29 real(kind=4) ::a 30 real(kind=8) ::b 31 print*,'in sub=','a=',a,'b=',b 32 end subroutine


程序输出

0.1000000      0.200000002980232     
  0.100000001490116     
  0.1000000    
  5.0000001E-02
  0.100000001490116     
  0.100000001490116     
 in sub=a= -1.0842022E-19 b=  5.122630465115234E-315