gpt4 book ai didi

c++ - clang++/g++/gfortran之间的简单测试用例

转载 作者:可可西里 更新时间:2023-11-01 17:58:43 34 4
gpt4 key购买 nike

我在 scicomp 上遇到了这个问题这涉及计算总和。在那里,你可以看到 c++和类似的 fortran执行。有趣的是,我看到 Fortran 版本的速度提高了大约 32%。

我想,我不确定他们的结果,并试图重振局面。这是我运行的(非常轻微的)不同代码:

C++

#include <iostream>
#include <complex>
#include <cmath>
#include <iomanip>

int main ()
{
const double alpha = 1;
std::cout.precision(16);

std::complex<double> sum = 0;
const std::complex<double> a = std::complex<double>(1,1)/std::sqrt(2.);
for (unsigned int k=1; k<10000000; ++k)
{
sum += std::pow(a, k)*std::pow(k, -alpha);

if (k % 1000000 == 0)
std::cout << k << ' ' << sum << std::endl;
}

return 0;
}

语言

implicit none
integer, parameter :: dp = kind(0.d0)
complex(dp), parameter :: i_ = (0, 1)

real(dp) :: alpha = 1
complex(dp) :: s = 0
integer :: k
do k = 1, 10000000
s = s + ((i_+1)/sqrt(2._dp))**k * k**(-alpha)
if (modulo(k, 1000000) == 0) print *, k, s
end do
end

我在 Ubuntu 12.04 LTS 机器上使用 gcc 4.6.3clang 3.0 编译上述代码,所有代码都带有 -O3 标志。这是我的时间安排:

time ./a.out

gfortran

real    0m1.538s
user 0m1.536s
sys 0m0.000s

g++

real    0m2.225s
user 0m2.228s
sys 0m0.000s

clang

real    0m1.250s
user 0m1.244s
sys 0m0.004s

有趣的是,当使用 gcc 时,我还可以看到 fortran 代码比 c++ 快大约相同的 32%。但是,使用 clang,我可以看到 c++ 代码实际上运行速度提高了大约 19%。这是我的问题:

  1. 为什么 g++ 生成的代码比 gfortran 慢?因为它们来自同一个编译器系列,这是否意味着(这个)fortran 代码可以简单地转换成更快的代码? Fortran 与 C++ 通常是这种情况吗?
  2. 为什么 clang 在这里做得这么好?是否有用于 llvm 编译器的 fortran 前端?如果有,那一个生成的代码会更快吗?

更新:

使用 -ffast-math -O3 选项生成以下结果:

gfortran

real    0m1.515s
user 0m1.512s
sys 0m0.000s

g++

real    0m1.478s
user 0m1.476s
sys 0m0.000s

clang

real    0m1.253s
user 0m1.252s
sys 0m0.000s

Npw g++ 版本的运行速度和 gfortran 一样快,而且 clang 比两者都快。在上述选项中添加-fcx-fortran-rules 不会显着改变结果

最佳答案

时间差异会与执行pow的时间有关,因为其他代码比较简单。您可以通过分析来检查这一点。那么问题是编译器如何计算幂函数?

我的计时:使用 gfortran -O3 的 Fortran 版本约为 1.20 秒,使用 g++ -O3 -ffast-math 编译的 C++ 版本为 1.07 秒。请注意,-ffast-math 对于 gfortran 无关紧要,因为 pow 将从库中调用,但它对g++

在我的例子中,对于 gfortran,调用的是函数 _gfortran_pow_c8_i4 ( source code )。它们的实现是计算整数幂的常用方法。另一方面,对于 g++,它是 libstdc++ 库中的一个函数模板,但我不知道它是如何实现的。显然,它的编写/优化稍微好一些。考虑到它是一个模板,我不知道该函数在多大程度上是即时编译的。对于它的值(value),使用 ifort 编译的 Fortran 版本和使用 icc 编译的 C++ 版本(使用 -fast 优化标志)都给出相同的计时,所以我猜它们使用相同的库函数。

如果我只是在 Fortran 中用复杂的算术(显式地写出实部和虚部)编写一个幂函数,它的速度与使用 g++ 编译的 C++ 版本一样快(但是 -ffast -math 会减慢它的速度,所以我坚持只使用 -O3gfortran):

complex(8) function pow_c8_i4(a, k)
implicit none

integer, intent(in) :: k
complex(8), intent(in) :: a

real(8) :: Re_a, Im_a, Re_pow, Im_pow, tmp
integer :: i

Re_pow = 1.0_8
Im_pow = 0.0_8
Re_a = real(a)
Im_a = aimag(a)
i = k

do while (i.ne.0)
if (iand(i,1).eq.1) then
tmp = Re_pow
Re_pow = Re_pow*Re_a-Im_pow*Im_a
Im_pow = tmp *Im_a+Im_pow*Re_a
end if
i = ishft(i,-1)
tmp = Re_a
Re_a = Re_a**2-Im_a**2
Im_a = 2*tmp*Im_a
end do
pow_c8_i4 = cmplx(Re_pow,Im_pow,8)
end function

根据我的经验,在 Fortran 实现中使用显式实部和虚部会更快,尽管使用复数类型当然非常方便。

最后说明:尽管这只是一个示例,但每次迭代调用幂函数的方式效率极低。相反,您当然应该在每次迭代时将 a 乘以自身。

关于c++ - clang++/g++/gfortran之间的简单测试用例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16639579/

34 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com