对于繁重的计算,Fortran比C更容易优化吗?

我不时地读到Fortran在繁重的计算中比C更快。这是真的吗?我必须承认我几乎不懂Fortran,但是到目前为止我看到的Fortran代码并没有显示出该语言具有C语言所不具备的特性。

如果是真的,请告诉我原因。请不要告诉我什么语言或库适合处理数字,我不打算写一个应用程序或库来做这个,我只是好奇。

164194 次浏览

Fortran和C之间的速度差异更多的是编译器优化和特定编译器使用的底层数学库的函数。Fortran没有什么固有的特性可以使它比C更快。

不管怎样,一个优秀的程序员可以用任何语言编写Fortran。

这不仅仅是主观的,因为它涉及到编译器的质量等等。然而,为了更直接回答你的问题,从语言/编译器的角度来看没有什么关于Fortran / C,本质上是要让它更快或比C。如果你做沉重的数学操作,还是到编译器的质量,程序员的技能在每个语言和数学的内在支持库,支持这些操作最终确定哪些是更快的对于一个给定的实现。

编辑:@Nils等人提出了一个很好的观点,即C语言中指针使用的差异,以及可能存在的别名,这可能会使C语言中最简单的实现变慢。然而,在C99中有一些方法可以解决这个问题,比如通过编译器优化标志和/或C语言的实际编写方式。这在@Nils的回答和随后的评论中有很好的介绍。

这两种语言具有相似的特性集。性能上的差异来自Fortran不允许混淆的事实,除非使用了EQUIVALENCE语句。任何有别名的代码都不是有效的Fortran,但是它是由程序员而不是编译器来检测这些错误的。因此,Fortran编译器忽略了可能的内存指针别名,并允许它们生成更有效的代码。看一下C语言中的这个小例子:

void transform (float *output, float const * input, float const * matrix, int *n)
{
int i;
for (i=0; i<*n; i++)
{
float x = input[i*2+0];
float y = input[i*2+1];
output[i*2+0] = matrix[0] * x + matrix[1] * y;
output[i*2+1] = matrix[2] * x + matrix[3] * y;
}
}

这个函数在优化后会比Fortran函数运行得慢。为什么如此?如果你在输出数组中写入值,你可能会改变矩阵的值。毕竟,指针可以重叠并指向相同的内存块(包括int指针!)。C编译器被迫从内存中重新加载所有计算的四个矩阵值。

在Fortran中,编译器只加载一次矩阵值,并将它们存储在寄存器中。它可以这样做是因为Fortran编译器假定指针/数组在内存中不重叠。

幸运的是,restrict关键字和严格别名已经被引入到C99标准中来解决这个问题。现在大多数c++编译器都很支持它。关键字允许你给编译器一个提示,程序员承诺一个指针不与任何其他指针别名。严格混叠意味着程序员保证不同类型的指针永远不会重叠,例如double*不会与int*重叠(特殊的例外是char*void*可以与任何指针重叠)。

如果你使用它们,你将得到与C和Fortran相同的速度。然而,只能在性能关键函数中使用restrict关键字的能力意味着C(和c++)程序更安全,更容易编写。例如,考虑无效的Fortran代码:CALL TRANSFORM(A(1, 30), A(2, 31), A(3, 32), 30),大多数Fortran编译器都会在没有任何警告的情况下编译它,但会引入一个只在某些编译器、某些硬件和某些优化选项上出现的错误。

我还没有听说过Fortan比C快得多,但是可以想象在某些情况下它会更快。关键不在于语言特征的存在,而在于那些(通常)不存在的特征。

一个例子是C指针。C指针几乎到处都在使用,但指针的问题是编译器通常无法判断它们是否指向同一个数组的不同部分。

例如,如果你写了一个strcpy例程,看起来像这样:

strcpy(char *d, const char* s)
{
while(*d++ = *s++);
}

编译器必须在d和s可能是重叠数组的假设下工作。所以当数组重叠时,它不能执行会产生不同结果的优化。正如您所期望的,这在很大程度上限制了可以执行的优化类型。

