我最近开始维护大量科学计算密集型的 FORTRAN 代码。尽管有谷歌和两本入门级书籍,但我很难掌握四十年前语言的所有细节,例如细微差别。该代码充满了“性能增强改进”。有没有人有任何指南或实用建议 -将 FORTRAN 优化至 CS 101 级别?有人知道 FORTRAN 代码优化是如何操作的吗?是否有任何典型的 FORTRAN“陷阱”对于接管 FORTRAN 77/90 代码库的 Java/C++/.NET 开发人员来说可能不会出现?

有帮助吗?

解决方案

你必须“感觉”一下程序员过去必须做的事情。我使用的绝大多数代码都比我年龄大,并且在我父母上高中时的“新”机器上运行。

我遇到的常见的损害可读性的 FORTRAN 主义是:

  • 公共块
  • 隐式变量
  • 具有共享 CONTINUE 语句的两个或三个 DO 循环
  • GOTO 代替 DO 循环
  • 算术 IF 语句
  • 计算的 GOTO
  • 某些公共块中的等价 REAL/INTEGER/other

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

  1. 得到 斯帕格 / plusFORT, ,物有所值,它会自动解决很多问题并且没有 Bug(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 年间编写的,在某种程度上是我负责的,所以我可能遇到过您可能发现的任何“问题”。

其他提示

旧版 Fortran 肥皂盒

我帮助维护/改进了遗留的 Fortran 代码库很长一段时间,并且大部分认为 六字母变量 是在钱上。不过,这个建议偏向于技术性的建议。更艰巨的任务是实施“良好做法”。

  • 建立所需的编码风格和编码指南。
  • 需要对提交到代码库的任何内容进行代码审查(不仅仅是编码人员!)。(版本控制应该与此过程相关联。)
  • 开始构建和运行单元测试;同上基准测试或回归测试。

如今,这些听起来似乎是显而易见的事情,但冒着过度概括的风险,我声称大多数 Fortran 代码商店都有一种根深蒂固的文化,有些甚至在“软件工程”一词存在之前就开始了,随着时间的推移,什么将占据主导地位是“现在就完成它”。(无论如何,这并不是 Fortran 商店所独有的。)

拥抱陷阱

但是如何处理已经存在的、破旧的遗留代码库呢?我同意乔尔·斯波尔斯基关于重写的观点, . 。然而,在我看来 六字母变量 确实指向允许的例外: 使用软件工具过渡到更好的 Fortran 结构。 代码分析器可以捕获/纠正很多内容(福检查)和代码重写器(加堡)。如果你必须手工完成,请确保你有一个紧迫的理由。(我希望我手头有一份来自修复软件错误的软件错误数量的参考资料,这真是令人谦卑。我认为一些这样的统计数据是 专家 C 编程.)

也许赢得 Fortran 陷阱游戏的最佳进攻就是拥有最好的防守:对语言相当了解。为了进一步实现这一目标,我建议...图书!

Fortran 死树库

多年来,作为一名“QA 老兵”,我只取得了有限的成功,但我发现教育确实有效,有时是无意的,而最有影响力的事情之一就是某人手头上的一本参考书。我喜欢并且强烈推荐

面向科学家和工程师的 Fortran 90/95, ,斯蒂芬·J.查普曼

这本书甚至对 Fortran 77 也很有帮助,因为它特别指出了不应该使用的结构,并提供了更好的替代方案。然而,它实际上是一本教科书,当你真的想了解 Fortran 95 的本质时,它可能会失去动力,这就是我推荐的原因

Fortran 90/95 解释, ,迈克尔·梅特卡夫和约翰·K.里德

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

由于专注于从 Fortran 77 到 Fortran 90 的问题,我很喜欢

迁移到 Fortran 90, ,吉姆·克里根

但这本书现在已经绝版了。(我只是不明白奥莱利的用法 苹果浏览器, ,为什么不是每一本他们的绝版书都可用?)

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

经典FORTRAN, ,迈克尔·库普弗施密德

本书不仅展示了“仅”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 问题通常具有科学和数学性质,因此不要假设这些性能技巧是为了改进编译。应该不是语言的问题吧在 Fortran 中,解决方案很少与代码本身的效率有关,而是与解决最终问题的基础数学有关。这些技巧可能会使编译速度变慢,甚至可能使逻辑显得混乱,但其目的是使解决方案更快。除非你确切地知道它在做什么以及为什么,否则不要管它。

即使是简单的重构,例如更改看起来愚蠢的变量名称也可能是一个很大的陷阱。自麦克斯韦时代以来,历史上特定科学领域的标准数学方程将使用特定的速记法。因此,看到电磁学中名为 B(:) 的数组就可以告诉所有 Emag 工程师到底要解决什么问题。改变它,后果自负。道德上,在重命名之前也要了解科学的标准命名法。

作为一个在 FORTRAN(77 版本,尽管我已经有一段时间没有认真使用它)和 C/C++ 方面都有经验的人,首先想到的要注意的项目是数组。FORTRAN 数组以索引 1 开头,而不是像 C/C++/Java 中那样以 0 开头。另外,内存排列也颠倒了。因此,增加第一个索引可以为您提供连续的内存位置。

我的妻子仍然经常使用 FORTRAN,并且有一些她需要使用的 C++ 代码,现在我要开始帮助她了。当她转变过程中出现问题时,我会尽力指出它们。也许他们会帮忙。

您能解释一下维护代码时必须做什么吗?真的需要修改代码吗?如果您可以通过仅修改该代码的接口而不是代码本身来摆脱困境,那将是最好的。

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

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

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

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

嗯,从某种意义上说,你很幸运,因为 Fortran 没有太多微妙的控制流结构或继承等。另一方面,它有一些真正令人惊奇的陷阱,比如算术计算的分支到数字标签的东西、不需要声明的隐式类型变量、缺乏真正的关键字。

我不知道“性能增强改进”。我猜想它们中的大多数可能都是无效的,因为几十年来的编译器技术已经使得大多数暗示变得不必要。不幸的是,您可能不得不保持原样,除非您打算进行大规模重写。

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

我喜欢 FORTRAN,我曾经用它来教学和编码。只是想把它扔进去。好几年没碰过它了。
我一开始使用的是 COBOL,当我转向 FORTRAN 时,我感觉自己被解放了。一切都是相对的,是吗?我同意上面所说的 - 认识到这是一种过程语言 - 没有任何微妙之处 - 所以请按照你所看到的那样接受它。
一开始可能会让你感到沮丧。

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

我想补充一点,你必须区分为了让野兽运行而所做的事情,与“优化”代码的事情,与更具可读性和可维护性的事情。我记得在尝试让 DOE 模拟代码在具有虚拟内存的 IBM 上运行时处理 VAX 覆盖(它们必须被删除,整个东西变成一个地址空间)。

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

如果这段代码要继续存在并可维护,你就应该为你自己和你的继任者让它变得可读和易于理解。 更改代码时请确定您在做什么! FORTRAN 有许多特殊的结构,很容易让来自 C 编程世界的人陷入困境。请记住,FORTRAN 的历史可以追溯到 50 年代中后期,当时还没有语言和编译器设计科学之类的东西,只是 特别指定 拼凑一些东西(对不起,博士。B!)。

这是另一个不时困扰我的问题。当您处理 FORTRAN 代码时,请确保跳过所有六个初始列。每隔一段时间,我只会让代码缩进五个空格,但没有任何效果。乍一看一切似乎都很好,然后我终于意识到所有的行都是从第 6 列而不是第 7 列开始的。

对于任何不熟悉 FORTRAN 的人来说,前 5 列用于行号(=标签),第 6 列用于连续字符,以防您的行长度超过 80 个字符(只需在此处放置一些内容,编译器就知道这一行实际上是之前的一部分)并且代码总是从第 7 列开始。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top