第一篇 闲话

中国数学的经典著作大都以依据不同方法或不同类型分成

章节的问题集的形式出现。每一个别问题又都分成若干个

条目:条目一是“问”,提出有具体数值的问题;条目二

是“答”,给出这一问题的具体数值答案;条目三称为“术”,

一般说来乃是解答与条目一同种类型问题的普遍方法,实

际上就相当于现在计算机科学中的“算法”,但有时也相

当于一个公式或一个定理;条目四是“注”,说明“术”

的依据与理由,实质上相当于一种证明;宋元以来,可能

是由于印刷术的发达,往往加上条目五“草”,记述依据

“术”得出答案的详细计算过程。

早在《九章算术》中,第八章方程章全章就是线性联立方

程组的解法。依刘微注:“并列为行,故谓之方程。”又

说:“令每行为率,二物者再程,三物者三程,皆如物数

程之。”当时以筹作算,依题意将数据按物数排成各行,

然后进行运算。…中学教科书解线性方程组的消元法,最

早即见之于《九章算术》。

数学在中国古时历来称为算术。这正好反映了中国古算构

造性、计算性与机械化的特色。数学不仅为了应用,即使

为了在纯数学范畴内获得具体结果,也一不能无算,二必

须有术。…中国古代算术的思想与方法,正好与近代计算

机的使用融合无间,也必将因此而重返青春,以另一种崭

新面貌在未来的数学发展中扮演重要角色。

----吴文俊[1]《对中国传统数学的再认识》

 

 

 


 

[1]吴文俊,中科院院士,我国最卓越的现代数学家之一,在拓扑学等领域取得世界性成就,近年积极推动数学机械化领域的发展。

 

1  目的是计算

我们这本书描述了一门语言。不幸的是语言很难成为我们的爱好,更何况FORTRAN语言也无法仿效英语,能够被某些英语大师成功地转换为一种疯狂。因此几乎每一个学习过编程语言的人都会有一种痛苦地记忆,那就是一种极端缺乏趣味的痛苦,因为很容易我们就会忘记这种语言的用处。显然,如果一种工具连用处都不是那么明显的话,哪里还谈得上给人带来乐趣呢?

所以要想在FORTRAN语言的学习过程当中不至于总是遭遇无聊,唯一的解救之途就是一开始就要找到学习它的绝对充足的理由,并且在学习过程中还会不得不反复地依靠这个理由,来说服自己需要更加有耐心,更加能够忍受烦琐和约定,逐渐地,也许我们能够从FORTRAN语言的惊人表达能力当中,体会到一种新的看待世界的角度,这大概会是我们享受那么多的枯燥之后,所能够得到的最佳回报。

所以我们不得不在进入正题之前,扯点闲话,看看学习FORTRAN的理由何在。

1.1  始于计算,终于计算

在荒莽的历史尽头,我们常常听说人类之所以能够凭借虚弱的身躯,一次又一次地打退其他凶猛动物的猖狂进攻,而终于成就为今日当之无愧的“万兽之王”,这个原因有很多种解释,比如说是劳动,说是手,说是大脑,莫衷一是,各有各的理论和证据,确实是个很难取得定论的问题,因此我想提出一种新的解释,大概是不会遭到立刻的覆灭性打击。

人类的进化始于计算,我相信。

在有关非洲黑猩猩的纪录片里面,可以看到黑猩猩也会用手使用工具,一个黑猩猩家庭为了生活也勤于劳动,一个黑猩猩群落社会里面的形形色色的政治行为,显示它们的大脑也不是很闲,但有一次我看到黑猩猩们抢香蕉时,总是把自己已经抢到手的香蕉给弄丢了而无知觉,突然觉得它们最缺乏的也许是算数的能力。

所以我想,人类的起源一定跟计算有莫大的关系。

当然这些都是戏说而已,不过如果说人类的科学是从计算开始的,应该是不会有太大的争议的。

也许有人说人类的科学活动应该是起源于观察,但从动物行为学的角度来看,观察这种行为是很难界定的,而计算则是非常好界定的行为,因为最原始的计算行为显然应该就是数数。

可以想像,当人类开始意识到自我在这个世界的孤独存在时,对于日月星辰和风雨雷电的无常和力量该是多么地恐惧啊!而人类把自己从这种恐惧当中解救出来的第一个方法应该就是算数。

