在现代时代学习FORTRAN


78

我最近来维护大量科学计算密集的FORTRAN代码。尽管有google和两本入门级书籍,但我在处理40岁语言的所有细微差别方面都遇到了困难。该代码充斥着“性能增强改进”。没有人有任何导游或实际的建议到CS 101的水平-optimizing FORTRAN?有谁知道FORTRAN代码优化的运作方式?Java / C ++ /。NET提出的开发人员接管FORTRAN 77/90代码库时,可能不会发生任何典型的FORTRAN“陷阱”吗?


4
这段文字可能会让您感兴趣吗?fortranrefactoring.com.ar/papers/…–
Rook

2
@DavidSokol我很喜欢在恐龙TDL播客上听您的讲话,尤其是关于上下文的问题:)注意,播客没有提到这一点,我只是记得听完之后看过它。
Tim Post

2
上面的链接已死,文档现在在这里:fortranrefactoring.org/papers/…–

Answers:


89

您对于某种程序员过去所做的事情必须有一种“感觉”。我使用的绝大多数代码都比我老,并且在我父母上高中时在“新”机器上运行。

我要处理的常见FORTRAN原则会损害可读性:

  • 普通块
  • 隐式变量
  • 共享CONTINUE语句的两个或三个DO循环
  • GOTO代替DO循环
  • 算术IF语句
  • 计算GOTO的
  • 等价的REAL / INTEGER /其他在某些公共区块中

解决这些问题的策略包括:

  1. 获得Spag / plusFORT,物有所值,它可以自动解决许多问题,并且提供Bug Free(tm)
  2. 如果可能,请移至Fortran 90,否则请移至自由格式的Fortran 77
  3. 将IMPLICIT NONE添加到每个子例程,然后修复每个编译错误,这很耗时,但最终是必需的,某些程序可以自动为您执行此操作(也可以编写脚本)
  4. 将所有公共块移动到模块,低挂水果,值得
  5. 将算术IF语句转换为IF..ELSEIF..ELSE块
  6. 将计算的GOTO转换为SELECT CASE块
  7. 将所有DO循环转换为较新的F90语法

    myloop: do ii = 1, nloops
        ! do something
    enddo myloop
    
  8. 将等效的通用块成员转换为模块中分配的ALLOCATABLE内存,或者如果Hollerith存储在REAL中则转换为其真实字符例程

如果您对如何完成一些可读性任务有更具体的问题,我可以提供建议。我有几十万行Fortran的代码库,它以某种方式负责了40多年,因此我可能遇到了您可能发现的所有“问题”。


3
另外,有关fortran重构的精彩文章。fortranrefactoring.com.ar/papers/…– 2011
Rook

如果代码的组织得不够好,并且被优化细节所混淆,这将非常困难。迁移到fortran 90样式将对您有所帮助。此外,fortran 2008的更高版本还提供了优化功能。
宙斯

看来plusFORT网站已移至此处:polyhedron.com/?
jrh

32

旧版Fortran肥皂盒

我帮助维持/改进了Fortran遗留代码库已有相当长的一段时间,并且大多数情况下都认为6个字母变量是有钱的。但是,这种建议往往是技术性的。在实施“良好做法”方面,更难对付。

  • 建立所需的编码样式和编码准则。
  • 对于提交给代码库的所有内容,都需要进行代码审查(不仅仅是编码者!)。(版本控制应与此过程联系在一起。)
  • 开始构建和运行单元测试;同上基准测试或回归测试。

如今,这些听起来似乎很明显,但是冒着过于笼统的风险,我声称大多数Fortran代码商店都拥有根深蒂固的文化,有些甚至在“软件工程”一词出现之前就已经开始了,并且随着时间的流逝,什么将成为主导是“立即完成”。(无论如何这都不是Fortran商店所独有的。)

拥抱陷阱

但是,如何处理已经存在的,肮脏的旧遗留代码库?我同意乔尔·斯波尔斯基(Joel Spolsky)的改写,同意。但是,我认为sixlettervariables确实指出了允许的例外:使用软件工具过渡到更好的Fortran构造。代码分析器(FORCHECK)和代码重写器(plusFORT)可以捕获/纠正很多错误。如果必须手动操作,请确保您有紧迫的理由。(我希望我能参考一些来自修复软件错误的软件错误的数量,这令人沮丧。我认为专家C编程中有这样的统计数据。)

在赢得Fortran陷阱的比赛中,最好的进攻方式就是拥有最好的防守:相当熟练地掌握这种语言。为了达到这个目的,我推荐...书籍!

Fortran死树库

多年来,我作为“ QA专家”仅取得了微不足道的成功,但我发现教育确实在某些程度上不经意间奏效,而最有影响力的事情之一就是某人手头上的参考书。我喜欢并强烈推荐

