在现代时代学习FORTRAN

我最近来维护大量的科学计算密集型FORTRAN代码。 尽pipe有谷歌和两本入门级别的书籍,但我仍然无法处理所有40年语言的细微差别。 代码充斥着“性能增强的改进”。 有没有人有任何指导或实用的build议优化FORTRAN到CS 101的水平? 有没有人知道如何运行FORTRAN代码优化? 是否有任何典型的FORTRAN'gotchas'可能不会出现在Java / C ++ /。NET高级开发人员接pipeFORTRAN 77/90的代码库?

你必须得到一个“感觉”,程序员必须在当天做什么。 我工作的绝大多数代码都比我年长,而且在我父母上高中的时候用的机器是“新”的。

我所处理的常见FORTRAN主义,伤害可读性是:

  • 共同的块
  • 隐式variables
  • 两个或三个共享CONTINUE语句的DO循环
  • GOTO代替DO循环
  • 算术IF语句
  • 计算GOTO的
  • 在某些通用块中,等价REAL / INTEGER / other

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

  1. 获得Spag / plusFORT ,值得的钱,它自动解决了很多问题,并且Bug Free(tm)
  2. 如果可能的话转移到Fortran 90,如果不移动到自由格式的Fortran 77
  3. 将IMPLICIT NONE添加到每个子例程,然后修复每个编译错误,耗时但最终是必需的,有些程序可以自动为您执行此操作(或者您可以编写脚本)
  4. 把所有的COMMON块移到MODULE,低挂果,值得
  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中的真正的字符例程

如果您对如何完成一些可读性任务有更具体的问题,我可以提供build议。 我有一个几十万行的Fortran代码库,这个代码库是在40年的时间里我写的,所以我可能会遇到你可能发现的任何“问题”。

传统的Fortran Soapbox

我帮助维护/改进了传统的Fortran代码库已经有一段时间了,大部分情况下,我认为六个可变因素有用的。 这个build议虽然倾向于技术性的, 在实施“良好做法”方面,一个更棘手的问题是锄头。

  • build立所需的编码风格和编码准则。
  • 要求代码审查(不仅仅是编码器!)提交给代码库的任何东西。 (版本控制应该绑定到这个过程。)
  • 开始build立和运行unit testing; 同样基准或回归testing。

这些听起来似乎是最近很明显的事情,但是冒着过度泛化的风险,我宣称大多数Fortran代码商店都有一种根深蒂固的文化,一些在“软件工程”这个词甚至存在之前就已经开始了,随着时间的推移,是“现在就完成”。 (这对Fortran商店来说不是唯一的。)

拥抱问题

但是如何处理已经存在的,糟糕的旧的遗留代码库呢? 我同意Joel Spolsky重写, 不要 。 但是,在我看来, 六个可变因素确实指向了可允许的例外: 使用软件工具转换到更好的Fortran结构。 代码分析器( FORCHECK )和代码重写器( plusFORT )可以捕获/纠正很多问题。 如果你必须手工做,确保你有一个紧迫的原因。 (我希望手头上有一些软件错误来自修复软件错误,这是令人惋惜的,我认为这样的统计数据是在Expert C Programming中的) 。

赢得Fortran陷阱游戏中最好的进攻方式是拥有最好的防守:相当了解这门语言。 为了达到这个目的,我推荐…书籍!

Fortran死树图书馆

作为一名“QA唠叨”,多年来我只取得了小小的成就,但是我发现教育确实有时是无意的,最有影响力的东西之一就是某人手头上的参考书。 我爱,并强烈推荐

Fortran 90/95科学家和工程师 ,Stephen J. Chapman

这本书在Fortran 77中甚至还不错,因为它明确指出了不应该使用的构造,并提供了更好的select。 然而,这实际上是一本教科书,当你真正想知道Fortran 95的本质时,它可能会失去动力,这就是为什么我build议

Fortran 90/95由Michael Metcalf和John K. Reid解释

作为Fortran 95的参考资料(原文如此)。要警告的是,这不是最清晰的文字,但是当您真正想要充分利用新的Fortran 95function时,面纱将会取消。

为了关注从Fortran 77到Fortran 90的问题,我很享受

由Jim Kerrigan 迁移到Fortran 90