算数导致了人类最早的科学活动,即天文学和几何学。人们从对日月星辰的计数当中发现了天体的运行是有常的,而不是什么不可琢磨的妖魔鬼怪在主宰;从对土地与山河的度量中建立了明确的几何概念,从而对自己所生活的世界开始了真正的理解。而这种理解活动一旦开始,就无法停止了,演变至今,就构成了我们人类最值得自豪的成就-科学。

科学的历史表明了它的基础,就是计算。

如果我们只是一味地观察,我们会纪录下来大量的经验,然而却无法理解这些经验的含义,更进一步,对于经验有了总结归纳之后,哪怕是进行计算的确切程度不同,也会导致不同的对于自然的理解。

一个很著名的例子,就是太阳系行星的运动的问题。

对于古人来说,所谓行星的意思就是那些星星是相对于恒星在明显地运动,在漫天的相互位置不变的恒星的对比之下,很少的这种匆匆行者是非常引人注目的。于是很早开始人们就纪录这些行星的运行轨道。在古希腊时代,最有名的关于这些行星运动的研究是托勒密完成的,他对有关行星的纪录数据进行了计算,得到了一个极其“圆满”的行星运动模型,即以地球为宇宙中心,行星围绕地球做严格圆周运动。现在看来,他的观测数据肯定不会是很精确,而他的计算也不会很准确,一直到开普勒,在获得了非常精确的行星轨道运行的数据的基础上,进行了大量的计算,最终得到了革命性的开普勒三定律。

接下来牛顿出场了,他更是一个计算天才,正是通过计算,从开普勒三定律获得了他的最伟大的发现,万有引力定律。

然后还是通过计算,我们现在可以运用牛顿万有引力公式的计算而把脚印留到月球的寂寞沙尘上。

还有一个非常独特的例子,就是中国的古代科学和技术,更是强烈地依赖计算。

相比于古希腊,中国的古代数学几乎完全是以计算为中心的,翻开中国的古代数学书,一个鲜明的特点就是几乎完全是针对问题的数学计算方面的内容,而很少有古希腊传统的公理,定理与证明。

实际上,古代中国在技术上一直领先于世界,很难说跟这种重视计算的风格没有关系。其中最有名的例子就是祖冲之关于圆周率的计算,而我们现在都很清楚,祖冲之的计算不仅是为圆周率提供了一个远比西方要精确的具体数值,更重要的是提供了一种非常通用的计算方法,即一种近似积分计算,而这种计算方法对于古代中国的技术进步的重要作用,正是一个表明计算的重要性的典范。

如果说计算在科学的早期发展中扮演了关键的作用,那么我们还是可以说计算仍然在现代科学技术扮演着关键的角色。

固然现代的科学技术领域广阔而渊深,然而哪里没有计算的身影呢?甚至在某些科学哲学家的看法里面,能否进行计算是衡量一个理论是否已经成为科学的一个部门的标准。也许这种说法不免偏激,但是计算对于科学与技术的意义,确实是一个深刻的问题。

我们不妨考察一下物理学里面计算所占据的地位,也许有助于更深地理解这个问题。

几乎是一直到十九世纪,物理学还是以实验为主要内容,进入二十世纪之后,一场物理学革命飞快地竖立了理论物理学的丰碑,足以与传统的实验物理学分庭抗礼。而这种局面在二战时期就开始改变,二战后在实验物理与理论物理之外,计算物理鼎足而立,导致这种变局的最关键的因素就是电子计算机的发明。

在计算机没有发明之前,人们不得不采取各种方式来回避过于庞大的计算问题,而大量的关键问题,又非得进行庞大的计算不可,以物理学为例,一旦我们透彻地解决了线性问题之后,接踵而来的就是远比线性现象更为广泛的非线性现象,对于非线性问题,我们已经掌握的解析方法极其贫乏,这就逼迫我们走上直接计算之路。