[我应该注意到,C99有一个“restrict”关键字,显式地告诉编译器指针不重叠。还要注意,Fortran也有指针,语义不同于C语言,但指针不像C语言那样无处不在。

但是回到C与Fortran的问题上,可以想象,Fortran编译器能够执行一些对于(直接编写的)C程序可能无法实现的优化。所以我不会对这种说法感到太惊讶。不过,我确实希望性能差异不会太大。(~ 5 - 10%)

一般来说,FORTRAN比C慢。C可以使用硬件级指针,允许程序员手动优化。FORTRAN(在大多数情况下)不能访问硬件内存寻址黑客。(VAX FORTRAN是另一回事。)我从70年代开始断断续续地使用FORTRAN。(真的)。

然而,从90年代开始,FORTRAN已经发展到包括特定的语言结构,可以优化成内在的并行算法,可以真正在多核处理器上呐喊。例如,自动矢量化允许多个处理器同时处理数据向量中的每个元素。16个处理器——16个元素向量——处理需要1/16的时间。

在C语言中,您必须管理自己的线程并为多处理仔细设计算法,然后使用一堆API调用来确保并行性正确发生。

在FORTRAN中,您只需要为多处理仔细设计算法。编译器和运行时可以为您处理其余的工作。

你可以阅读一些关于高性能Fortran的内容,但是你会发现很多死链接。你最好阅读并行编程(比如OpenMP.org)以及FORTRAN如何支持它。

在特定的目的下,语言 Fortran和C语言并没有使其中一个比另一个更快。对于每一种语言,都有一些特定的编译器,这使得一些语言比其他语言更适合某些任务。

多年来,Fortran编译器一直存在,它可以对你的数字例程施黑魔法,使许多重要的计算变得异常快速。当代的C编译器无法做到这一点。因此,在Fortran中出现了许多伟大的代码库。如果您想要使用这些经过良好测试的、成熟的、出色的库,就需要使用Fortran编译器。

我的非正式观察表明,如今人们用任何古老的语言来编码他们繁重的计算内容,如果这需要一段时间,他们就会在一些廉价的计算集群上找到时间。摩尔定律让我们所有人都成了傻瓜。

Fortran速度更快有几个原因。然而,它们的重要性是如此无关紧要,或者可以通过任何方式解决,所以它不应该是重要的。现在使用Fortran的主要原因是维护或扩展遗留应用程序。

  • 在函数上

    PURE和ELEMENTAL关键字这些是没有副作用的功能。这允许在某些情况下进行优化,即编译器知道将使用相同的值调用相同的函数。注意:GCC实现了“pure”;作为语言的扩展。其他编译器也可以。模块间分析也可以执行这种优化,但它很困难。

  • 处理数组而不是单个元素的标准函数集。像sin(), log(), sqrt()这样的东西接受数组而不是标量。这使得优化例程更加容易。如果这些函数是内联的或内置的,那么在大多数情况下,自动向量化提供了相同的好处

  • 内置复杂类型。理论上,这可以允许编译器在某些情况下重新排序或消除某些指令,但你可能会从c中使用的struct { double re; double im; };习语中看到同样的好处。它有助于更快的开发,尽管操作符在Fortran中处理复杂类型。

我认为支持Fortran的关键一点是,它是一种稍微更适合表达基于向量和数组的数学的语言。上面指出的指针分析问题在实践中是真实的,因为可移植代码不能真的假设您可以告诉编译器一些东西。用一种更接近域外观的方式来表达计算总是有一个优势。C语言其实根本没有数组,如果你仔细看的话,只是一些类似数组的东西。Fortran有真正的箭头。这使得某些类型的算法更容易编译,尤其是并行机器。

在运行时系统和调用约定等方面,C语言和现代的Fortran非常相似,很难看出有什么不同。注意,这里的C实际上是基础C: c++是一个完全不同的问题,具有非常不同的性能特征。

是的,在1980年;在2008年?取决于

当我开始专业编程时,Fortran的速度优势正受到挑战。我记得在多布斯医生那里读到的和告诉老程序员关于这篇文章——他们笑了。

所以我对此有两种观点,理论上的和实际的。今天的Fortran与C/ c++甚至任何允许汇编代码的语言相比没有内在的优势。Fortran今天仍然享受着围绕优化数字代码而建立的历史和文化遗产的好处。

在Fortran 77之前,语言设计的主要关注点都是优化。由于编译器理论和技术的状态,这通常意味着限制特性和能力,以便给编译器在优化代码方面的最佳机会。一个很好的类比是,把Fortran 77看作是一辆为了速度而牺牲功能的专业赛车。如今,所有语言的编译器都变得越来越好,程序员的工作效率也越来越受到重视。然而,仍然有一些地方,人们主要关心的是科学计算的速度;这些人很可能从那些曾经是Fortran程序员的人那里继承了代码、培训和文化。

当一个人开始谈论代码优化时,有很多问题,最好的方法是潜伏在人们工作的地方有快速的数字代码。但请记住,这种极其敏感的代码通常只占整个代码行的一小部分,而且非常专门:许多Fortran代码就像其他语言和优化甚至不应该是这类代码的主要关注点中的许多其他代码一样“低效”。

要开始了解Fortran的历史和文化,维基百科是一个很好的地方。Fortran维基百科条目是极好的,我非常感谢那些花时间和精力使它对Fortran社区有价值的人。

(这个答案的缩短版本将是由尼尔斯开始的优秀线程中的评论,但我没有业力这样做。实际上,如果不是因为这个帖子有实际的信息内容和分享,而不是激烈的争吵和语言偏见,我可能根本不会写任何东西,这是我对这个主题的主要经验。我不知所措,不得不分享这份爱。)

Fortran与C语言还有一个不同之处——而且可能更快。Fortran有比c更好的优化规则,在Fortran中,表达式的求值顺序没有定义,这允许编译器对其进行优化——如果想强制某个顺序,就必须使用括号。在C语言中,顺序要严格得多,但对于“-fast”选项,它们更轻松,“(…)”也会被忽略。我认为Fortran有一种方法正好位于中间。(嗯,IEEE使实时变得更加困难,因为某些计算顺序的更改要求没有溢出发生,溢出要么必须被忽略,要么会妨碍计算)。

另一个更聪明的规则领域是复数。这不仅是因为直到c99才有了它们,而且Fortran中管理它们的规则更好;由于gfortran的Fortran库部分是用C编写的,但实现了Fortran语义,GCC获得了这个选项(也可以用于“普通”C程序):

< p > -fcx-fortran-rules 复杂的乘法和除法遵循Fortran规则。范围缩减作为复杂除法的一部分,但没有检查复杂乘法或除法的结果是否为“NaN + I*NaN”,试图在这种情况下挽救这种情况

上面提到的别名规则是另一个好处,而且——至少在原则上——整个数组操作,如果编译器的优化器适当地考虑到这一点,可以产生更快的代码。另一方面,某些操作需要更多的时间,例如,如果对一个可分配数组进行赋值,则需要进行大量的检查(重新分配?[Fortran 2003特性],具有数组跨步等),这使得简单的操作在幕后变得更加复杂——因此更慢,但使语言更强大。另一方面,具有灵活边界和跨步的数组操作使编写代码更容易——编译器通常比用户更好地优化代码。

总的来说,我认为C和Fortran的速度差不多;选择应该更多的是你更喜欢哪种语言,或者是使用Fortran的全数组操作及其更好的可移植性更有用,还是使用C中更好的系统接口和图形用户界面库。

我比较了Fortran、C和c++的速度与netlib的经典Levine-Callahan-Dongarra基准测试。使用OpenMP的多语言版本是 http://sites.google.com/site/tprincesite/levine-callahan-dongarra-vectors C语言更丑陋,因为它一开始是自动翻译,加上某些编译器的限制和pragmas插入。 c++就是在适用的地方使用STL模板的C。在我看来,STL是否提高了可维护性是一个混合包

为了了解自动函数内联在多大程度上改进了优化,只需要进行很少的练习,因为示例基于传统的Fortran实践,其中很少依赖内联。

到目前为止使用最广泛的C/ c++编译器缺乏自动向量化,而这些基准测试严重依赖于此。

关于这之前的帖子:在Fortran中使用括号来指示更快或更准确的求值顺序的例子有两个。已知的C编译器没有在不禁用更重要的优化的情况下观察括号的选项。

没有一种语言比另一种语言更快的事情,所以正确的答案是没有

你真正要问的是“用Fortran编译器X编译的代码是否比用C编译器Y编译的等效代码更快?”这个问题的答案当然取决于您选择哪两个编译器。

人们可能会问的另一个问题是“假设他们在优化编译器上投入了相同的精力,哪个编译器会生成更快的代码?” 这个问题的答案实际上是Fortran。Fortran编译器有一定的优势:

  • Fortran必须与Assembly竞争,因为当时有人发誓永远不使用编译器,所以它的设计是为了提高速度。C语言设计得很灵活。
  • Fortran的利基市场一直是数字运算。在这个域代码是从来没有足够快。所以一直有很大的压力来保持语言的效率。
  • 大多数关于编译器优化的研究都是由对加速Fortran数字运算代码感兴趣的人完成的,因此优化Fortran代码是一个比优化任何其他编译语言更广为人知的问题,而新的创新首先出现在Fortran编译器中。
  • 要人: C比Fortran更鼓励使用指针。这大大增加了C程序中任何数据项的潜在作用域,这使得它们更加难以优化。注意,Ada在这个领域也比C好得多,并且是一种比常见的Fortran77更现代的OO语言。如果您想要一种能够生成比C更快的代码的OO语言,这是您的一个选择。
  • 由于Fortran编译器的数字运算优势,它的客户往往比C编译器的客户更关心优化。

然而,没有什么能阻止人们在C编译器的优化上投入大量精力,并使其生成比他们平台的Fortran编译器更好的代码。事实上,C编译器产生的较大销售额使得这种情况非常可行

在某种程度上,Fortran在设计时就考虑到了编译器优化。该语言支持整个数组操作,编译器可以利用并行性(特别是在多核处理器上)。例如,

密集矩阵乘法很简单:

matmul(a,b)

向量x的L2范数为:

sqrt(sum(x**2))

此外,诸如FORALLPURE &ELEMENTAL程序等进一步帮助优化代码。由于这个简单的原因,即使是Fortran中的指针也不如C语言灵活。

即将发布的Fortran标准(2008)具有协同数组,允许您轻松地编写并行代码。G95(开源)和来自CRAY的编译器已经支持它。

所以是的,Fortran可以很快,因为编译器可以比C/ c++更好地优化/并行化。但是就像生活中的其他事情一样,有好的编译器和坏的编译器。

大多数帖子已经提出了令人信服的论点,所以我只是在另一个方面加上众所周知的2美分。

在处理能力方面,fortran更快或更慢是有其重要性的,但如果用fortran开发一些东西需要5倍多的时间,因为:

  • 对于不同于纯粹的数字运算的任务,它缺乏任何好的库
  • 它缺乏任何像样的文档和单元测试工具
  • 它是一种表达能力非常低的语言,代码行数激增。
  • 它处理字符串的能力很差
  • 它在不同的编译器和架构之间有大量的问题,让你抓狂。
  • 它有一个很差的IO策略(读/写顺序文件。是的,随机访问文件存在,但你见过它们被使用过吗?)
  • 它不鼓励良好的开发实践、模块化。
  • 缺少完全标准、完全兼容的开源编译器(gfortran和g95都不支持所有的编译器)
  • 与C语言的互操作性非常差(混乱:一个下划线,两个下划线,没有下划线,通常是一个下划线,如果有另一个下划线则是两个。不要深入研究常见的模块…)

那么这个问题就无关紧要了。如果某样东西很慢,大多数时候你无法在给定的限制范围内改进它。如果你想要更快,改变算法。最后,使用电脑的时间很便宜。人类的时间不是。珍惜减少人类时间的选择。如果它增加了使用电脑的时间,无论如何它都是有成本效益的。

更快的代码并不取决于语言,而是编译器,所以你可以看到ms-vb的“编译器”会生成臃肿、更慢和冗余的目标代码,这些代码被捆绑在“。exe”中,但powerBasic生成的代码更好。 由C和c++编译器生成的目标代码在某些阶段(至少2个)生成,但从设计上讲,大多数Fortran编译器至少有5个阶段,包括高级优化,因此从设计上讲,Fortran总是能够生成高度优化的代码。 所以最后是编译器不是你应该要求的语言,我知道最好的编译器是英特尔Fortran编译器,因为你可以在LINUX和Windows上得到它,你可以使用VS作为IDE,如果你正在寻找一个便宜的编译器,你可以始终依赖于OpenWatcom

更多信息: http://ed-thelen.org/1401Project/1401-IBM-Systems-Journal-FORTRAN.html < / p >

几年来,我一直在用FORTRAN和C语言做一些广泛的数学运算。从我自己的经验来看,FORTRAN有时确实比C好,但不是因为它的速度(通过使用适当的编码风格,可以使C执行得和FORTRAN一样快),而是因为像LAPACK这样的非常优化的库(然而,它也可以从C代码中调用,可以直接链接到LAPACK,也可以使用LAPACKE接口用于C),还因为出色的并行化。在我看来,FORTRAN使用起来真的很尴尬,而且它的优点并不能抵消这个缺点,所以我现在使用C+GSL来进行计算。

有趣的是,这里的很多答案都来自于不懂语言。这对于那些打开过旧的FORTRAN 77代码并讨论过其弱点的C/ c++程序员来说尤其如此。

我认为速度问题主要是C/ c++和Fortran之间的问题。在大型代码中,它总是取决于程序员。有一些语言特性是Fortran优于的,而一些特性是C优于的。所以,在2011年,没有人能真正说出哪一个更快。

关于语言本身,Fortran现在支持完全面向对象的特性,并且完全向后兼容。我已经彻底地使用了Fortran 2003,我想说使用它是令人愉快的。在某些方面,Fortran 2003仍然落后于c++,但让我们看看它的用法。Fortran主要用于数值计算,由于速度原因,没有人使用花哨的c++ OOP特性。在高性能计算中,c++几乎无处可去(看看MPI标准,你会发现c++已经被弃用了!)。

现在,您可以简单地使用Fortran和C/ c++进行混合语言编程。Fortran中甚至有GTK+的接口。有免费的编译器(gfortran, g95)和许多优秀的商业编译器。

Fortran有更好的I/O例程,例如隐含的do工具提供了C标准库无法比拟的灵活性。

Fortran编译器直接处理更复杂的 涉及到语法,而且这样的语法不能轻易简化 对于参数传递形式,C不能有效地实现
Fortran传统上不设置像-fp:strict这样的选项(ifort需要在USE ieee_算术中启用一些功能,f2003标准的一部分)。英特尔c++也没有将-fp:strict设置为默认值,但这对于ERRNO处理是必需的,例如,其他c++编译器并不能方便地关闭ERRNO或获得诸如simd缩减之类的优化。gcc和g++要求我设置Makefile,以避免使用危险的组合-O3 - fast-math -fopenmp -march=native。 除了这些问题,这个关于相对性能的问题变得更加挑剔,并且依赖于关于选择编译器和选项的本地规则
我是一个业余程序员,在这两种语言上我都是“一般”。 我发现编写快速Fortran代码比编写C(或c++)代码更容易。Fortran和C都是“历史悠久”的语言(按照今天的标准),被大量使用,并且很好地支持免费和商业编译器。< / p >

我不知道这是否是一个历史事实,但Fortran感觉它是为并行/分布式/向量化/多核化而构建的。今天,当我们谈论速度时,它几乎是“标准度量”:“它能缩放吗?”

对于纯粹的cpu计算,我喜欢Fortran。对于任何与IO相关的东西,我发现使用c更容易(无论如何这两种情况都很困难)。

当然,对于并行计算密集型代码,你可能需要使用GPU。C和Fortran都有很多或多或少很好地集成了CUDA/OpenCL接口(现在还有OpenACC)。

我比较客观的回答是:如果你对这两种语言都同样了解或不了解,那么我认为Fortran更快,因为我发现用Fortran写并行/分布式代码比用c更容易(一旦你明白你可以写“自由形式”Fortran,而不仅仅是严格的F77代码)

对于那些因为不喜欢第一个答案而对我投反对票的人,我有第二个答案:这两种语言都有编写高性能代码所需的特性。所以这取决于你实现的算法(cpu密集型?IO密集?内存密集?),硬件(单CPU ?多核吗?分配超级计算机?GPGPU吗?FPGA ?),你的技能,最终是编译器本身。C和Fortran都有很棒的编译器。(我真的很惊讶Fortran编译器有多先进,但C编译器也是如此)。

PS:我很高兴你特别排除了库,因为我有很多关于Fortran GUI库的不好的东西要说。:)

