Fortran学习(2)-基本规则

简单规则

建议使用自有格式编码(free-format). 注释使用“!”开始。
但是老的程序,可能由固定格式与自由模式转换。
程序单元尽可能彼此独立,重复利用率
程序单元间的变量,一般是不相通的。

语句大致分三类:
1 声明语句,只在编译时运行。
2 执行语句
3 结构语句

声明都先写:Implicit None
1 一个项目开始 program name, 结束:end progarm.
2 大小写不区分,如 A , a 是一样的
3 ! 注释符号,;&代码换行, /:跳到下一行
4 变量不能以数字开头
5 最好都写: implicit none, 即不使用默认的数据类型
6 各个数据类型表示:
implicit none
integer::number=5, data, i=0, j !整型,kind可以改变其最大值与最新值,1,2,4,8
real::value,x,y,pi=3.1415 !浮点.kind=4(单精度,38位数), 8(双精度), 16(四精度)
character (4) :: file='test.data' !字符 Kind=1, ASCII编码
logical::end. file = .false. !逻辑型
complex(kind=??):: !复数型(两个浮点型的组合)
type(??):: !派生型(上述类型的组合)
属性: 形容词来赋予,
如: Real, Parameter::PI=3.1415 !常数
Kind 种别,来区分同一种数据类型,但不同长度或精度或编码方式,在编译时决定。 常数也有kind值; Selected_Int_Kind(), or Selected_Real_Kind(r,p)(10^r为最大值,p为有效数), 可以给出不同编辑器的使用kind值

转换

read(字符串,) 整型或实型变量。 字符串 => 数字
write(字符串,
) 整型或实型变量。 数字 => 字符串

7 Arrays (数组)
integer::x(5,50) 5行50列的整数数组
character(5)::x(25) 25个元素的符号向量,每个元素5个字符长度
real::c(3,4,5) 60个元素(3x4x5)的3-D数组
默认生成的数组元素都为1
8 设置常量
integer, parameter::n=5, m=20
real, parameter::pi=3.1415
real::x(n,m). ! 提前设置x矩阵的为n行,m列

9 字符串,有利于实现批量处理
10 浮点数需注意:
(1)对浮点数进行相等判断,应写: if( abs(a-1.3)<1.0e-5 )
(2)不要以浮点数作为数组的角标, 应:b=a(2)
(3)不要用其作为循环变量,应 Do i = 0, 20
r = i/10.0

运算

+, - , * , / : 分别表示加减乘除; 但是整数和实数不能相互转化
** : 表示次方,如2**3, 表示2的3次方
注意区分: 整数与实数不能直接进行运算
整数除以整数,结果是整数,eg: 1/2=0
整数除以浮点数,结果是浮点数,eg: 1/2.0=0.5

矩阵
1 矩阵*常数 = 矩阵中每个元素分别乘以常数
2 matmul(z,y) ! 矩阵z, y相乘
3 v=z(1:100:5) !间隔为5,
4 x = transpose(y) !x=y'
5 dot_product(v,w) !v'w
6 a=maxval(x) ! x中的最大值
7 k=sum(y, mask=y>2.5) !大于2.5的元素求和
8 k=sum(y, dim=1) !按行求和

结构语句

if

if (condition1) then
.... !执行命令
elseif (condition2)
... !执行命令
elseif (condition3)
... !执行命令
else
...
endif

condition 中可以使用 < , <=, ==(.eq. 相等), >=, > , /=(.ne. 不等)
.and. , .not. , .or.
比较数组是,使用any 或者all

select case

select case (keywrod)
          case (A)
                        ....
           case (B)
                .....
            case default
                ....
end select

do loop

do i=1,n,2 !从1到n继续间隔为2的循环运行
    ...  !执行命令
enddo
do while ()
   ....
end do

隐式循环

a = [(i,i=1,10)]
相当于:
do i = 1,10
      a(i) = i
end do

署名的do循环

outer: do i=1, 10
      inner: do j=1,20
          ....
          ...
      end do inner
end do outer

循环控制:Cycle, exit

do
...
if (expression) then
cycle
else
exit
end if
end do
cycle:表示忽略本轮循环剩余内容,直接进入下一轮循环
exit:(用于循环时)忽略循环剩余内容,跳出(指定)循环。
用其循环和退出特定署名的循环

outer: do i=1,10
      inner: do j=1,20
         if (condition A) then
             cycle outer
          else if (condition B) then
              exit outer
          end if
      end do inner
end do outer