而除了非线性问题之外,物理学乃至整个自然科学看待世界的方式都是原子式的,即我们总是可以把一个现象理解为它的组成成分的相互作用的结果,于是我们就有了分子,原子等基本的科学观念,这种做法一直都是充满胜利的,然而这种胜利也是伴随着沉重代价的,即当我们重新面对复杂现象时,不得不从它的组成成分开始考虑,这就是统计物理学的基本思想,显然这种做法给我们带来了繁重的计算任务,因为迄今为止,我们人类对于一个包含超过了3个的,具有相互作用的成员的系统的精确解析求解,已经是有点一筹莫展了,更何况常见的那些动辄包含了成千上万成员的系统呢?因此在很大一部分情况下,我们唯一的选择,就是直接的计算。

因此我们可以说,计算确实是科学的基石之一。

至于我们所生活的这个几乎完全由科学技术所塑造的世界,哪里没有计算的身影呢?如果说计算帮助我们理解了自然,进一步我们还可以说计算创造了我们的生活。

任何一个科学上的对于自然的新的理解,要转变为为人所用的技术时,基本的途径就是计算。道理很显然,当我们要制造一种自然界从未出现过的物品时,我们需要的是具体的制造数据,而不能只是一堆公式,那么数据从哪里来呢?当然只能从对公式的计算得来。因此我们可以把计算理解为理论的实现途径。即理论无论是要反映真实世界,还是要体现到我们的实际物品上,它都需要通过一条叫计算的路,理论武装了我们的大脑,而计算则创造了我们的世界。

所以我们可以说,人类的历史,最早是始于计算,而这个历史的实现的最前沿,则仍然是终于计算。

1.2  描述计算的语言

长久以来,人类的计算都是依靠自己来完成的,但如果仔细考虑一下,就会发现计算的实质是把一个经过清楚的分析,明确了求解的方法的问题,分解为明确,可行,而有限的步骤,显然这种工作本质上是机械性的,如果把已经得到求解方法的问题还交给人脑来计算,显然有浪费人力之嫌;从另外一个方面来讲,往往一个需要专门加以计算的问题,也是一个需要进行庞大的计算的问题,庞大到人力已经难以胜任的程度。

因此这两个方面都要求人类发明能够进行计算的机器,这就直接导致了计算机的发明。

今天当我们面临需要计算的问题时,对付问题的就不再只是一个大脑,而是一个大脑加上一台机器。所以接下来的问题就是如何让大脑与计算机协同工作,使得大脑能够专门用来寻求问题的算法,而计算机能够被用来计算解。

这种协同工作的第一个要求就是人需要能够把自己对于问题的计算过程的理解表示为机器的机械运动。首先人对于问题及其求解的理解是可以非常清晰地依靠数学语言来加以描述说明的。然后我们再看机器那一端。

所谓计算机就是能够自动执行一系列机器动作的机器,对于那些机器动作,我们可以把它们和基本的计算操作对应起来,这就使得有可能把计算问题的能行的计算步骤分解为有限的机器操作,这里剩下的问题就是一方面是我们熟知的描述问题求解的数学语言,另一方面就是描述机器操作的语言,这两个方面的语言如何对应的问题。

下面我们讨论一个非常简单的例子,用来说明这里面的语言翻译问题。

一个一元二次方程的求解是一个很简单的数学问题。设方程的形式为:

   

那么方程的解的一般公式为:

注意我们现在的目的是计算,而不是求解析解,因此得到这个公式不是问题的结束,而是问题的开始,即运用这个公式,在abc都有具体取值的情况下,求出具体的数值解。因为如果该方程描述的是一个抛体运动,那么我们需要知道的当然是解的数值,以便我们了解和控制该抛体运动。

所以我们还需要进一步把这个数学表述转述为一个具体的求值过程的描述如下:

(1) 获得abc的具体取值;

(2) 根据abc的具体取值计算的值;

(3) 如果大于0,那么分别计算上面的两个公式的数值,得到两个不同的实数根;

(4) 如果=0,那么计算公式,得到的x的值就是方程的两个相同的根;

(5) 如果小于0,那么分别计算上面的两个公式的数值,得到两个不同的复数根。

这样得到的上面的5个计算步骤描述,才是希望计算机所执行的计算过程的一个大概描述。当然这个描述是基于我们已经获得的对于一元二次方程的求解问题的数学上的彻底了解。

那么描述计算机的操作的语言是什么样的形式呢?