快速简单: 这两种语言同样快,但Fortran更简单。 到底哪个更快取决于算法,但无论如何,速度上没有很大的差别。这是我2015年在德国斯图加德高性能计算中心的Fortran研讨会上所学到的。我既使用Fortran也使用C语言,我也有同样的观点

解释:

C语言是用来编写操作系统的。因此,它拥有编写高性能代码所需的更多自由。一般来说,这是没有问题的,但是如果一个人不仔细编程,他很容易减慢代码的速度。

Fortran是为科学编程而设计的。因此,它支持编写语法方面的快速代码,因为这是Fortran的主要目的。与公众的看法相反,Fortran并不是一种过时的编程语言。它的最新标准是2010年,新的编译器定期发布,因为大多数高性能代码都是用Fortran编写的。Fortran进一步支持现代功能,如编译器指令(在C语言中)。

< >强的例子: 我们想给一个大的结构体作为函数的输入参数(fortran: suboutine)。在函数中,参数不会被改变

C同时支持引用调用和值调用,这是一个非常方便的特性。在我们的例子中,程序员可能会意外地使用按值调用。这大大降低了速度,因为需要首先将结构体复制到内存中。

Fortran只使用引用调用,这迫使程序员手动复制结构,如果他真的想要按值调用操作。在我们的例子中,通过引用调用,fortran将自动和C版本一样快。