聚合数据

常见:
枚举(parameter),
数组(dimension),只存在一类
结构体(type), 可以多类
类(class, type derived),面向对象的扩展,数据的组装

数组

高频使用,是Fortran数值计算的最重要元素
分类:1 固定大小数组:(1)静态数组(声明)(2)自动数组(传参)
2 动态分布数组:allocate分布...deallocate结束

定义: type, dimension(bound) [,attr]::name #较多固定数组大小
type [,attr]::name(bound) # 少量数组相同大小
访问方式: 整体(数组),元素,片段,不连续段
使用的函数: SQRT(num) 求方根,单独求取
整体求

结构体

定义: type[[],attr-list::] name
...
end type name

访问方式: type%mem
在数值计算以外的扩展,

在结构体基础上,向面向对象拓展

常用函数

狭义(数学上)的函数:
Fortain 也有一些提前自己定义的函数
int() - 直接截取为整数
nint - 四舍五入为整数
max, min, sqrt, sin, cos, tan, exp, log, log10, abs, mode,
len: 符号的长度

广义:引导程序执行流程的重要方式(指function,subroutine,module)
使用函数优点:

  1. 将长过程拆分成多个小的过程,分别实现,有利于代码的逻辑结构
  2. 封装,类似包
  3. 一次书写,多次调用
  4. 函数内部与调用者是隔离的,不能直接使用调用者的变量
  5. 函数的局部变量在函数返回后丢失,下次进入时他们的值不确定

缺点:牺牲一小部分的效率

function ,subroutine和module

function

function trace_f(x,n) result(t)
         integer::n,i
         real::x(n,n), t
          .....
end

调用: result = trace_f(x,n)

subroutine

subroutine trace_sub(t,x,n)
         integer::n,i
         real::x(n,n), t
          .....
end
调用: call trace_sub(t,x,n)

function 的变量只能读入,result输出; subrountine的变量可以读入和输出
function和 subrountine都对内部变量都不会每次都初始化,如调运运行一次后,下一次变量值就会改变。需要使用使用save来固定初始值,
如: integer, save::count=0 !这样每次count都为0

虚参:子程序指定 subroutine( x, y)
实参: 调用者指定 call subrountine(5,6)
一般按顺序结合,
传递参数的方式两种: 传地址(高效,可回传,节省内存), 和传值(先复制一份再修改,不可回传,速度慢,浪费内存,但是安全)
Fortran默认使用的是传地址。
实参和虚参的数据类型,Kind值,数组的维度,尽量保持一致。
把能够交给外部配置的信息,都定义为虚参,提高子程序重复利用。

传递数组

数组,包含元素,维度,每个维度的上下限,大小信息。
1 自动数组
subroutine sub(a,m,n)
Integer m, n
Real a(m, n)
a = 2
End Subroutine sub ! 只传地址,维度设置成了参数,可以自己定义,这样参数较多

2 假定大小
Subroutine sub (a)
Real a(*)
a(1:6) = 1
End subroutine sub !只传递地址,虚参只能是1维,下限为1,不传递上限,容易越界

3 假设性状
subroutine sub (a)
real a(:,:)
a =1
end subroutine sub ! 传递地址,各维度大小,下限可自动,需要interface

第3类,是被推荐使用。

特殊用法

1 变量的save属性:局部变量具有临时性,使用save,可以让其保持上一次的值,
eg: Integer, save :: var, 或者Interg ::var=0

2 虚参的Intent属性(需要Interface):明确指定虚参的目的:输入参数,输出参数,中性参数,
!输入参数,在子程序内部不许改变
Integer, Intent(IN)::input_arg
!输出参数,子程序返回前必须改变,所以不能是常数,也不能是表达式
Integer, Intent(OUT) :: output_arg
!中性参数
Integer, Intent(INOUT):: neuter_arge

Integer::neuter_arg !未定Intent为中性

请注意:Intent的检查是在编译时进行,而非运行时检查,这样可以在变编程时,发现问题。
建议:对每一个虚参都指定Intent属性

3 可选参数,运行时,动态决定参数的个数: Open语句,
Integer, optional::c

4更改参数的顺序:即实参和虚参顺序不一定对应。
eg: call writeresult(Data=var, file="res.txt", size=1000) !指定虚参名称=

5 函数名作为参数:实参与虚参都是函数名,让子程序本身以另外的子程序做参数。 可以用interface定义。

6 result 后缀:旨在通过对返回值重命名以便于理解或书写,
eg: Type (ST_d) Function Rdegree_to_typedegree (rr) result (stt)