我们知道所谓计算机的工作在本质上是运行一些基本的机械电子操作,固然我们可以把那些操作根据运算法则而定义为相应的运算,例如一个开关电路的信号叠加,可以适当地定义为二进制数值的加法,但显然不可能期望依靠这种物理现象能够直接地表达更加复杂的计算,例如上面公式里面的开平方。幸好我们依靠数学,可以做到把任何复杂的计算分解或近似分解为极少数简单计算的叠加与组合。因此最终我们已经至少在理论上可以期望使用计算机来完成那些具有明确求解过程的计算任务。

然而问题是当我们需要向计算机提交一个数值计算任务时,如果总是要求我们首先把计算任务的描述按照计算机所能够理解和执行的程度来进行的话,无疑会使得向计算机提交计算任务成为一件极其麻烦的事情,本来我们利用计算机的目的是为了减轻自己的机械劳动工作量,如果向计算机提交问题是如此麻烦的话,显然不符合我们发明计算机的初衷。

因此进入二十世纪五十年代后,提出了计算机高级语言的概念,所谓高级语言,就是非常接近我们平常对于数学问题的描述的语言,而所谓给出计算机高级语言,实质上并不是说计算机能够直接理解高级语言了,而是把高级语言到计算机内部的机器语言的翻译工作本身交给计算机来完成,因为这种翻译工作在规范了高级语言之后,是计算机自身就完全可以做到的,当然这个翻译任务本身又是一个需要我们首先明确给出一般解答的计算问题。

世界上第一个诞生的计算机高级语言就是我们在这本书里要给出的FORTRAN

FORTRAN最早是IBM公司在1957给出的,专门用于向IBM自己生产的704计算机提交表述计算问题的。一个计算问题的求解过程如果使用了计算机语言来表述,就称为一个程序,FORTRAN正是这样一种专门用来写程序的语言。

由于IBM709计算机的成功,同时也使得FORTRAN获得了广泛的传播,这时FORTRAN的语言本性开始在另外一个方面显示了出来,即语言的生命就在于它的传播。于是大多数其它计算机制造商也纷纷使得他们的产品能够输入和理解FORTRAN语言。

FORTRAN语言从它的名称来源就可以知道是一种与某些特定机器进行通讯的语言工具。即FORTRAN语句可以通过特定的机器上配置的编译程序而翻译成机器语言,因此早期的FORTRAN语言具有强烈的与机器系统相关的一些特征,它们反映了那些特定机器的某些特点,显然如果考虑到高级语言的本质是要用来描述计算过程,即所谓算法语言,那么这些与机器相关的特征是没有意义的,而FORTRAN不断更新版本所带来的进步,也就包含了不断舍弃这种特征的目的在内。

FORTRAN的这种历史痕迹的一个例子就是把语言用那些特定机器所能接受的字符序列(亦就是IBM公司用来向计算机输入程序的卡片穿孔设备的48个字符)来定义.而它的那种卡片输入方式决定了很多的程序书写格式。例如通常把语言中的一个语句写在一个记录上,也就对应着穿孔的一张卡片;各个语句按顺序读入,对应着卡片的顺序读入;卡片的格式是固定的,构成后来所谓的固定源码形式。

这就是最初提出计算机高级语言时我们所拥有的第一种高级语言的状况。

不久降生的另外一种高级语言是ALGOL,这个名称就是算法语言的简称,因此可以预料到这种语言具有与FORTRAN非常不同的面貌,因为这种语言在设计初始,就不是计算机制造公司为某种特定机器设计的,而是纯粹面向描述计算过程的,也就是所谓面向算法描述的。

ALGOL最早是在1958年由德意志联邦共和国应用数学与力学协会提出的。ALGOL的设计目标显然比FORTRAN要来得高远,它希望不仅能够用于人对机器转述计算过程,也希望能够直接用于人与人之间的对于算法的描述。

为了实现这个通用的目的,ALGOL的字符不是针对任一具体机器定义的,因此它不反映任何一台特定机器的特性。实际上ALGOL所使用的字符与词汇完全是独立定义的。除此之外ALGOL还具有许多更加独特的性质。

不过语言终久摆脱不了它的市场属性,由于FORTRAN更加具有市场侵占能力,最终FORTRAN至今还是主流的科学计算编程语言,而ALGOL语言则不幸成为了任人凭吊的古董。