使用现代标准和编译器,不!

这里的一些人认为FORTRAN更快,因为编译器不需要担心别名(因此可以在优化过程中做更多的假设)。然而,这已经在C语言中处理了,因为C99标准(我认为)包含了限制关键字。这基本上告诉编译器,在给定作用域内,指针没有别名。此外,C支持适当的指针算术,在性能和资源分配方面,像混叠这样的东西非常有用。尽管我认为最近版本的FORTRAN允许使用“适当的”指针。

对于现代实现,C通用优于FORTRAN(尽管它也非常快)。

http://benchmarksgame.alioth.debian.org/u64q/fortran.html

编辑:

一个公平的批评似乎是,基准测试可能是有偏见的。这里是另一个来源(相对于C),将结果放在更多的上下文中:

http://julialang.org/benchmarks/

你可以看到C在大多数情况下优于Fortran(再次看到下面的批评也适用于这里);正如其他人所指出的,基准测试是一门不精确的科学,很容易偏袒一种语言而不是其他语言。但它确实说明了Fortran和C语言有相似的性能。

Fortran可以非常方便地处理数组,特别是多维数组。在Fortran中对多维数组元素进行切片比在C/ c++中容易得多。c++现在有库可以做这项工作,比如Boost或Eigen,但它们毕竟是外部库。在Fortran中,这些函数是固有的。

对于开发来说,Fortran是更快还是更方便主要取决于您需要完成的工作。作为地球物理的科学计算人员,我用Fortran(我指的是现代Fortran, >=F90)进行了大部分计算。