Fortran比C更容易优化计算吗?
我不时读到Fortran是或可以比C更快的计算。 这是真的吗? 我必须承认,我几乎不了解Fortran,但是到目前为止我看到的Fortran代码并没有表明这个语言具有C没有的特性。
如果是这样,请告诉我为什么。 请不要告诉我什么语言或库对数字处理有好处,我不打算写一个应用程序或库来做到这一点,我只是好奇。
这些语言具有相似的function集。 性能差异来自Fortran说不允许别名的事实。 任何具有别名的代码都是无效的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的慢。 为什么这样? 如果将值写入输出数组,则可以更改matrix的值。 所有的指针都可以重叠并指向相同的内存块(包括int
指针!)。 C编译器被强制从内存中为所有计算重新加载四个matrix值。
在Fortran中,编译器可以加载一次matrix值并将它们存储在寄存器中。 它可以这样做,因为Fortran编译器假定指针/数组在内存中不重叠。
幸运的是,restrict关键字和strict-aliasing已被引入C99标准来解决这个问题。 现在大多数C ++编译器都支持它。 关键字允许你给编译器一个暗示,程序员承诺一个指针不会与别的指针混淆。 严格别名意味着程序员承诺不同types的指针不会重叠,例如double*
不会与int*
重叠(具体的例外是char*
和void*
可以和任何东西重叠)。
如果你使用它们,你将获得与C和Fortran相同的速度。 但是,仅将性能关键函数用于restrict关键字的能力意味着C(和C ++)程序更安全,更易于编写。 例如,考虑无效的Fortran代码: CALL TRANSFORM(A(1, 30), A(2, 31), A(3, 32), 30)
,大多数Fortran编译器将愉快地编译而没有任何警告,但引入了一个bug只在某些编译器上显示,在一些硬件和一些优化选项。
是的,在1980年; 在2008? 依靠
当我开始专业编程时,Fortran的速度优势正在受到挑战。 我记得在Dobbs博士那里读到这篇文章,并且告诉了那些年长的程序员这篇文章 – 他们笑了。
所以我对此有两个看法,理论性和实践性。 理论上 Fortran今天对于C / C ++甚至任何允许汇编代码的语言都没有内在的优势。 在实践中, Fortran今天仍然享有围绕数字代码优化而build立的历史和文化遗产的益处。
直到包括Fortran 77在内,语言devise考虑因素都被优化为主要焦点。 由于编译器理论和技术的状态,这通常意味着限制特性和function,以便为编译器提供优化代码的最佳select。 一个很好的比喻就是将Fortran 77认为是一款专业赛车,以牺牲速度为代价。 现在编译器在各种语言中都变得更好,程序员的生产力特性也更受重视。 但是,人们仍然主要关心科学计算的速度, 这些人很可能inheritance了自己是Fortran程序员的代码,培训和文化。
当开始讨论代码的优化时,会遇到很多问题,最好的办法就是让潜伏在那些有快速数字代码的人的工作中 。 但请记住,这些敏感的代码通常只是整个代码行的一小部分,而且非常专业化:许多Fortran代码与其他语言中的许多其他代码一样“低效”, 优化甚至不应该是这样的代码的主要关注 。
开始学习Fortran的历史和文化的一个很好的地方就是维基百科。 Fortran维基百科条目非常好,我非常感谢那些花时间和精力为Fortran社区创造价值的人。
(这个答案的简短版本可能是Nils开始的优秀线程中的一个注释,但是我没有这个业力,实际上,我可能根本没有写任何东西,信息内容和分享,而不是火焰战争和语言偏执,这是我对这个主题的主要经验,我不知所措,不得不分享爱情。)
在某种程度上,Fortran的devise始终考虑到编译器优化。 该语言支持整个数组操作,编译器可以利用并行(特别是在多核处理器上)。 例如,
密集matrix乘法就是:
matmul(a,b)
向量x的L2范数是:
sqrt(sum(x**2))
此外,诸如FORALL
, PURE
和ELEMENTAL
程序等语句进一步帮助优化代码。 因为这个简单的原因,甚至在Fortran中的指针也不像C那样灵活。
即将推出的Fortran标准(2008)具有联合数组,可让您轻松编写并行代码。 来自CRAY的G95(开源)和编译器已经支持它。
所以是的Fortran可以很快,因为编译器可以比C / C ++更好地优化/并行化。 但是,像生活中的其他东西一样,还有好的编译器和糟糕的编译器。
很有趣的是,在这里不知道语言的答案很多。 对于已经打开旧FORTRAN 77代码的C / C ++程序员来说尤其如此,并且讨论这些缺点。
我想速度问题大多是C / C ++和Fortran之间的问题。 在巨大的代码中,它总是依赖于程序员。 Fortran语言的一些特性优于C语言。 所以,在2011年,没有人能真正说出哪一个更快。
关于语言本身,Fortran现在支持完整的OOPfunction,并且完全向后兼容。 我已经彻底地使用了Fortran 2003,我只能说使用它非常令人愉快。 在某些方面,Fortran 2003仍然在C ++之后,但让我们看看这个用法。 Fortran主要用于数值计算,由于速度原因,没有人使用奇特的C ++ OOP特性。 在高性能计算中,C ++几乎没有地方可走(看看MPI标准,你会发现C ++已经被废弃了)。
现在,您可以简单地使用Fortran和C / C ++进行混合语言编程。 Fortran中甚至有GTK +的接口。 有免费的编译器(gfortran,g95)和许多优秀的商业版本。
有几个原因可以使Fortran更快。 然而,他们的重要程度是如此的无关紧要,或者无论如何都可以解决,这应该不重要。 现在使用Fortran的主要原因是维护或扩展传统应用程序。
-
PURE和ELEMENTAL关键字的function。 这些是没有副作用的function。 这允许在编译器知道相同函数将被调用相同值的某些情况下进行优化。 注意:GCC实现“纯”作为语言的扩展。 其他编译器也可以。 模块间分析也可以执行这种优化,但是很难。
-
处理数组的标准函数集,而不是单个元素。 像sin(),log(),sqrt()这样的东西需要数组而不是标量。 这使得优化例程变得更容易。 在大多数情况下,如果这些函数是内联或内置的,则自动vector化会带来相同的好处
-
内置复杂types。 从理论上讲,这可以让编译器在某些情况下重新sorting或删除某些指令,但是可能会看到与struct {double re,im; }; 成语中使用的习惯用法。尽pipe运营商在Fortran中使用复杂types,但它使得开发速度更快。
我认为支持Fortran的关键在于它是一种更适合expression基于向量和数组的math语言。 上面指出的指针分析问题在实际中是真实的,因为可移植代码不能真正假定你可以告诉编译器什么。 以更接近域的外观的方式expression计算机总是有优势的。 如果你仔细观察,C并没有真正拥有数组,只是一些类似的行为。 Fortran有真正的arrawys。 这使得编译某些types的algorithm更容易,特别是对于并行机器。
像运行时系统和调用约定一样,C和现代的Fortran非常相似,很难看出什么会有所作为。 请注意,这里的C真的是基础C:C ++是一个完全不同的问题,具有非常不同的性能特点。
没有一种语言比另一种语言更快,所以正确答案是否定的 。
你真正要问的是“用Fortran编译器X编译的代码比用C编译器Y编译的等效代码快吗? 这个问题的答案当然取决于你select哪两个编译器。
另外一个可以问的问题是“如果在编译器中进行相同的优化,那么编译器会生成更快的代码? 这个答案实际上是Fortran 。 Fortran编译器具有certian优势:
- Fortran不得不在今天与大会进行竞争,当时一些人发誓从不使用编译器,所以它是为了速度而devise的。 C的devise灵活。
- Fortran的利基一直在数字化。 在这个领域代码是不够快的。 所以保持语言高效总是有很大的压力。
- 编译器优化的大部分研究都是由有兴趣加速Fortran数字处理代码的人完成的,因此,优化Fortran代码是一个比优化其他任何编译语言更为出名的问题,并且先在Fortran编译器中显示新的创新。
- Biggie :C鼓励比Fortran更多地使用指针。 这大大增加了C程序中任何数据项的潜在范围,这使得它们难以优化。 请注意,在这个领域,Ada也比C好,而且是比现在常见的Fortran77更现代的OO语言。 如果你想要一个比C代码更快的代码,这是你的select。
- Fortran编译器的客户再次考虑到其编译器的用户数量,他们倾向于比C编译器的客户更关心优化。
然而,没有什么能阻止某人花费大量的精力进入他们的C编译器的优化,并使其生成比他们平台的Fortran编译器更好的代码。 事实上,C编译器产生的较大销售量使得这种情况非常可行
还有另一个Fortran与C不同的项目 – 可能会更快。 Fortran具有比C更好的优化规则。在Fortran中,expression式的求值顺序没有被定义,这允许编译器优化它 – 如果要强制某个顺序,就必须使用括号。 在C中,顺序要严格得多,但用“快速”选项,它们更放松,“(…)”也被忽略。 我认为Fortran有一个很好的方式在中间。 (那么,IEEE会让生活变得更加困难,因为某些评估顺序的改变要求不会发生溢出,这或者不得不忽视或者妨碍评估。
更聪明的规则的另一个领域是复杂的数字。 不仅如此,直到C99,C才拥有了它们,在Fortran中pipe理它们的规则也更好; 由于gfortran的Fortran库部分用C语言编写,但实现了Fortran语义,因此GCC获得了选项(也可以用于“普通”C程序):
-fcx-fortran-rules复杂的乘法和除法遵循Fortran规则。 范围缩减是作为复杂划分的一部分完成的,但是没有检查复数乘法或除法的结果是否是“NaN + I * NaN”,试图在这种情况下挽救情况。
上面提到的别名规则是另一个好处,而且 – 至less在原则上 – 全数组操作,如果编译器的优化程序正确考虑了这些操作,则可以导致更快的代码。 相反,某些操作需要更多的时间,例如,如果对可分配数组进行赋值,则需要进行大量检查(重新分配[Fortran 2003特性],数组步长等),这使得简单的操作在后台更复杂 – 因此速度更慢,但是使得语言更加强大。 另一方面,具有灵活的边界和步长的数组操作使编写代码变得更加容易,编译器通常比用户更好地优化代码。
总的来说,我认为C和Fortran的速度差不多。 select的应该是更多的语言,或者使用Fortran的全数组操作,并且更好的可移植性更有用 – 或者更好地连接到C中的系统和graphics用户界面库。
我比较了Fortran,C和C ++的速度与netlib的经典Levine-Callahan-Dongarra基准。 使用OpenMP的多语言版本是http://sites.google.com/site/tprincesite/levine-callahan-dongarra-vectors C语言比较丑陋,因为它以自动翻译开始,并且在某些情况下插入了限制和编译指示编译器。 在适用的情况下,C ++就是STL模板的C语言。 在我看来,STL是否提高了可维护性是一个混杂的包。
自动函数内嵌只有很less的练习,可以看到它在多大程度上改进了优化,因为这些示例是基于传统的Fortran实践的,对内部的依赖很小。
迄今为止最广泛使用的C / C ++编译器缺乏自动vector化,这些基准依赖于这些vector。
回顾刚刚发布的文章:有一些例子在Fortran中使用括号来表示更快或更准确的评估顺序。 已知的C编译器没有选项来观察括号,而不禁用更重要的优化。
Fortran和C 语言没有什么特别的用途,使得它比另一个更快。 对于这些语言中的每一种语言都有特定的编译器 ,这些语言对某些任务比其他语言更有利。
多年来,Fortran编译器已经存在,它可以为您的数字例程添加黑魔法,使得许多重要的计算变得非常快速。 当代的C编译器不能这样做。 因此,在Fortran中增加了一些很棒的代码库。 如果您想要使用这些经过良好testing的,成熟的,精彩的库,您可以打开Fortran编译器。
我的非正式的观察表明,现在人们用任何旧的语言来编码他们沉重的计算资料,如果花费一些时间,他们会在一些便宜的计算机群上找时间。 摩尔定律使我们都成为愚人。
我和FORTRAN和C做了一些广泛的math, 根据我自己的经验,我可以说FORTRAN有时真的比C好,但不是它的速度(通过使用适当的编码风格,C可以像FORTRAN一样快速地执行),而是因为LAPACK等非常优化的库,很好的并行化。 在我看来,FORTRAN真的很尴尬,它的优点还不足以取消这个缺点,所以现在我用C + GSL来做计算。
Fortran和C之间的任何速度差异将更多地是编译器优化和特定编译器所使用的底层math库的函数。 Fortran没有什么内在的东西可以使它比C更快。
无论如何,一个好的程序员可以用任何语言编写Fortran。
我是一个业余爱好者,我是两种语言的“平均”。 我发现编写比C(或C ++)代码更快的Fortran代码比较容易。 Fortran和C都是“历史性”语言(按照今天的标准),被大量使用,并且很好地支持了免费和商业编译器。
我不知道这是否是一个历史事实,但是Fortran觉得它是构build为并行/分布式/vector化/任意多核的。 而今天,在我们谈论速度的时候,它几乎就是“标准指标”:“它的规模?
对于纯cpu捣弄我爱Fortran。 对于IO相关的任何事情,我发现与C一起工作更容易(无论如何都很难)。
当然,对于并行math密集型代码,您可能需要使用GPU。 C和Fortran都有很多或多或less的集成CUDA / OpenCL接口(现在是OpenACC)。
我的中等客观的答案是:如果你同样知道这两种语言同样好/很差,那么我认为Fortran更快,因为我发现在Fortran编写并行/分布式代码比C更容易。(一旦你明白,你可以写“自由forms”fortran和不只是严格的F77代码)
对于那些愿意不喜欢第一个答案的人来说,这是第二个答案:这两种语言都具有编写高性能代码所需的特性。 所以它取决于你正在执行的algorithm(CPU密集型?密集型?内存密集型?),硬件(单一CPU?多核?分布式超级计算机?GPGPU?FPGA?),你的技能,最终是编译器本身。 C和Fortran都有令人敬畏的编译器。 (我非常惊讶于Fortran编译器的高级编译器,C编译器也是如此)。
PS:我很高兴你专门排除了libs,因为我有很多关于Fortran GUI库的坏消息。 🙂
我没有听说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已经发展到包含特定的语言结构,可以被优化成固有的并行algorithm, 可以在多核处理器上真正地尖叫。 例如,自动vector化允许多个处理器同时处理数据vector中的每个元素。 16个处理器 – 16个元素的vector处理需要1/16的时间。
在C语言中,你必须pipe理你自己的线程,并仔细devise你的algorithm以进行多处理,然后使用一堆API调用来确保并行性正确发生。
在FORTRAN中,你只需要仔细devise你的algorithm进行多处理。 编译器和运行时可以为你处理剩下的事情。
您可以阅读关于高性能Fortran的一些信息,但会发现很多死链接。 你最好阅读并行编程(如OpenMP.org )以及FORTRAN如何支持。
快速简单: 两者同样快速,但Fortran更简单。 到底什么更快取决于algorithm,但是反正没有速度差别。 这是我在2015年德国斯图加特高性能计算中心Fortran研讨会上学到的。我与Fortran和C一起工作,并分享了这个观点。
说明:
C被devise来编写操作系统。 因此它比编写高性能代码更有自由。 一般来说,这是没有问题的,但是如果不仔细编程,可以很容易地减慢代码的速度。
Fortran是为科学编程devise的。 由于这个原因,它支持快速编写语法,因为这是Fortran的主要目的。 与公众意见相反,Fortran并不是一种过时的编程语言。 其最新的标准是2010年,并且定期发布新的编译器,因为大多数高性能代码都是在Fortran中编写的。 Fortran进一步支持作为编译器指令的现代function(在C编译指示中)。
Example: We want to give a large struct as an input argument to a function (fortran: subroutine). Within the function the argument is not altered.
C supports both, call by reference and call by value, which is a handy feature. In our case, the programmer might by accident use call by value. This slows down things considerably, as the struct needs to be copied in within memory first.
Fortran works with call by reference only, which forces the programmer to copy the struct by hand, if he really wants a call by value operation. In our case fortran will be automatically as fast as the C version with call by reference.
The faster code is not really up to the language, is the compiler so you can see the ms-vb "compiler" that generates bloated, slower and redundant object code that is tied together inside an ".exe", but powerBasic generates too way better code. Object code made by a C and C++ compilers is generated in some phases (at least 2) but by design most Fortran compilers have at least 5 phases including high-level optimizations so by design Fortran will always have the capability to generate highly optimized code. So at the end is the compiler not the language you should ask for, the best compiler i know is the Intel Fortran Compiler because you can get it on LINUX and Windows and you can use VS as the IDE, if you're looking for a cheap tigh compiler you can always relay on OpenWatcom.
More info about this: http://ed-thelen.org/1401Project/1401-IBM-Systems-Journal-FORTRAN.html
Most of the posts already present compelling arguments, so I will just add the proverbial 2 cents to a different aspect.
Being fortran faster or slower in terms of processing power in the end can have its importance, but if it takes 5 times more time to develop something in Fortran because:
- it lacks any good library for tasks different from pure number crunching
- it lack any decent tool for documentation and unit testing
- it's a language with very low expressivity, skyrocketing the number of lines of code.
- it has a very poor handling of strings
- it has an inane amount of issues among different compilers and architectures driving you crazy.
- it has a very poor IO strategy (READ/WRITE of sequential files. Yes, random access files exist but did you ever see them used?)
- it does not encourage good development practices, modularization.
- effective lack of a fully standard, fully compliant opensource compiler (both gfortran and g95 do not support everything)
- very poor interoperability with C (mangling: one underscore, two underscores, no underscore, in general one underscore but two if there's another underscore. and just let not delve into COMMON blocks…)
Then the issue is irrelevant. If something is slow, most of the time you cannot improve it beyond a given limit. If you want something faster, change the algorithm. In the end, computer time is cheap. Human time is not. Value the choice that reduces human time. If it increases computer time, it's cost effective anyway.
Fortran has better I/O routines, eg the implied do facility gives flexibility that C's standard library can't match.
The Fortran compiler directly handles the more complex syntax involved, and as such syntax can't be easily reduced to argument passing form, C can't implement it efficiently.
Using modern standards and compiler, no!
Some of the folks here have suggested that FORTRAN is faster because the compiler doesn't need to worry about aliasing (and hence can make more assumptions during optimisation). However, this has been dealt with in C since the C99 (I think) standard with the inclusion of the restrict keyword. Which basically tells the compiler, that within a give scope, the pointer is not aliased. Furthermore C enables proper pointer arithmetic, where things like aliasing can be very useful in terms of performance and resource allocation. Although I think more recent version of FORTRAN enable the use of "proper" pointers.
For modern implementations C general outperforms FORTRAN (although it is very fast too).
http://benchmarksgame.alioth.debian.org/u64q/fortran.html
编辑:
A fair criticism of this seems to be that the benchmarking may be biased. Here is another source (relative to C) that puts result in more context:
http://julialang.org/benchmarks/
You can see that C typically outperforms Fortran in most instances (again see criticisms below that apply here too); as others have stated, benchmarking is an inexact science that can be easily loaded to favour one language over others. But it does put in context how Fortran and C have similar performance.
This is more than somewhat subjective, because it gets into the quality of compilers and such more than anything else. However, to more directly answer your question, speaking from a language/compiler standpoint there is nothing about Fortran over C that is going to make it inherently faster or better than C. If you are doing heavy math operations, it will come down to the quality of the compiler, the skill of the programmer in each language and the intrinsic math support libraries that support those operations to ultimately determine which is going to be faster for a given implementation.
EDIT: Other people such as @Nils have raised the good point about the difference in the use of pointers in C and the possibility for aliasing that perhaps makes the most naive implementations slower in C. However, there are ways to deal with that in C99, via compiler optimization flags and/or in how the C is actually written. This is well covered in @Nils answer and the subsequent comments that follow on his answer.
Fortran traditionally doesn't set options such as -fp:strict (which ifort requires to enable some of the features in USE IEEE_arithmetic, a part of f2003 standard). Intel C++ also doesn't set -fp:strict as a default, but that is required for ERRNO handling, for example, and other C++ compilers don't make it convenient to turn off ERRNO or gain optimizations such as simd reduction. gcc and g++ have required me to set up Makefile to avoid using the dangerous combination -O3 -ffast-math -fopenmp -march=native. Other than these issues, this question about relative performance gets more nit-picky and dependent on local rules about choice of compilers and options.