1.3  为什么选择FORTRAN

到底选择什么样的语言,本身是一类非常具有争议性的问题。曾几何时,在科学计算领域,就沸沸腾腾地讨论过最好使用什么样的语言。也许我们可以说这是一个见仁见智的问题,因为我们作为语言的使用者,总是拣自己已经很熟悉的语言,当然总是自己能够很好驾驭的语言是最好的。但是具体地针对科学计算来说,由于科学计算问题具有自身的独特的价值标准,在这个价值标准之下,各种不同的语言还是可以进行客观比较的。

首先我们得把自己面临的任务界定清楚,也就是什么是科学计算问题?

所谓科学计算问题大体上包括如下三个涵义:

    问题本身以及问题的解答都能够使用数学语言予以精确描述;

    如果要使用通常的数学方法来给出我们所需要的数值答案,会很麻烦或者根本无法给出;

    问题以一定的科学与技术知识作为背景。

我们会看到正是科学计算问题的这种内涵决定了它在选择计算语言时所具有的价值标准。

首先,一个科学计算问题总是要以一个数学计算问题的形式出现,因此描述科学计算问题的语言应该能够自然地描述数学问题,即要求编程语言和数学语言在表达方式上具有比较直接自然的对应关系。

然后一个科学计算问题之所以需要使用计算机,那肯定是因为这个问题具有一定的计算量,那么程序的运行效率往往是选择语言时最重要的考量因素。

正是在这两点上,FORTRAN是现在众多语言当中的绝对胜出者。

在描述数学语言的自然性方面, FORTRAN可以说比现在还“活”着的任何语言都强。当然在历史上曾经出现过象ALGOL那样的相当数学化的语言,可惜的是它缺乏市场生存能力,所以就只剩下FORTRAN独美于今了。FORTRAN擅长描述数学计算,这点应该是几乎没有什么争议的。也正是由于这个缘故,FORTRAN的易学是公认的。任何一个科技专业人员,只要对于一个具体问题的数学求解过程有明晰的概念,要把这个求解过程翻译为FORTRAN语言是非常轻松的。

至于执行速度方面,则常常有些似是而非的说法误导初学者。最典型的一个错误观念就是“C代码的执行速度最快”。这个说法来源于C语言的特殊性,因为C语言更多的是一种系统编程语言,对硬件的控制能力很强,在高级语言里面无出其右者,于是给人以C程序的速度必定最快的印象。但是忘记了这个速度快是来自C语言的系统编程特性,而在做科学计算时,并不需要过多地涉及到系统内核,因此C语言的长处在科学计算方面可以说并不能适当地发挥,相反,在数值计算方面,C绝对不是FORTRAN的对手,因为相对于C以系统编程为目的,FORTRAN是以科学计算为目的的,语言本身在设计之初,就考虑到了针对科学计算而进行优化,因此FORTRAN生成的可执行代码是高度优化的。

实际的运行效率方面的比较也表明了FORTRAN在科学计算方面的优越性。无论是国内还是国外,也无论是经典的串行机还是并行矢量机,大量的经验表明,在执行同一个科学计算任务时,CC++代码的效率都低于FORTRAN代码,

除了常见的对于C有着高效的迷信之外,还常常有着对于FORTRAN是如何如何落后的偏见。当然这种偏见是有来源的,那就是曾经功勋卓著的FORTRAN 77在很长一段时间里面,都缺乏进取心,使得迄今很多人提起FORTRAN,想到的就是在当今时代已经显得非常落后的FORTRAN 77。实质上,FORTRAN标准在进入FORTRAN 90时代之后,特别是现时的FORTRAN 95版本,可以说只要是对于科学计算有用的特性,CC++有的,现在FORTRAN 95绝对不缺,而反过来FORTRAN 95所具有的很多针对科学计算的特性,却是CC++所不具有的。哪怕是C++最引以为傲的面向对象性质,FORTRAN 2000也将全面引入。所以说,FORTRAN已经完全赶上了编程语言的潮流。

与程序运行的效能有关的另外一个重要方面,是程序语言能否支持程序的并行运行,在这点上,可以说FORTRAN表现了它的最大优势,因为FORTRAN 95正是着力于获得并行计算的能力的一个版本。

