我不时会读到Fortran是或者可以比C更快进行繁重的计算.这是真的吗?我必须承认我几乎不知道Fortran,但到目前为止我见过的Fortran代码并没有表明该语言具有C所没有的功能.
如果是真的,请告诉我原因.请不要告诉我哪些语言或库对数字运算有好处,我不打算写一个app或lib来做那个,我只是很好奇.
这些语言具有类似的功能集.性能差异来自于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编译器假定指针/数组在内存中不重叠.
幸运的是,已经在C99标准中引入了restrict关键字和严格别名来解决这个问题.如今,它在大多数C++编译器中得到了很好的支持.该关键字允许您向编译器提供程序员承诺指针不与任何其他指针进行别名的提示.严格别名意味着程序员承诺不同类型的指针永远不会重叠,例如a restrict
不会与a 重叠double*
(具有特定的例外,int*
并且char*
可以与任何东西重叠).
如果你使用它们,你将从C和Fortran获得相同的速度.但是,仅将restrict关键字用于性能关键功能的能力意味着C(和C++)程序更安全,更容易编写.例如,考虑一下无效的Fortran代码:void*
大多数Fortran编译器都会很乐意在没有任何警告的情况下进行编译,但会引入一个只出现在某些编译器,某些硬件和一些优化选项上的错误.
当我开始专业编程时,Fortran的速度优势正受到挑战.我记得在Dobbs医生那里读过这篇文章并告诉老程序员这篇文章 - 他们笑了.
所以我对此有两点看法,理论和实践.从理论上讲, Fortran今天对C/C++甚至任何允许汇编代码的语言都没有内在的优势.在实践中, Fortran今天仍然享有围绕数字代码优化而建立的历史和文化遗产的好处.
直到并包括Fortran 77,语言设计考虑因素都将优化作为主要关注点.由于编译器理论和技术的状态,这通常意味着限制功能和能力,以便为编译器提供优化代码的最佳机会.一个很好的比喻是将Fortran 77视为专业赛车,为速度牺牲功能.这些天编译器在所有语言中都有所改进,并且程序员生产力的功能更受重视.然而,仍有一些地方人们主要关注科学计算的速度; 这些人很可能从他们自己是Fortran程序员的人那里继承了代码,培训和文化.
当人们开始谈论代码的优化时,存在许多问题,并且最好的方法是潜伏在哪里,人们的工作就是拥有快速的数字代码.但请记住,这些极其敏感的代码通常只占整个代码行的一小部分而且非常专业:很多Fortran代码与其他语言中的许多其他代码一样"低效",优化甚至不应该是这种代码的主要关注点.
维基百科是一个了解Fortran历史和文化的好地方.Fortran维基百科条目非常棒,我非常感谢那些花时间和精力为Fortran社区创造价值的人.
(这个答案的缩短版本应该是Nils开始的优秀线程中的评论,但我没有业力去做.事实上,我可能根本不会写任何东西,但是因为这个线程有实际信息内容和分享,而不是火焰战争和语言偏见,这是我对这个主题的主要体验.我不知所措,不得不分享爱情.)
在某种程度上,Fortran的设计考虑了编译器优化.该语言支持整个阵列操作,其中编译器可以利用并行性(特别是在多核处理器上).例如,
密集矩阵乘法很简单:
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现在支持Full OOP功能,并且完全向后兼容.我彻底使用了Fortran 2003,我想说使用它很愉快.在某些方面,Fortran 2003仍然落后于C++,但让我们来看看它的用法.Fortran主要用于数值计算,由于速度原因,没有人使用花哨的C++ OOP功能.在高性能计算中,C++几乎没有任何地方可去(看看MPI标准,你会发现C++已被弃用!).
如今,您可以使用Fortran和C/C++进行混合语言编程.Fortran中甚至还有GTK +接口.有免费的编译器(gfortran,g95)和许多优秀的商业编译器.
Fortran可以更快的原因有几个.然而,它们重要的数量是如此无关紧要或无论如何都可以解决,它应该无关紧要.现在使用Fortran的主要原因是维护或扩展遗留应用程序.
关于函数的PURE和ELEMENTAL关键字.这些功能没有副作用.这允许在某些情况下优化,其中编译器知道将使用相同的值调用相同的函数.注意:GCC实现"纯"作为语言的扩展.其他编译器也可以.模块间分析也可以执行此优化,但很难.
处理数组的标准函数集,而不是单个元素.像sin(),log(),sqrt()这样的东西需要数组而不是标量.这样可以更轻松地优化例程.如果这些函数是内联函数或内置函数,则自动向量化在大多数情况下都会带来相同的好处
内置复合型.从理论上讲,这可能允许编译器在某些情况下重新排序或消除某些指令,但是你可能会看到结构{double re,im; }; 在C中使用的成语虽然运算符在fortran中处理复杂类型,但它可以加快开发速度.
我认为支持Fortran的关键点在于它是一种稍微适合表达基于矢量和数组的数学的语言.上面指出的指针分析问题在实践中是真实的,因为可移植代码不能真正假设您可以告诉编译器一些东西.以更接近域的外观的方式表达计算总是有利的.如果仔细观察,C根本就没有数组,只是像它那样的行为.Fortran有真正的图纸.这使得编译某些类型的算法变得更容易,特别是对于并行机器.
在运行时系统和调用约定等内容中,C和现代Fortran非常相似,很难看出会产生什么影响.请注意,这里的C实际上是基本C:C++是一个完全不同的问题,具有非常不同的性能特征.
没有一种语言比另一种语言更快,所以正确答案是否定的.
您真正需要问的是"使用Fortran编译器X编译的代码比使用C编译器Y编译的等效代码更快吗?" 这个问题的答案当然取决于你选择哪两个编译器.
人们可能会问的另一个问题是"考虑到在编译器中进行优化所需的相同工作量,哪个编译器会产生更快的代码?" 对此的答案实际上是Fortran.Fortran编译器具有certian优势:
当一些人发誓永远不会使用编译器时,Fortran不得不与大会竞争,所以它是专为速度而设计的.C设计灵活.
Fortran的利基已被数字运算.在这个域名代码永远不够快.因此,保持语言效率始终存在很大压力.
编译器优化的大多数研究都是由对加速Fortran数字运算代码感兴趣的人完成的,因此优化Fortran代码是一个比优化任何其他编译语言更为人熟知的问题,并且新的创新首先出现在Fortran编译器中.
Biggie:C鼓励使用比Fortran更多的指针.这极大地增加了C程序中任何数据项的潜在范围,这使得它们更难以优化.请注意,在这个领域,Ada也比C更好,并且是比常见的Fortran77更现代的OO语言.如果你想要一个可以生成比C更快的代码的OO语言,那么这是一个选项.
再次由于它的数字运算利基,Fortran编译器的客户往往比C编译器的客户更关心优化.
然而,没有什么能阻止某人在他们的C编译器优化中花费大量精力,并使其生成比其平台的Fortran编译器更好的代码.实际上,C编译器产生的较大销售额使这种情况非常可行
Fortran与C不同的另一个项目 - 可能更快.Fortran具有比C更好的优化规则.在Fortran中,没有定义表达式的评估顺序,这允许编译器对其进行优化 - 如果想要强制某个顺序,则必须使用括号.在C中,顺序要严格得多,但是使用"-fast"选项,它们会更放松,"(...)"也会被忽略.我认为Fortran有一种很好的中间位置.(好吧,IEEE使得现场更加困难,因为某些评估顺序的变化要求不会发生溢出,要么必须忽略这些溢出,要么妨碍评估).
智慧规则的另一个领域是复数.不仅C到C 99还有它们,在Fortran中管理它们的规则也更好; 由于gfortran的Fortran库部分用C语言编写但实现了Fortran语义,因此GCC获得了选项(也可以与"普通"C程序一起使用):
-fcx-fortran-rules复数乘法和除法遵循Fortran规则.范围减少是作为复杂除法的一部分完成的,但是没有检查复数乘法或除法的结果是否是"NaN + I*NaN",试图在这种情况下挽救情况.
上面提到的别名规则是另一个好处,并且 - 至少在原则上 - 全数组操作,如果编译器的优化器正确考虑,可以导致更快的代码.另一方面,某些操作需要更多时间,例如,如果对可分配数组进行分配,则需要进行大量检查(重新分配?[Fortran 2003功能],数组步长等),这使得简单的操作在幕后更加复杂 - 因此速度较慢,但却使语言更加强大.另一方面,具有灵活边界和跨度的数组操作使编写代码更容易 - 编译器通常比用户更好地优化代码.
总的来说,我认为C和Fortran的速度同样快; 选择应该更多,哪种语言更喜欢或者使用Fortran的全数组操作及其更好的可移植性是否更有用 - 或者更好地连接到C中的系统和图形用户界面库.
Fortran和C 语言没有任何特定目的使得一种语言比另一种语言更快.对于这些语言中的每一种语言都有一些特定的编译器,这些编译器比某些语言更有利于某些任务.
多年来,Fortran编译器已经存在,可以为你的数字例程做黑魔法,使得许多重要的计算速度非常快.当代的C编译器也做不到.结果,Fortran中出现了许多优秀的代码库.如果你想使用这些经过良好测试,成熟,精彩的库,你可以打破Fortran编译器.
我的非正式观察表明,现在人们用任何旧语言编写繁重的计算资料,如果需要一段时间,他们会在一些廉价的计算集群上找到时间.摩尔定律使我们所有人都变得愚蠢.
我将Fortran,C和C++的速度与netlib的经典Levine-Callahan-Dongarra基准进行比较.使用OpenMP的多语言版本是 http://sites.google.com/site/tprincesite/levine-callahan-dongarra-vectors C更加丑陋,因为它从自动翻译开始,加上限制和编译指示的插入编译器.在适用的情况下,C++只是带有STL模板的C. 在我看来,STL是否能提高可维护性.
只需极少量的自动函数内嵌运算即可了解它在多大程度上改进了优化,因为这些示例基于传统的Fortran实践,其中很少依赖于内嵌.
迄今为止使用最广泛的C/C++编译器缺乏自动向量化,这些基准测试依赖于自动向量化.
重新发布之前的帖子:有几个例子,其中在Fortran中使用括号来指示更快或更准确的评估顺序.已知的C编译器没有选项来观察括号而不禁用更重要的优化.
我是一个业余爱好者,而且我对这两种语言都很"平均".我发现编写快速Fortran代码比编写C(或C++)代码更容易.Fortran和C都是"历史性"语言(按今天标准),使用频繁,并且支持免费和商业编译器.
我不知道这是否是一个历史事实,但Fortran觉得它的构建是并行/分布式/矢量化/无论多少核心化.今天,当我们谈论速度时,它几乎就是"标准指标":"它是否会扩展?"
对于纯粹的cpu运算,我喜欢Fortran.对于与IO相关的任何事情,我发现使用C更容易(无论如何都很困难).
当然,对于并行数学密集型代码,您可能希望使用GPU.C和Fortran都有很多或多或少集成的CUDA/OpenCL接口(现在是OpenACC).
我的客观答案是:如果你对这两种语言同样好/差,那么我认为Fortran更快,因为我发现在Fortran中编写并行/分布式代码比在C中更容易.(一旦你明白你可以编写"自由形式"fortran和不只是严格的F77代码)
对于那些愿意投票给我的人来说,这是第二个答案,因为他们不喜欢第一个答案:两种语言都具有编写高性能代码所需的功能.所以它取决于您正在实施的算法(CPU密集型?密集型?内存密集型?),硬件(单CPU?多核?分发超级计算机?GPGPU?FPGA?),您的技能以及最终编译器本身.C和Fortran都有很棒的编译器.(我很惊讶Fortran编译器的先进性,但C编译器也是如此).
PS:我很高兴您明确地排除了libs,因为我对Fortran GUI库有很多不好的说法.:)
我用FORTRAN和C做了几年的广泛数学.根据我自己的经验,我可以说FORTRAN有时候确实比C好,但不是因为它的速度(可以通过使用适当的编码风格使C表现得像FORTRAN一样快),而是因为LAPACK等非常优化的库,并且因为很好的并行化.在我看来,FORTRAN真的很难处理,它的优点还不足以取消这个缺点,所以现在我使用C + GSL进行计算.
我没有听说Fortan比C快得多,但可以想象在某些情况下它会更快.关键不在于存在的语言特征,而在于(通常)不存在的语言特征.
一个例子是C指针.C指针几乎无处不在,但指针的问题在于编译器通常无法判断它们是否指向同一数组的不同部分.
例如,如果您编写了一个如下所示的strcpy例程:
strcpy(char *d, const char* s) { while(*d++ = *s++); }
编译器必须在假设d和s可能是重叠数组的情况下工作.因此,当阵列重叠时,它无法执行会产生不同结果的优化.正如您所期望的那样,这极大地限制了可以执行的优化类型.
[我应该注意到C99有一个"restrict"关键字,它明确告诉编译器指针不重叠.另请注意,Fortran也有指针,语义与C语言不同,但指针并不像C中那样普遍存在.
但回到C vs. Fortran问题,可以想象Fortran编译器能够执行一些(直接编写的)C程序可能无法实现的优化.所以我对这个说法不会感到惊讶.但是,我确实希望性能差异不会那么大.[〜5-10%]
快速而简单: 两者都同样快,但Fortran更简单. 最终真的更快取决于算法,但无论如何都没有相当大的速度差异.这是我在2015年德国Stuttgard高性能计算中心的Fortran研讨会上学到的.我与Fortran和C共同工作并分享了这一观点.
说明:
C旨在编写操作系统.因此,它具有比编写高性能代码所需的更多自由度.一般情况下这没有问题,但如果没有仔细编程,可以轻松减慢代码速度.
Fortran专为科学编程而设计.出于这个原因,它支持在语法上编写快速代码,因为这是Fortran的主要目的.与公众舆论相反,Fortran不是一种过时的编程语言.它的最新标准是2010年,并且定期发布新的编译器,因为大多数高性能代码都是在Fortran中编写的.Fortran进一步支持现代功能作为编译器指令(在C pragma中).
示例: 我们希望将一个大型结构作为函数的输入参数(fortran:subroutine).在函数内,参数不会改变.
C支持通过引用调用和按值调用,这是一个方便的功能.在我们的例子中,程序员可能会偶然使用按值调用.这会大大减慢速度,因为结构需要先在内存中复制.
Fortran只能通过引用调用,它强制程序员手动复制结构,如果他真的想要通过值操作调用.在我们的例子中,fortran将自动与C版本一样快,并通过引用调用.
Fortran和C之间的任何速度差异将更多地取决于编译器优化和特定编译器使用的基础数学库.Fortran没有什么内在的东西能让它比C更快.
无论如何,一个优秀的程序员可以用任何语言编写Fortran.
通常FORTRAN比C慢.C可以使用硬件级指针,允许程序员手动优化.FORTRAN(在大多数情况下)无法访问硬件内存寻址黑客.(VAX FORTRAN是另一个故事.)自70年代以来,我一直使用FORTRAN.(真.)
然而,从90年代开始,FORTRAN已经发展到包括特定的语言结构,可以优化为固有的并行算法,这些算法可以真正在多核处理器上尖叫.例如,自动矢量化允许多个处理器同时处理数据向量中的每个元素.16个处理器 - 16个元素矢量 - 处理需要1/16的时间.
在C中,您必须管理自己的线程并仔细设计算法以进行多处理,然后使用一堆API调用来确保并行性正确发生.
在FORTRAN中,您只需仔细设计算法以进行多处理.编译器和运行时可以为您处理其余的事情.
您可以阅读一些关于高性能Fortran的内容,但是您会发现很多死链接.你最好阅读并行编程(如OpenMP.org)以及FORTRAN如何支持它.
更快的代码并不能完全由语言决定,而是编译器,因此您可以看到ms-vb“ compiler”生成“肿,较慢且冗余的目标代码,这些目标代码在” .exe“内捆绑在一起,但是powerBasic生成的方式也是如此更好的代码。由C和C ++编译器生成的目标代码是在某些阶段(至少2个阶段)生成的,但是根据设计,大多数Fortran编译器至少有5个阶段(包括高级优化),因此根据设计,Fortran将始终具有生成高度优化的代码的能力。因此,最后是编译器而不是您应该使用的语言,我所知道的最好的编译器是Intel Fortran编译器,因为您可以在LINUX和Windows上获得它,并且可以将VS用作IDE,如果您正在寻找一个便宜的编译器,您可以随时在OpenWatcom上转播。
有关此的更多信息:http : //ed-thelen.org/1401Project/1401-IBM-Systems-Journal-FORTRAN.html