在平顶多维数组中检测“角落等级”的有效方法

时间:2013-10-17 19:57:39

标签: c optimization

这是一段非常频繁调用的代码,是我尝试优化的卷积算法的一部分(从技术上讲,它是我的第一次通过优化,而且我已经将速度提高了2倍,但现在我我被卡住了:

inline int corner_rank( int max_ranks, int *shape, int pos ) {
  int i;
  int corners = 0;
  for ( i = 0; i < max_ranks; i++ ) {
    if ( pos % shape[i] ) break;
    pos /= shape[i];
    corners++;
  }
  return corners;
}

该代码用于计算N维数组中的位置pos的属性(已被展平为指针,加上算术)。 max_ranks是维度,shape是每个维度中的大小数组。

示例三维数组可能包含max_ranks = 3shape = { 3, 4, 5 }。前几个元素的原理图布局可能如下所示:

 0       1       2       3       4       5       6       7       8
 [0,0,0] [1,0,0] [2,0,0] [0,1,0] [1,1,0] [2,1,0] [0,2,0] [1,2,0] [2,2,0]

 Returned by function:
 3       0       0       1       0       0       1       0       0

第一行0..8显示由pos给出的索引偏移量,下面的数字给出了多维索引。编辑:在下面我已经放置了函数返回的值(在12,24和36位返回值2)。

该函数有效地返回多维索引中“前导”零的数量,并且设计为避免需要在每个增量上完全转换为数组索引。

我能用这个功能做些什么来使它本身更快?是否有一种聪明的方法可以避免%,或者另一种计算“角落等级”的方法 - 如果它有一个我不知道的更正式的名字,就会道歉。 。

1 个答案:

答案 0 :(得分:2)

如果max_ranks等于零,则应该返回pos的唯一时间。检查此项允许您从for循环中删除条件检查。这应该改善最坏情况的完成时间和max_ranks的大值循环的速度。

这是我的补充,另外还有一种避免分割操作的方法。我相信这和@twalberg建议的手写div一样快,除非有一些方法可以在没有第二次乘法的情况下产生余数。

我担心,因为最常见的答案是0(甚至没有超过第一个mod调用),你不会看到太多改进。我的猜测是你的平均运行时间非常接近模数函数本身的运行时间。您可以尝试搜索更快的方法来确定数字是否为pos的因子。你实际上并不需要计算余数;你只需知道是否是否为余数。

很抱歉,如果我通过重组您的代码让事情变得混乱。我相信除非您的编译器已经进行了这些优化,否则这会稍快一些。

inline int corner_rank( int max_ranks, int *shape, int pos ) {
  // Most calls will not get farther than this.
  if (pos % shape[0] != 0) return 0;

  // One check here, guarantees that while loop below always returns.
  if (pos == 0) return max_ranks;

  int divisor = shape[0] * shape[1];
  int i = 1;
  while (true) {
    if (pos % divisor != 0) return i;
    divisor *= shape[++i];
  }
}

同时尝试将posdivisor声明为可能的最小类型。如果它们永远不会超过255,您可以使用unsigned char。我知道有些处理器可以比较大的数字更快地执行除数,但你必须适当地设置变量类型。