由于现代科学计算的规模越来越大,计算并行化是一条不得不走的路线,现代计算机硬件的发展,也使得并行化具有实际的普及前景,因为不仅专门的大型计算机是并行的,现在的一般PC都可以拥有多个处理器,因此现代的从事科学计算的用户不得不掌握并行化计算的编程能力。

但是进行并行化编程所遇到的一个主要问题,就是任何过程编程语言都内在地使用线性存储模式,也就是一个数组的元素总是被认为按照数组元素的先后顺序而连续地存储在内存单位里面,这样一种模式就决定了这样的过程编程语言无法真正地实现对并行计算的描述。而FORTRAN 95则完全改观了这种制约,因为在FORTRAN 95里面对于数组以及数组运算建立了全新的面向并行化计算的概念,诸如纯过程的概念,逐元过程的概念,FORALL结构等等,都有效地摆脱了线性存储模式的制约,使得FORTRAN 95成为描述并行计算的标准语言,特别是那些专用的数据并行化语言都纷纷采用FORTRAN作为基础语言,例如高性能FORTRAN(High Performance Fortran)Fortran DVienna Fortran,以及CRAFT等。这样就使得使用FORTRAN 95编写的程序可以直接在这些数据并行化语言的平台上运行,而反过来使用这些专用语言编写的程序也可以毫不困难地转移到FORTRAN 95平台上运行,这样一种局面使得FORTRAN在并行计算领域独领风骚。

综上所述,我们完全可以说FORTRAN 95是进行科学计算的最佳语言,作为需要进行科学计算的科学与技术领域的工作人员,掌握FORTRAN 95远比掌握CC++等语言要重要得多,至于那些计算机符号代数与数值计算软件,例如MATHEMATICAMAPLEMATLABMacsymaMATHCAD等等,只能说是进行科学计算的教学模型与辅助工具,由于它们都提供了现成的算法,因此可以使得初学者能够应用于一些简单的场合,真正要用它们来对付稍微大一点的问题,有经验的用户都知道,那会是一件非常痛苦的强人所难的事情。因此最终要自由地进行科学计算,则非FORTRAN莫属。

1.4  FORTRAN的进步

下面我们介绍一下FORTRAN在历史上所取得的重要进步,特别是FORTRAN 95有别于FORTRAN 90的特征,更能够引导我们走向高性能的FORTRAN并行编程的领域。

1.4.1  FORTRAN 95的进步

FORTRAN的每一个进步,都意味着要把很多的语言特征归结为三类:

    新的语言特征;

顾名思义,就是FORTRAN最新版本引入的全新语言。

    过时的语言特征;

就是暂时在最新的FORTRAN标准里面仍然可以使用,而不会出现不兼容的情形,但是被指明为过时的语言特征,是在未来的下一个FORTRAN版本里面将要被淘汰的部分。

    废弃的语言特征。

顾名思义,就是在过去的FORTRAN版本里面曾经出现过,但在现在的版本里面已经不许使用的语言特征。

下面分别介绍它们。

1.4.2  新的语言特征

FORTRAN 95所增加的新的语言成分包括全新的功能和对旧有功能的改进两个部分。它们主要包括:

    FORALL语句与结构。

    (PURE)过程。

    逐元(ELEMENTAL)过程。

    WHERE结构的扩展。

    默认初始化。

    NULL固有函数。

    CPU_TIME固有子例行程序。

    固有函数CEILINGFLOORMAXLOCMINLOC的扩展。

    可分配数组的动态去分配。

    名称列表输入里面的注释。

    最小域宽格式说明。

    用于支持IEEE 754/854浮点运算标准的某些修改。

下面分别予以说明。

1. FORALL语句与结构

FORALL语句与结构和纯过程这两个新的语言成分,主要是为了提高在多处理器系统上面的程序并行运行效率而引进的。

只要系统支持并行的赋值,FORALL语句以及结构,就能够自然地实现对一个庞大的数组的所有元素进行同时赋值,从而充分地利用了系统的并行效能。这个新特征的引入充分显示了FORTRAN在并行运算方面的努力。

2. (PURE)过程

