优化数学表达式

时间:2015-04-02 19:31:25

标签: c++ c optimization

我很沮丧fitch软件花了多少时间做一些简单的计算。我使用英特尔VTune对其进行了分析,似乎有52%的CPU时间花在nudists()函数上:

void nudists(node *x, node *y)
{
  /* compute distance between an interior node and tips */
  long nq=0, nr=0, nx=0, ny=0;
  double dil=0, djl=0, wil=0, wjl=0, vi=0, vj=0;
  node *qprime, *rprime;

  qprime = x->next;
  rprime = qprime->next->back;
  qprime = qprime->back;
  ny = y->index;
  dil = qprime->d[ny - 1];
  djl = rprime->d[ny - 1];
  wil = qprime->w[ny - 1];
  wjl = rprime->w[ny - 1];
  vi = qprime->v;
  vj = rprime->v;
  x->w[ny - 1] = wil + wjl;
  if (wil + wjl <= 0.0)
    x->d[ny - 1] = 0.0;
  else
    x->d[ny - 1] = ((dil - vi) * wil + (djl - vj) * wjl) / (wil + wjl);
  nx = x->index;
  nq = qprime->index;
  nr = rprime->index;
  dil = y->d[nq - 1];
  djl = y->d[nr - 1];
  wil = y->w[nq - 1];
  wjl = y->w[nr - 1];
  y->w[nx - 1] = wil + wjl;
  if (wil + wjl <= 0.0)
    y->d[nx - 1] = 0.0;
  else
    y->d[nx - 1] = ((dil - vi) * wil + (djl - vj) * wjl) / (wil + wjl);
}  /* nudists */

两条长行占CPU总时间的24%。有没有办法优化这个代码,尤其是两条长线?消耗大量CPU时间的另一个功能是:

void secondtraverse(node *q, double y, long *nx, double *sum)
{
  /* from each of those places go back to all others */
   /* nx comes from firsttraverse */
   /* sum comes from evaluate via firsttraverse */
  double z=0.0, TEMP=0.0;

  z = y + q->v;
  if (q->tip) {
    TEMP = q->d[(*nx) - 1] - z;
    *sum += q->w[(*nx) - 1] * (TEMP * TEMP);
  } else {
    secondtraverse(q->next->back, z, nx, sum);
    secondtraverse(q->next->next->back, z, nx,sum);
  }
}  /* secondtraverse */

计算总和的代码占CPU时间的18%。有什么方法可以让它跑得更快?

完整的源代码可以在这里找到:http://evolution.genetics.washington.edu/phylip/getme.html

1 个答案:

答案 0 :(得分:1)

就优化大方程线而言,您正在使用一些最耗时的操作:乘法和除法。

您必须在更大的框架,图片或范围内寻找优化。一些想法:

  • 固定点算术
  • 消除每次迭代的划分。
  • 线程
  • 多核心
  • 数组,不是链接列表

定点算术

如果您可以使数字基数为2的幂,那么您的许多分区将变为位移。例如,除以16与右移4次相同。转移通常比分裂更快。

每次迭代消除除法

不是在每次迭代中执行除法,而是将其解压缩并更少地执行,可能使用不同的值。

如果将除法视为分数,则可以在除以分母之前多次使用分子。

线程

您可能需要考虑多个线程。根据代码效率创建线程。让一个线程成为在后台计算的工作线程。

多核(并行执行)

&#39; x&#39;并且&#39; y&#39;变量似乎彼此独立。可以为并行编程设置这些计算。一个核心或处理器执行&#39; x&#39;计算,而另一个核心是计算&#39; y&#39;变量。

考虑将其拆分为更高级别。一个核心(线程)处理所有&#39; x&#39;变量,而另一个核心处理&#39; y&#39;变量。结果独立保存。让主核心在所有&#39; x&#39;之后处理所有结果。并且&#39; y&#39;变量已经计算出来。

数组,不是列表

当所有数据都适合处理器的数据缓存时,您的处理器将会非常开心。如果它不能适合所有数据,那么尽可能适合。因此,与链表相比,数组最适合数据缓存行。处理器将知道阵列地址是顺序的,并且可能不必重新加载数据高速缓存。