史蒂芬·查普曼(Stephen J.Chapman)为科学家和工程师设计的Fortran 90/95

这本书对于Fortran 77甚至是很好的,因为它专门指出了不应该使用的结构,并提供了更好的替代方法。但是,它实际上是一本教科书,当您真的想了解Fortran 95的精髓时,可能会一发不可收拾,这就是我建议的原因

Fortran 90/95解释,作者:Michael Metcalf和John K. Reid

作为您对Fortran 95的参考(原文如此)。请注意,这不是最清晰的文字,但是当您真正想充分利用Fortran 95的新功能时,面纱就会浮现。

我专注于解决从Fortran 77到Fortran 90的问题,

由Jim Kerrigan迁移到Fortran 90

但是这本书现在已经绝版了。(我只是不理解O'Reilly使用Safari的原因,为什么不是每本绝版书籍都可用?)

最后,关于精彩绝妙的经典软件工具的继承人,我提名

古典FORTRAN,由迈克尔Kupferschmid

这本书不仅显示了使用“仅” Fortran 77可以做什么,还讨论了一些更细微的问题(例如,是否应该使用EXTERNAL声明)。本书并没有完全涵盖与“软件工具”相同的空间,但是它们是我将其标记为“有趣”的三本Fortran编程书中的两本...(这是第三本)。

适用于几乎所有Fortran编译器的杂项建议

  • 有一个编译器选项可以强制执行IMPLICIT NONE行为,您可以使用它来识别问题例程,而无需先使用IMPLICIT NONE声明对其进行修改。直到第一次生成炸弹之后,由于在传统例程中插入了IMPLICIT NONE命令,该建议才显得有意义。(什么?您的代码审查没有抓住这个?;-)
  • 有一个用于数组边界检查的编译器选项,在调试Fortran 77代码时非常有用。
  • Fortran 90编译器应该能够编译几乎所有的Fortran 77代码,甚至是较旧的Fortran代码。打开Fortran 90编译器上的报告选项,通过它运行旧代码,您将在语法检查方面有一个不错的起点。一些商用的Fortran 77编译器实际上是在Fortran 77模式下运行的Fortran 90编译器,因此对于任何构建脚本而言,这都是相对琐碎的选择。

用于科学家和工程师的Fortran 90/95链接已死,但您可以在亚马逊上找到它,价格约为50美元,或者平装第一版的价格约为25美元
jrh

24

原始问题中有一些我要警告的问题。您说代码中充斥着“性能增强改进”。由于Fortran问题通常具有科学和数学性质,因此请不要认为存在这些提高性能的技巧。这可能与语言无关。在Fortran中,解决方案很少涉及代码本身的效率,而很少涉及解决最终问题的基础数学。这些技巧可能会使编译速度变慢,甚至可能使逻辑显得混乱,但是其目的是使解决方案更快。除非您确切知道它在做什么以及为什么,否则就别管它了。

即使是简单的重构(例如更改看起来笨拙的变量名称)也可能是一个很大的陷阱。自麦克斯韦时代以来,给定科学领域中的历史标准数学方程式将使用特定的简写形式。因此,看到电磁学中名为B(:)的数组将告诉所有Emag工程师确切的解决方案。改变它,后果自负。道德,在重命名之前也要了解科学的标准术语。


7

作为具有FORTRAN(虽然自从我认真使用以来已经有一段时间了,已有77种风味)和C / C ++两者的经验的人,要立即注意的项目就是数组。正如在C / C ++ / Java中一样,FORTRAN数组的索引从1开始而不是0。同样,存储排列也相反。因此,递增第一个索引将为您提供顺序的内存位置。

我的妻子仍然定期使用FORTRAN,并且有一些她需要使用的C ++代码,现在我将开始帮助她。在她转换期间出现问题时,我会尝试指出这些问题。也许他们会有所帮助。


12
默认情况下,Fortran数组以索引1开头,但可以声明为以任何值开头。
MSB 2010年

6

自1967年以来,我就一直使用从'66版本开始的Fortran(在具有70k内存的IBM 7090上)。然后,我使用了PL / 1一段时间,但后来又回到了Fortran 95,因为它非常适合我们遇到的矩阵/复数问题。我想补充一下考虑,旧代码的许多复杂结构仅仅是由于可用的内存量少,迫使诸如通过计算或分配的GOTOs重用几行代码之类的事情。另一个问题是通过为每个重复的子表达式定义辅助变量来进行优化-编译器根本没有为此进行优化。另外,不允许写DO i=1,n+1;你必须写n1=n+1;DO i=1,n1。结果,旧代码被多余的变量所淹没。当我在Fortran 95中重写代码时,只有10%的变量幸免。如果您想使代码更易读,我强烈建议您寻找易于消除的变量。

我可能要提到的另一件事是,多年来,复杂的算术和多维数组的效率非常低。这就是为什么您经常会发现代码被重写为仅使用实数变量和使用单个线性索引寻址的矩阵来执行复杂的计算。


5

好吧,从某种意义上来说,您很幸运,因为Fortran并没有太多的微妙的控制流构造或继承之类的方式。另一方面,它有一些真正令人惊讶的陷阱,例如算术计算的分支到数字标签的东西,不需要声明的隐式类型变量,缺少真正的关键字。

我不知道“性能增强改进”。我猜它们中的大多数可能无效,因为几十年的编译器技术使大多数提示没有必要。不幸的是,除非计划进行大规模重写,否则您可能必须保持现状。

无论如何,核心科学计算代码应相当可读。任何使用中缀算术的编程语言都是阅读Fortran算术和赋值代码的良好准备。


5

您能否解释一下维护代码所要做的事情?您真的需要修改代码吗?如果您可以通过仅修改该代码的接口而不是代码本身来解决问题,那将是最好的选择。

处理大型科学代码(而不仅仅是FORTRAN)时,固有的问题是基础数学和实现都很复杂。几乎默认情况下,该实现必须包括代码优化,以便在合理的时间范围内运行。由于该领域的许多代码是由本领域的专家而不是软件开发领域的专家/工程师创建的,这一事实使情况更加复杂。我们只是说“易于理解”并不是他们的首要任务(我是其中之一,还在学习成为一名更好的软件开发人员)。

由于问题的性质,我认为一般性的问题和答案不足以提供帮助。我建议您发布一系列带有代码段的特定问题。也许从最让您头疼的那一个开始?


4

我喜欢FORTRAN,我曾经在其中教书和编码。只是想扔进去。多年来没有碰过它。
我从COBOL开始,当我搬到FORTRAN时,我感到自己很自由。一切都是相对的,是吗?我仅次于上面所说的内容-认识到这是一种程序语言-没有子标题-因此请按照您的意愿使用。
一开始可能会让您感到沮丧。


2
我也经历了那个阶段。实际上,我记得最小化陷阱的“最佳实践”。但是后来我继续研究Lisp,Pascal,C,C ++。我仍然需要使用一些Fortran。真正的问题是,大多数内容都是在很少的程序员约束下编写的。人们仍然在教Fortran,但他们没有教纪律。
Mike Dunlavey 2009年

3

我从打孔卡上的Fortran IV(WATFIV)开始,我的早期工作是VS FORTRAN v1(IBM,Fortran 77级)。这个线程中有很多好的建议。

我要补充一点,您必须区分为使野兽完全运行而完成的工作,与“优化”代码的工作,以及更具可读性和可维护性的工作。我可以记得在尝试使用虚拟内存在IBM上运行DOE仿真代码时必须处理VAX叠加(必须将它们删除,并将整个东西变成一个地址空间)。

我当然首先要通过适当的缩进和注释,仔细地将FORTRAN IV控制结构重组到至少FORTRAN 77级别。尝试摆脱原始控制结构(例如ASSIGN和COMPUTED GOTO和算术IF),当然,要尽可能多地使用GOTO(使用IF-THEN-ELSE-ENDIF)。绝对在每个例程中使用IMPLICIT NONE,以强制您正确声明所有变量(您不会相信我在其他人的代码中捕获了多少个错误-变量名中的错字)。注意“过早的优化”,最好让编译器自己处理。

如果此代码要继续存在并可以维护,则您应该对自己和后继者有所帮助,以使其易于阅读和理解。只要确定您在更改代码时正在做什么!FORTRAN具有许多特殊的构造,可以很容易地使来自编程世界C端的人员绊倒。请记住,FORTRAN的历史可以追溯到50年代中期,当时还没有语言和编译器设计等科学知识,只是临时性地将某些东西混在一起了(抱歉,B博士!)。


1

这是不时咬我的另一个人。在使用FORTRAN代码时,请确保跳过所有六个初始列。每隔一段时间,我只会让代码缩进五个空格,而没有任何效果。乍一看一切似乎还好,然后我终于意识到所有的行都从第6列而不是第7列开始。

对于不熟悉FORTRAN的人,前5列用于行号(= labels),第6列用于连续字符,以防万一您的行长于80个字符(只需在此处添加一些内容,编译器就知道该行实际上是之前的一部分),并且代码始终从第7列开始。


6
此注释对于FORTRAN 77及更早版本适用,但对于使用自由格式源布局的Fortran 90及更高版本不适用。
MSB 2010年

3
而且,这些行应该在第72列而不是第80列结束。
白嘴鸦
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.