我不知道2000年的编程语言会是什么样,但是我知道它会被称为FORTRAN。
-Charles Anthony Richard Hoar,约。1982年
在业界,Fortran如今很少使用-在流行语言列表之一中,它排名第28位。但是Fortran仍然是进行大规模物理系统模拟的主要语言-即恒星和星系的天体物理建模(例如Flash),大规模分子动力学,电子结构计数代码(SIESTA),气候模型等。在高性能计算领域(其中一部分是大规模数值模拟),如今仅使用两种语言-C / C ++和“现代Fortran”(Fortran 90/95/03/08)。流行的开放式MPI库已经针对这两种语言开发了代码并行化工具。通常,如果需要在多个处理器上运行的快速代码,则只有两个选择。在现代的Fortran中,有一个名为“ coarray ” 的功能,它允许在并行编程中直接使用该语言。 Coarray出现在Fortran 95扩展中,后来被整合到Fortran 2008中。物理学家对Fortran的积极使用常常使计算机科学家和与该领域无关的其他人感到困惑,他们认为Fortran是历史上的时代错误。我想解释一下为什么Fortran仍然有用。我不鼓励学习物理的学生教Fortran-因为他们中的大多数人都会做研究,所以他们最好学习C / C ++(或者停在Matlab / Octave / Python中)。我想解释为什么仍然使用Fortran,并证明这不仅是因为物理学家“落后于时代”(尽管有时如此)-去年,我看到一名物理专业的学生在研究代码Fortran 77,而他和他的经理都没有听到有关Fortran 90的任何消息。计算机科学家应将Fortran在数值计算领域的主导地位视为挑战。在深入探讨该主题之前,我想讨论一下这个故事,因为当人们听到“ Fortran”一词时,他们会立即想到打孔卡和带编号行的代码。第一个Fortran规范是1954年编写的。按照现代标准,早期的Fortran(当时的名称用大写字母FORTRAN编写)是一种地狱般的语言,但这是对先前汇编程序编程的不可思议的进步。正如Stony Brook University的Miriam Forman教授回忆说的那样,FORTRAN经常用打孔卡编程。 Fortran有许多版本,其中最著名的是标准66、77、90、95、03和08。人们常说,由于其速度,Fortran仍在使用。但是他最快吗?在基准游戏.alioth.debian.org有C和Fortran的比较在多种语言中进行了几次测试。在大多数情况下,Fortran和C / C ++是最快的。最喜欢的Python程序员通常在速度上落后100倍,但这是解释代码的顺序。Python不适合用于复杂的数值计算,但非常适合于另一个。有趣的是,C / C ++在除两个测试之外的所有测试中均胜过Fortran,尽管通常它们的结果差异不大。Fortran获胜的测试中,最“物理”的测试是对n个物体系统的仿真和频谱计算。结果取决于处理器内核的数量,例如,Fortran在四核上落后于C / C ++。在测试中,Fortran远远落后于C / C ++,它在大多数时间都读取和写入数据,在这一方面,Fortran的运行速度是众所周知的。因此,C / C ++的速度与Fortran一样快,有时还快一些。我们感兴趣的是,“为什么物理学教授继续建议他们的学生使用Fortran而不是C / C ++?”Fortran具有旧代码
由于Fortran的悠久历史,因此上面写着大量的物理代码也就不足为奇了。物理学家正在尝试最小化编程时间,因此,如果他们找到更早的代码,他们将使用它。即使旧代码不可读,文档记录不充分且效率最高,但使用旧的经过验证的代码比编写新的代码更有可能。物理学家的任务不是写代码,而是试图理解现实的本质。教授总是手头有继承的代码(通常他们是几十年前编写的),然后将其传递给学生。这样可以节省时间,并消除了纠错过程中的不确定性。物理专业的学生比C / C ++更轻松地学习Fortran
我认为Fortran比C / C ++更易于学习。 Fortran 90和C非常相似,但是Fortran更易于编写。 C是一种相对原始的语言,因此选择C / C ++的物理学家从事面向对象的编程。 OOP很有用,尤其是在大型软件项目中,但要花更长的时间研究。您需要研究类和继承之类的抽象。 OOP范例与Fortran使用的过程范例大不相同。 Fortran基于一个简单的程序范例,该范例更接近于计算机幕后发生的事情。当优化/矢量化代码以提高速度时,过程范例更易于使用。物理学家通常了解计算机的工作原理,并根据物理过程进行思考,例如,将数据从磁盘传输到RAM,再从RAM传输到处理器缓存。它们不同于数学家,他们更喜欢根据抽象函数和逻辑进行思考。而且,这种想法与面向对象不同。从我的角度来看,OOP代码的优化比过程的更为复杂。与物理学家喜欢的数据结构相比,对象是非常庞大的结构:数组。亮度一:Fortran阵列工作
数组,或者如物理学家所说的,矩阵,是所有物理计算的核心。在Fortran 90+中,您可以找到许多与之合作的机会,类似于APL和Matlab / Octave。可以复制数组,乘以标量,然后以非常直观的方式在数组之间相乘:A = B
A = 3.24*B
C = A*B
B = exp(A)
norm = sqrt(sum(A**2))
在这里,A,B,C是某个尺寸的数组(例如10x10x10)。如果A和B的大小相同,则C = A * B给我们矩阵的逐元素乘法。对于矩阵乘法,使用C = matmul(A,B)。几乎所有的Fortran内部函数(Sin(),Exp(),Abs(),Floor()等)都将数组作为参数,这导致了代码简洁明了。 C / C ++中根本没有类似的代码。在基本的C / C ++实现中,仅复制数组就需要在所有元素上运行for循环或调用库函数。如果在C中输入错误的库函数数组,则会发生错误。需要使用库而不是内部函数意味着生成的代码将不是干净,可移植的,也不是易于学习的。在Fortran中,通过简单语法A [x,y,z]访问数组的元素,而在C / C ++中则需要编写A [x] [y] [z]。数组的元素以1开头,这对应于物理学家对矩阵的理解,并且在C / C ++数组中,编号从零开始。以下是在Fortran中使用数组的其他一些功能。A = (/ i , i = 1,100 /)
B = A(1:100:10)
C(10:) = B
首先,通过隐式的do循环(也称为数组构造函数)创建向量A。然后,使用步骤10创建一个由B的每10个元素组成的向量B。最后,从第10个元素开始将数组B复制到数组C。Fortran支持使用零或负索引声明数组:double precision, dimension(-1:10) :: myArray
最初,负索引看起来很愚蠢,但是我听说它们的用处-例如,想象一下这是发布任何说明的附加区域。Fortran还支持矢量索引。例如,您可以将元素1,5和7从维度N x 1的数组A转移到维度3 x 1的数组B:subscripts = (/ 1, 5, 7 /)
B = A(subscripts)
Fortran 在所有内部函数中均支持数组掩码。例如,如果我们需要计算所有大于零的矩阵元素的对数,则使用:log_of_A = log(A, mask= A .gt. 0)
或者我们可以在一行中取消数组的所有负元素:where(my_array .lt. 0.0) my_array = 0.0
Fortran使动态分配和释放数组变得容易。例如,放置一个二维数组:real, dimension(:,:), allocatable :: name_of_array
allocate(name_of_array(xdim, ydim))
在C / C ++中,这需要以下输入:int **array;
array = malloc(nrows * sizeof(double *));
for(i = 0; i < nrows; i++){
array[i] = malloc(ncolumns * sizeof(double));
}
在Fortran中释放数组deallocate(name_of_array)
在C / C ++中为此for(i = 0; i < nrows; i++){
free(array[i]);
}
free(array);
:
在像C / C ++这样的语言中,所有变量均按值传递,但按引用传递的数组除外。但是在许多情况下,按值传递数组更有意义。例如,让数据由不同时间段的100个分子的位置组成。我们需要分析一个分子的运动。我们获取与该分子中原子的坐标相对应的数组(子数组)的一部分,并将其传递给函数。在其中,我们将处理传输子数组的复杂分析。如果我们通过引用将其传递,则传输的数据将不会连续位于内存中。由于内存访问的性质,使用这种阵列会很慢。如果按值传递它,则将在内存中创建一行排列的新数组。令物理学家高兴的是,编译器承担了优化内存的所有肮脏工作。在Fortran中,变量通常是按引用而不是按值传递的。在后台,Fortran编译器会自动优化其传输,以提高效率。从优化内存使用领域的教授的角度来看,编译器应该比学生更受信任!其结果是,物理学家很少使用指针,尽管用Fortran 90 + 他们。Fortran和C之间差异的更多示例
在进行故障排除和优化时,Fortran有几个用于管理编译器的选项。可以在编译阶段而不是执行期间捕获代码中的错误。例如,任何变量都可以声明为参数,即常量。double precision, parameter :: hbar = 6.63e-34
如果代码中的参数更改,则编译器将返回错误。在C中,这称为constdouble const hbar = 6.63e-34
问题在于const real与simple real不同。如果接受real的函数获取const real,则它将返回错误。很难想象这会导致代码中的互操作性问题。Fortran还具有一个意图规范,该规范告诉编译器传递给函数的参数是输入,输出还是输入和输出参数。这有助于编译器优化代码并提高其可读性和可靠性。Fortran具有在不同频率下使用的其他功能。例如,Fortran 95能够使用pure修饰符声明函数。这样的函数没有副作用-它仅更改其参数,而不更改全局变量。这种函数的一个特例是元素函数,它接受并返回标量。它用于处理数组元素。该函数是纯函数还是元素函数的信息使编译器可以执行其他优化,尤其是在并行化代码时。将来会发生什么?
在科学计算中,Fortran仍然是主要语言,并且在不久的将来不会消失。在调查中在使用该语言的2014年超级计算机大会的访问者中,有100%的人表示他们将在未来5年内使用它。从调查中还可以看出,有90%的人使用了Fortran和C的混合物。Fortran2015规范的创建者预计将增加这些语言的混合使用,其中包括更多的代码互操作性功能。从Python代码越来越多地调用Fortran代码。批评使用Fortran的计算机科学家并不理解该语言仍然是唯一适合其后缀的名称-FOrmula TRANslation,翻译公式,即将物理公式转换为代码。他们中的许多人都不知道该语言正在发展,并且不断包含新功能。将旧版本的Fortran 90+称为旧版,就像调用旧的C ++一样,因为C是在1973年开发的。另一方面,即使最新的Fortran 2008标准也具有与Fortran 77和大多数Fortran 66的向后兼容性。因此,语言的发展存在一定的困难。最近,麻省理工学院的研究人员决定克服这些困难,从零开始为HPC开发一种名为Julia的语言,该语言于2012年首次发布。朱莉娅是否代替Fortran仍有待观察。无论如何,我怀疑这将花费很长时间。