这是一段非常频繁调用的代码,是我尝试优化的卷积算法的一部分(从技术上讲,它是我的第一次通过优化,而且我已经将速度提高了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 = 3
和shape = { 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)。
该函数有效地返回多维索引中“前导”零的数量,并且设计为避免需要在每个增量上完全转换为数组索引。
我能用这个功能做些什么来使它本身更快?是否有一种聪明的方法可以避免%
,或者另一种计算“角落等级”的方法 - 如果它有一个我不知道的更正式的名字,就会道歉。 。
答案 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];
}
}
同时尝试将pos
和divisor
声明为可能的最小类型。如果它们永远不会超过255,您可以使用unsigned char
。我知道有些处理器可以比较大的数字更快地执行除数,但你必须适当地设置变量类型。