为什么这个简单的程序部分让我震惊了两个多小时?

时间:2014-02-03 13:41:46

标签: c++ c

我在下面粘贴了我的程序的一部分,为什么需要花费大量的时间来执行?

for(i=0;i<N;i++)
     {
     for(j=0;j<N;j++)
        {
         if(j<i) {
           pot[i]+=-(x[i]-x[j])*1./pow((pow(x[i]-x[j],2.)+ blah blah,1.5);
          }
         if(j>i) {
           pot[i]+=(x[i]-x[j])*1./pow((pow(x[i]-x[j],2.)+blah blah,1.5);
          }
        }
     }

运行差不多需要两个小时,如果我将1.5作为1.4,那么一切都会好的。

下面的那个非常精细

for(i=0;i<N;i++)
{
 pot[i]=0.0;
 for(j=0;j<N;j++)
    {
     if(j<i) 
      {
       pot[i]+=-1.*(x[i]-x[j])/pow(pow(x[i]-x[j],3.)+blah blah,1.);
      }
     if(j>i) 
      {
       pot[i]+=1.*(x[i]-x[j])/pow(pow(x[i]-x[j],1.)+blah blah,3.);
      }
    }
 }

/ *我非常需要我的程序中的前一个,而不是后来的一个* /

以上是该块的一部分

for(i=0;i<N;i++)
    {
    for(j=0;j<N;j++)
        {
            if(j<i)
                {
                pot[i]+=-(x[i]-x[j])*1./pow(fabs(pow(x[i]-x[j],2.)+ g*g*pow(x[i+N]-x[j+N],2.)+ h*h*pow(x[i+2*N]-x[j+2*N],2.)),1.5) ;
                }
            if(j>i)
                {
                pot[i]+=(x[i]-x[j])*1./pow(fabs(pow(x[i]-x[j],2.) + g*g*pow(x[i+N]-x[j+N],2.) + h*h*pow(x[i+2*N]-x[j+2*N],2.)),1.5) ;
                }
        }
    }

2 个答案:

答案 0 :(得分:5)

好吧,如果N为1000,它将执行pow两百万次。在这种情况下,pow会执行log,然后是乘法,然后是exp。这是沉重的代码。

我只想指出,如果您想知道,编译器优化对此代码没有帮助,因为程序计数器几乎所有时间都花在logexp上。

另外,正如@amon指出的那样,你可以摆脱一个pow电话,给出两倍的加速。

答案 1 :(得分:3)

按照目前的情况,你将对pow()产生2个N ** 2个调用。 pow()很昂贵,每次调用pow()都会调用log()和exp()。对于N = 1000,也就是说,正如另一个人观察到的那样,每次调用200万次log()和exp()。

log()和exp()本身很昂贵,是浮点幂级数扩展。

你的编译器知道像2.和3这样的数字实际上是小整数,并且知道如何将pow(x,N)(其中N是一个小整数)减少到适当的乘法系列,这是可能的。广场。这样可以大大减少第二个例子的运行时间。

Dijkstra曾经观察过(在一个研究生招募演讲中),演习的目标是“不要弄乱它”。观察pow(x,2)== x * x和pow(x,1.5)== x * sqrt(x),你可以通过定义两个(内联)函数并重写来摆脱大量的超越数字训练调用关键线:

    pot[i]+=(x[i]-x[j])*1./xsqrtx(square(x[i]-x[j])+blahblah);

另外,如果您实际上是在C / C ++中这样做,那么缓存点差可能是值得的。

    delta = x(i]-x[j];        
    pot[i]+=(delta)*1./xsqrtx(square(delta)+blahblah);

不允许C / C ++假设x在你不看时没有改变,并且进行这种特殊的常见子表达式优化。 (FORTRAN是,并且确实。)

最后,你知道你可以划分浮点数吗?

    delta = x(i]-x[j];        
    pot[i]+=(delta)/(xsqrtx(square(delta)+blahblah));