有一些论点,在某些情况下,Fortran可能比C更快,例如,当涉及到别名时,我经常听说它比C更好地进行自动矢量化(请参阅here进行一些好的讨论)。
然而,对于简单的函数来计算Fibonaci数和Mandelbrot在一些复杂的数字与直接的解决方案没有任何技巧和额外的提示/关键字到编译器,我会期望他们真的执行相同。
C实施:
int fib(int n) {
return n < 2 ? n : fib(n-1) + fib(n-2);
}
int mandel(double complex z) {
int maxiter = 80;
double complex c = z;
for (int n=0; n<maxiter; ++n) {
if (cabs(z) > 2.0) {
return n;
}
z = z*z+c;
}
return maxiter;
}
Fortran实施:
integer, parameter :: dp=kind(0.d0) ! double precision
integer recursive function fib(n) result(r)
integer, intent(in) :: n
if (n < 2) then
r = n
else
r = fib(n-1) + fib(n-2)
end if
end function
integer function mandel(z0) result(r)
complex(dp), intent(in) :: z0
complex(dp) :: c, z
integer :: n, maxiter
maxiter = 80
z = z0
c = z0
do n = 1, maxiter
if (abs(z) > 2) then
r = n-1
return
end if
z = z**2 + c
end do
r = maxiter
end function
朱莉娅实施:
fib(n) = n < 2 ? n : fib(n-1) + fib(n-2)
function mandel(z)
c = z
maxiter = 80
for n = 1:maxiter
if abs(z) > 2
return n-1
end
z = z^2 + c
end
return maxiter
end
(可以找到包含其他基准功能的完整代码here。)
根据Julia homepage,Julia和Fortran(-O3
)在这两个函数上的表现优于C(-O3
)。
怎么可能?
答案 0 :(得分:7)
老实说,我不会太认真地对待这些差异。不同的C编译器也会给出不同的结果。尝试使用GCC和Clang运行C微基准测试,您将获得与C vs. Fortran差不多的差异。为什么GCC有时比Clang更快,有时候不是?他们只是以不同的方式进行不同的优化和代码生成。不同硬件的相对性能也不同,因为它可能取决于寄存器的确切数量,高速缓存大小,超标量吞吐量,各种指令的相对速度等。
很奇怪Fortran 如此对于基准测试来说要快得多,所以如果有人在那里找到一个并且在这里发布答案,我很乐意提出它,但是≤15%的差异关于曼德尔和其他基准测试并不是那么引人注目。关于这些基准测试,对我来说最神秘的是Fortran在整数解析方面的速度如此之慢。我怀疑这是因为代码是愚蠢的,但我不是Fortran编码器所以我不确定应该改进什么。如果有人读这篇文章是Fortran专业版,想看看this code,我们将不胜感激。我怀疑Fortran比C慢5倍是错误的。
需要注意的一点是,在整理这些基准测试结果时,我们会拒绝零时间,以避免计算编译器只是对整个计算进行常量折叠的情况。在一些优化级别上,这正是C和Fortran编译器所做的,并且很难强迫它们不要这样做,缺少使用较低的优化级别。如果有人想弄清楚如何在不完全优化基准代码的同时强制编译器不要不断地折叠这些结果,那将是一个受欢迎的贡献。 (一种可能的方法是使用完全优化将基准函数编译为共享库,然后在关闭链接时优化的情况下将其链接到主程序。这很棘手,但它可能有效。)
最终,对于精确的微基准数字过多担忧会让人眼前一亮。这些基准测试的重点是某些语言具有可靠的快速标准实现 - 如C,Fortran,Julia和Go - 而其他语言则不然。在慢速语言中,您有时不得不求助于使用不同的语言来获得所需的性能,而在可靠的快速语言中,您永远不必这样做。这就是所有这一切。快速语言的确切相对表现是一场军备竞赛:有时候一种语言可能会领先,但其他语言总会紧随其后 - 关键是他们在竞争中处于领先地位。