PURE是一个完全新引入的过程属性。具有PURE属性的函数或子例行程序,除了返回值之外,将不具有任何的后效。也就是说,对于它的任意变元或全局变量,它都不改变它们的值,指针关联状态,以及数据映射,也不执行输入输出。

FORTRAN 95标准里面,一些场合要求其中的过程必须具有PURE属性。特别地PURE属性对于应用FORALL语句或结构进行并行赋值是必要条件。

3. 逐元(ELEMENTAL)过程

逐元过程同样是执行并行运算的强大工具。把一个逐元过程应用到一个数组,就把这个针对数组的运算转化为对数组的所有元素的单个的运算,所有单个的结果再组合起来,返回一个同样形状的数组。

4. WHERE结构的扩展

WHERE结构经过扩展,可以包含一个FORALL结构的嵌套,而FORALL结构又可以包含WHERE语句或结构的嵌套。两者的配合使用具有强大的功能。

5. 默认初始化

默认初始化可以应用于派生类型,包括哑元,这样就能保证具有指针成员的派生类型对象能够一直可以访问。从而避免了出现内存可分配,但是不能去分配的情形。

对于指针,可以使用新的固有函数NULL来给出初始的关联状态,也可以在使用数据之前,使用NULLIFY语句来获得初始化。

6. NULL固有函数

新引入的固有函数NULL的功能主要是给指针赋予一个初始的去关联的关联状态。

NULL函数可以在一个类型声明语句当中使用,给定一个指针的初始去关联状态,也可以在一个结构构造器里面使用,用来给定其中指针成员的初始去关联状态。

7. CPU_TIME固有子例行程序

固有函数CPU_TIME用来测量一个程序或一段代码所消耗的处理器时间。

这个函数的测量结果不一定是非常准确的,但在一些情形下是非常有用的。例如用来比较不同代码的运行时间,从而比较它们的效率;也可以用来检测一个并行程序是不是真正地把一个变元作为一个数组来并行处理,从而评价它的并行效率。

8. 固有函数CEILINGFLOORMAXLOCMINLOC的扩展

FORTRAN 90和高性能FORTRAN之间,某些固有函数以及相关函数存在某些不兼容,因为在高性能FORTRAN里面,在不同的变元位置增加了一个DIM函数。

FORTRAN 95里面,就放松了对于变元顺序的要求,这样在变元序列当中MASKDIM的出现就可以是任意的了,从而保证了FORTRAN 95与高性能FORTRAN的兼容性。

9. 可分配数组的动态去分配

FORTRAN 95里面,当退出一个给定的作用域时,其中没有通过使用SAVE而得到保留的可分配数组,就自动地去分配,和使用DEALLOCATE语句的效果一样。这样就可以防止可能发生的内存遗漏,从而规范分配过程。

10. 名称列表输入里面的注释

在名称列表输入纪录当中可以使用注释,从而方便了用户。

11. 最小域宽格式说明

在使用数值的格式输出的时候,运用增强的输出格式编辑描述符,就可以对域宽进行极小化,从而避免输出时的白边。

12. 用于支持IEEE 754/854浮点运算标准的某些修改

在所有以前的FORTRAN版本里面,都不区分+0.-0.,即正0和负0,在FORTRAN 95版本里面,就能够区分这两者了,即在使用SIGN函数时,可以通过让第一个变元为0,而第二个变元为负号,就得到负0

1.4.3  过时的语言特征

FORTRAN 95里面被划归为过时的语言特征,在FORTRAN 90里面还是允许正常使用的,但是在FORTRAN 95里面已经强烈地不提倡使用,因为它们在下一个FORTRAN版本里面会被彻底淘汰。这些过时的语言特征主要包括:

    算术IF语句。

    DO终止的某些形式。

    替代返回。

    计算GO TO语句。

    语句函数。

    可执行语句之间的DATA语句。

    哑长度字符函数。

    固定源码形式。

    字符型声明里面的CHARACTER*形式。

下面分别说明,并特别要注意它们为什么是多余的或容易产生错误的。

1. 算术IF语句

算术IF语句的功能完全可以通过使用IF语句或IF结构来替代。

2. DO终止的某些形式