但是这本书现在已经绝版了。 (我只是不明白O'Reilly对Safari的使用,为什么不是每一本绝版书都可以使用?)

最后,对于精彩,美妙的经典, 软件工具的inheritance人,我提名

古典FORTRAN ,由迈克尔Kupferschmid

这本书不仅说明了“只有”Fortran 77可以做什么,它还谈到了一些更微妙的问题(例如,是否应该使用EXTERNAL声明)。 本书并不完全覆盖“软件工具”的相同空间,但它们是三个Fortran编程书籍中的两个,我将其标记为“有趣”….( 这里是第三个 )。

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

  • 有一个编译器选项来执行IMPLICIT NONE行为,您可以使用该选项来识别问题例程,而无需先使用IMPLICIT NONE声明进行修改。 这个build议似乎没有什么意义,直到在第一次由于IMPLICIT NONE命令插入传统例程而造成炸弹爆炸之后。 (什么?你的代码审查没有收到这个?;-)
  • 有一个用于数组边界检查的编译器选项,在debuggingFortran 77代码时非常有用。
  • Fortran 90编译器应该能够编译几乎所有的Fortran 77代码甚至更老的Fortran代码。 打开Fortran 90编译器的报告选项,通过它运行你的遗留代码,你将有一个体面的开始语法检查。 一些商业Fortran 77编译器实际上是Fortran 90编译器,它们运行在Fortran 77模式下,所以这可能是相对简单的选项,无论你有什么构build脚本。

在原来的问题中,我会提醒一下。 你说代码充斥着“提升性能”。 由于Fortran问题通常具有科学性和math性,因此不要认为这些性能技巧可以改进编译。 这可能与语言无关。 在Fortran中,解决scheme很less涉及代码本身的效率,而是底层math解决最终问题的效率。 这些技巧可能会使编译速度变慢,甚至可能使逻辑看起来杂乱,但意图是使解决scheme更快。 除非你确切地知道它在做什么,为什么,不要pipe它。

即使是简单的重构,比如改变笨拙的variables名也是一个很大的缺陷。 自从麦克斯韦时代以来,科学领域的标准math方程就会使用一种特殊的速记方法。 因此,看到电磁学中名为B(:)的数组告诉所有Emag工程师到底要解决什么问题。 改变你的危险。 道德,也是在更名之前了解科学的标准命名。

作为一个在FORTRAN(77风格,虽然已经有一段时间,因为我认真使用它)有经验的人和C / C ++,要注意的那个项目立即跳转到想到的是数组。 在C / C ++ / Java中,FORTRAN数组的索引是1而不是0。 而且,存储器的安排是相反的。 所以增加第一个索引给你连续的内存位置。

我的妻子仍然经常使用FORTRAN,现在有了一些C ++代码,现在我即将开始帮助她。 随着问题出现在她的转换过程中,我会尽力指出。 也许他们会帮助。

自1967年以来,我一直使用Fortran作为自666版(在具有32k字内存的IBM 7090上)。 然后我使用了PL / 1一段时间,但后来又回到了Fortran 95,因为它非常适合我们的matrix/复数问题。 我想补充一下,旧代码的许多复杂结构只是由于可用的内存很less,迫使这样的事情,像通过计算或分配的GOTO重复使用几行代码。 另一个问题是通过为每个重复的子expression式定义辅助variables来进行优化 – 编译器根本就没有对其进行优化。 另外,不允许写DO i = 1,n + 1; 你必须写n1 = n + 1; DO i = 1,n1。 结果旧代码被多余的variables所淹没。 当我在Fortran 95中重写代码时,只有10%的variables存活下来。 如果你想让代码更清晰,我强烈build议寻找可以轻易消除的variables。

另一件我可能会提到的事情是,多年来,复杂的算术和multidimensional array是非常低效的。 这就是为什么你经常发现代码被改写为只使用实variables来进行复杂计算,而matrix则使用单个线性索引进行寻址。

那么从某种意义上说,你是幸运的,因为Fortran没有太多的微妙的stream程构造或inheritance等等。 另一方面,它有一些真正令人惊讶的陷阱,如算术计算的分支到数字标签的东西,不需要声明的隐式typesvariables,缺less真正的关键字。

我不知道“提高性能”。 我想大多数可能是无效的,因为几十年的编译器技术使得大多数暗示是不必要的。 不幸的是,除非你打算做大规模的重写,否则你可能不得不按照原来的方式。

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

你能解释一下你在维护代码时必须做些什么吗? 你真的要修改代码吗? 如果你可以通过修改那个代码的接口而不是代码本身来获得,那将是最好的。

处理大规模科学代码(而不仅仅是FORTRAN)时,内在的问题是底层math和实现都是复杂的。 几乎默认情况下,实现必须包含代码优化,以便在合理的时间范围内运行。 这是因为这个领域的许多代码是由他们领域的专家而不是软件开发的科学家/工程师创build的。 我们只是说“易于理解”不是他们的首要任务(我是其中之一,仍然在学习成为一个更好的软件开发人员)。

由于问题的本质,我不认为一般的问题和答案是足够有用的。 我build议您发布一系列附带代码片段的特定问题。 也许从那个让你最头痛的问题开始吧?

我喜欢FORTRAN,我曾经教过代码。 只是想把它扔进去。多年没有碰过它。
我从COBOL开始,当我搬到FORTRAN的时候,我感觉自己被释放了。 一切都是相对的,是吗? 我会再次说上面所说的 – 认识到这是一种程序语言 – 不要小题大做 – 就像你看到的一样。
可能让你感到沮丧。

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

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

我肯定会开始仔细重组FORTRAN IV控制结构到至lessFORTRAN 77级别,适当的缩进和评论。 尝试摆脱像ASSIGN和COMPUTED GOTO和算术IF这样的原始控制结构,当然,还有尽可能多的GOTO(使用IF-THEN-ELSE-ENDIF)。 在每一个例程中绝对使用IMPLICIT NONE,强制你正确地声明所有的variables(你不会相信我在其他人的代码中捕获了多less个错误 – 在variables名中有拼写错误)。 注意“过早优化”,你最好让编译器自己处理。

如果这个代码要继续生存并且可以维护,那么你应该为自己和你的inheritance者负责,使其可读性和可理解性。 只要确定你正在做什么,当你改变代码! FORTRAN有许多奇特的构造,可以轻松地将来自编程世界的C端的人绊倒。 请记住,FORTRAN的历史可以追溯到50年代中后期,当时没有像语言和编译器devise这样的东西,只是临时性地攻击某些东西(对不起,B博士)。

这是另一个不时有我咬我的地方。 当您使用FORTRAN代码时,请确保您跳过所有六个初始列。 每隔一段时间,我只会得到代码缩进五个空格,没有任何工作。 乍看起来一切似乎都没问题,然后我终于意识到,所有的行都是从第6列开始的,而不是从第7列开始的。

对于不熟悉FORTRAN的人来说,前5列是行号(=标签),第6列是连续字符,如果你有一个长度超过80个字符的行(只要在这里放一些东西,编译器知道这一行实际上是它之前的一部分),代码总是从第7列开始。