这是一个非常频繁调用的代码的一小部分,也是我试图优化的卷积算法的一部分(从技术上讲,它是我的第一次通过优化,我已经将速度提高了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给出的索引偏移量,下面的数字给出多维索引.编辑:下面我已经放置了函数返回的值(值为2,返回位置12,24和36).
该函数有效地返回多维索引中“前导”零的数量,并且设计为避免需要在每个增量上完全转换为数组索引.
我能用这个功能做些什么来使它本身更快?是否有一种聪明的方法可以避免%,或者另一种计算“角落等级”的方法 – 如果它有一个我不知道的更正式的名字,就会道歉. . .
最佳答案 你应该返回max_ranks的唯一时间是pos等于零.检查此项允许您从for循环中删除条件检查.这应该改善最坏情况的完成时间和max_ranks的大值的循环速度.
这是我的补充,另外还有一种避免分割操作的方法.我相信这和@twalberg建议的手写div一样快,除非有一些方法可以在没有第二次乘法的情况下产生余数.
我担心,因为最常见的答案是0(甚至没有通过第一次调用),你不会看到太多改进.我的猜测是你的平均运行时间非常接近模数函数本身的运行时间.您可以尝试搜索更快的方法来确定数字是否是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和除数声明为可能的最小类型.如果它们永远不会超过255,则可以使用unsigned char.我知道有些处理器可以比较大的数字更快地执行除数,但你必须适当地设置变量类型.