共享DO终止,或者不是使用END DO语句或CONTINUE语句的DO终止都是过时的,无论是从安全的角度,还是从清晰的角度,都最好使用具有不带标签的END DO语句的DO结构块形式。

3. 替代返回

替代返回强烈地依赖标签,是不值得提倡的,而且同样的功能完全可以通过CASE结构来实现。

4. 计算GO TO语句

计算GO TO语句完全可以使用CASE结构来代替,而且CASE结构还具有比计算GO TO语句更加广泛的功能。从结构化编程的角度来看,也应该使用CASE结构,而不是完全非结构化的,带有早期与系统相关特征的计算GO TO语句。

5. 语句函数

内部函数就具有语句函数的许多特征。而语句函数非常容易与赋值语句相混淆,所以语句函数也是不提倡使用的。

6. 可执行语句之间的DATA语句

如果在程序的可执行部分使用DATA语句的话,会容易让人产生一种错觉,即DATA语句能够在程序的执行过程当中进行赋值,而实际上,DATA语句只能用于数据的初始化,因此DATA语句最好还是只用于程序的说明部分。

7. 哑长度字符函数

哑长度字符函数要求在调用程序当中声明函数的名称,它完全可以通过运用具有显式界面或动态字符长度的子例行程序或函数来替代。

8. 固定源码形式

固定源码形式完全是由早期的卡片纸带式输入输出方式所决定,而现在卡片纸带式输入输出早已经不再使用,因此这种源码形式必定是要被淘汰的。

9. 字符型声明里面的CHARACTER*形式

在字符型声明语句当中用来说明字符长度的CHARACTER*完全是多余的,一般提倡采用更为合乎英语习惯的形式。

1.4.4  废弃的语言特征

FORTRAN 90里面还可以使用的语言特征有些已经被FORTRAN 95完全废弃了,因此要特别留意它们,以免出现源代码无法在FORTRAN 95系统里面调试通过的情况。

这些被FORTRAN 95废弃的语言特征主要包括:

    实型和双精度实型的DO变量。

    从块的外部分支到块内部的END IF语句。

    PAUSE语句。

    ASSIGN语句,带标签的GO TO语句。

    nH编辑描述符。

为了能够阅读使用FORTRAN 90以及更早版本的源代码,下面还是分别予以简要的说明。请注意它们遭到淘汰的原因所在。

1. 实型和双精度实型的DO变量

实型和双精度实型的DO变量或循环控制的DO参数都是难以移植的,而且也是很少用到的。因此现代的FORTRAN版本都要求DO变量为标量整型变量。

2. 从块的外部分支到块内部的END IF语句

从块的外部分支到块内部的END IF语句对于语句的执行序列的控制,是完全不必要的,也是不规范的,因此已经被完全淘汰了。

3. PAUSE语句

PAUSE语句用于把一个正在运行的程序挂起来,直到系统或操作重新开始运行。它的功能完全是多余的,因为WRITE语句可以发送消息到任何设备,例如操作控制台或终端,而READ语句则可以等待或接收来自同一个设备的消息。它们的配合使用就可以替代特别的PAUSE语句。

4. ASSIGN语句,带标签的GO TO语句

ASSIGN语句用来给一个整型变量赋予一个语句的标签。

它的一般用途就是,在程序的运行过程当中,通过ASSIGN语句就可以给该整型变量赋予分支目标语句的标签,从而给程序提供一种动态分支的能力。

然而整型变量除了可以具有标签值之外,还有可能具有一般的整数值,这就会容易导致程序错误,也使得程序难以阅读。

实际上ASSIGN语句,以及带标签的GO TO语句的功能,都可以由内部过程实现,因为ASSIGN语句无非就是纪录了一个可重用代码块完成运行后的返回点。

ASSIGN语句还可以把一个FORMAT语句的标签动态地赋予一个整型变量,然后该变量就可以用作WRITEREADPRINT语句的格式说明符。不过这个功能也可以通过把字符型变量,数组,以及常量用作格式说明符而得到实现。

总之,标签的使用总是不合时宜的。

5. nH编辑描述符

使用这个编辑描述符非常容易导致错误,因为跟在该描述符后面的字符数目很容易计算错误,而如果使用字符常量编辑描述符来行使相同的功能的话,则根本不需要计算字符数目。