7 递归子程序:自己调用自己的子程序,在特殊循环或迭代非常有效, 需要在最前面加Recursive
能不用链表,尽量别用
一定控制终止条件,
尽量少量使用局部变量
8 一进多出递归,往往与链表结合使用, 例如著名的二叉树, 如操作系统的树形文件夹结构。

module

module trace_m
         integer::n,i
         real::x(n,n), t
          .....
end module
Program main
  use trace_m  !可以直接使用内部定义的任何功能函数
     ....
end

当module有subroutine时, 需要将其与主程序连接
注意: module可能更方便封装函数和使用

读入和写出

read()读入
write() 输出
通用:print, 'value of a , b, and c are ', a, b, c
也可对输出的进行格式设定:
print '(5x, "value of i, x = "), i4, 2x,f6.2, f6.2)', i, x
i4: 4个整数的长度
a5: 5个字符的长度
f6.2: 总长度为6
在输出中,小数点后2位数,
5x: 在输出中, 5个空格
在读入中, 跳过5个字符
读入一个文件:
open(2, file='/home/data.csv') !需要一个整数来关联读入的文件
read
,a,b
隐式循环
read, ((y(i,j),j=1,m), j=1,n) #按行读取
read
, ((y(i,j),j=1,n), i=1,m) #按列读取
这对数组非常有用:
real::x(n,n),d(n)
integer::cont(100)
!
d=(/(x(i,i),i=1,n)/) ! d为x的对角线数据
cont=(/(i,i=1,100)/) !cont为1 2 3 4 ... 100

注意: 无论是否已读取所有字符(一行),一条read语句通常只读取一行! 因此,下一条读取语句无法读取上一条已跳过的字符

每次I/O格式完成计算后,都需要使字符格式转换二进制,二进制节省空间。
但是不同的电脑和编译器得到的二进制格式不同,所以不同的环境生成的二进制可能不同。
读数据可能需要格式:
character (20)::ff
write(ff, ' (i2) ' ) i
ff = ' ( ' // ff // ' f10.2) ' ! 如果i = 5, ff='( 5f10.2)'

编译器

具有:f90 , ifort 等
eg: ifort -parallel -o mtc mtc1.f mtc2.f second.f ! 编译后三个代码,生成mtc软件

矩阵

real::x(2), y(1000), g(3,3)
x=(/13.5, 2.7/) !x为(13.5与2.7)
y=(/ (i/10.0, i=1,1000) /) ! y为[0.1 0.2 ... 100]
real::dimension(n,m)::x,y,z !x,y,z都为[n,m]大小的矩阵
real,allocatable::a(:,:) !生成2维可分配数组
allocated (a(n,m)) !a为[n,m]的可分配数值
指针数组:
real,poniter::a(:,:),b(:,:) !a,b为2维数组
数据的元素也能加入指向,并且进行初始化:
type spare_matrix
integer::n=0
integer,pointer::row(:)=>null(), col(:)=>null()
real,pointer::val(:)=>null()
end type

新程序的组织-internal functions/subroutines and modules

前面描述的Functions and subroutines是单独的程序单元。 它们可以与主程序分开编译并放入库中。 但是,由于不进行参数检查,因此容易出错,例如,在编译过程中可能会以错误的数量或类型的参数调用子例程而没有任何警告。
Fortran 90为程序放置提供了两种新的可能性:内部子程序和内部模块。
eg:
常规的程序如下:

program test
      call sub1(x,y)
      z=fun(h,k)
end program

subroutine sub1(a,b)
    ....
end subroutine

function fun(i,j)
    ....
end function

但是改成为: 内部子程序使用方法:

program test2
     call sub(x,y)
     z=fun(h,k)
         contains  !表明插入
         subroutine sub(a,b)
               ....
          end subroutine
         function fun(i,j)
             .....
         end function
end program

其中主程序可以使用所以的变量(同样子程序内可以使用主程序定义的变量),并不是library的一部分。

使用内部modules

module mm2
      contains
      subroutine sub(a,b)
          .....
      end subroutine
      function fun(i,j)
            ....
      end function
end module

program test3  !主程序
      use mm2
     call sub(x,y)
     z=fun(h,k0
end program


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,284评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,115评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,614评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,671评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,699评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,562评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,309评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,223评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,668评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,859评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,981评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,705评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,310评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,904评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,023评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,146评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,933评论 2 355

推荐阅读更多精彩内容