fortran计算真实*4的平方根与添加int的速度一样快



扰流板:测试程序对结果没有任何作用,因此通过优化编译器删除了循环的内容每次运行时间...无论如何,我会让问题和答案保留下来,以防万一某人(我?)犯同样的错误(再次...)。

原始文章:我想测试与简单添加相比,计算平方根的速度慢,并在下面编写了小程序。我得到的结果是,在这种情况下,它需要大约相同的时间,0.3秒。这里发生了什么?

program sqtest
implicit none
real r, s
integer i,j,n, sq, t
sq=11
n=100000000
r=1.11
if (sq==1) then
 do i = 1,n
  s = sqrt(float(i)*r)
 enddo
 write(*,*) "squareroot"
else
 do j = 1,n
  t = j+4
 enddo
 write(*,*) "plus"
endif

end program

sq=1使用平方根。平方根环ASO会产生乘法,并从int转换为float

进行此类测试时有很多事情要考虑。首先,您必须清楚地定义要比较的内容。对于这样的简单测试,您还应该停用优化,大多数主要编译器都接受选项-O0以停用优化。否则,编译器会发现您没有使用计算值进行任何操作,甚至没有运行循环,因为它没有用。

要简短剪切,我将您的程序修改为

program sqtest
implicit none
real r0, r1, r2, s
integer i,n
real :: start, finish

    n=10**9
    call random_number(r0)
    call random_number(r1)
    call random_number(r2)

    call cpu_time(start)
    do i = 1,n
        s = sqrt(r0)
    enddo
    call cpu_time(finish)
    print '("SQRT:      Time = ",f6.3," seconds.")',finish-start
    call cpu_time(start)
    do i = 1,n
        s = r1+r2
    enddo
    call cpu_time(finish)
    print '("Addtition: Time = ",f6.3," seconds.")',finish-start
end program

,它为我的系统提供了以下结果:

ifort 13, n = 10^8
SQRT:      Time =  0.378 seconds
Addtition: Time =  0.202 seconds
ifort 13, n = 10^9
SQRT:      Time =  3.460 seconds
Addtition: Time =  1.857 seconds
gfortran (GCC) 4.9, n = 10^8
SQRT:      Time =  0.385 seconds
Addtition: Time =  0.191 seconds
gfortran (GCC) 4.9, n = 10^9
SQRT:      Time =  3.529 seconds
Addtition: Time =  1.733 seconds
pgf90 14, n = 10^8
SQRT:      Time =  0.380 seconds
Addtition: Time =  0.058 seconds
pgf90 14, n = 10^9
SQRT:      Time =  3.438 seconds
Addtition: Time =  0.520 sec

您会注意到我在代码中调用CPU时间。为了使数字有意义,您应该多次运行每种情况并计算时间平均值或选择最小值。最低限度是您系统在最佳条件下所能达到的目标。您还将看到结果取决于编译器。PGF90显然可以在加法方面提供更好的结果。我从平方根上删除了float(i)*。GFORTRAN和PGF90的表现非常快(n = 10^9),而ifort的性能非常慢(n = 10^9的7.3秒)。这意味着Gfortran和PGF90以某种方式选择了不同的路径(更快的操作),也许它们可以进行一些优化?

您将在此文档中找到硬件平方根的成本:http://www.agner.org/optimize/instruction_tables.pdf。

可以以不同的方式计算SQRT。通常,这是一个仅涉及添加和乘以操作的迭代过程。通常将SQRT计算为SQRT(X)= X *(1/SQRT(X)),因为(1/SQRT(X))可以比SQRT(x)更快地计算。

如果您采用了Haswell CPU,则单个SQRTSS指令的延迟是单个精度为11个循环,双精度为16个周期(SQRTSD)。从单一的精确度中,与双重精度相比,它需要更少的迭代才能收敛到所需的精度。在同一CPU上,SQRT(RSQRTSS)的延迟为1周期,因此,如果您要求进行积极的优化,则编译器可能会选择生成此指令。

如果您需要多个独立的平方根,例如在示例中,则可以由编译器自动将代码矢量化。存在以相互吞吐量为14的矢量变体VSQRTP。在这种情况下,您的平均每平均每平方英尺大约得到14/8 = 1.75个循环。

参考:

  • https://en.wikipedia.org/wiki/fast_inverse_square_root
  • https://en.wikipedia.org/wiki/methods_of_computing_square_roots
  • 确定浮点平方根

也许您的编译器正在优化代码。您可以通过使用不同阶数(例如1E6、1E7、1E8,..,1E10)测量来测量这一点,并查看时间尺度。顺便说一句,您的机器/编译器上的整数允许范围是什么?

相关内容

最新更新