如何使这段代码更快(学习最佳实践)?

时间:2014-04-02 19:54:07

标签: c++ performance gcc

我在这里有一个小循环,我想知道我是否犯了一个大错误。

例如,有没有办法以不同的方式重写部分内容,以使矢量化成为可能(假设启用了GCC4.8.1和所有的联合友好标志)?

这是传递列表数字的最佳方法(const float name_of_var [])吗?

代码的想法是采用(未经数字的)y和两个绑定值(ox[0]<=ox[1])的向量(在数学意义上,而不是必需的std :: vector)和存储在整数向量rdx中,i条目的索引y满足ox [0]&lt; = y [i]&lt; = ox [1]。

rdx可以包含m个元素,而y可以包含nn>m。如果超过my[i]满足ox [0]&lt; = y [i]&lt; = ox [1]然后代码应该返回第一个m

提前致谢,

void foo(const int n,const int m,const float y[],const float ox[],int rdx[]){
    int d0,j=0,i=0;
    for(;;){
        i++;
        d0=((y[i]>=ox[0])+(y[i]<=ox[1]))/2;
        if(d0==1){
            rdx[j]=i;
            j++;
        }
        if(j==m)    break;
        if(i==n-1)  break;
    }
}

3 个答案:

答案 0 :(得分:1)

d0=((y[i]>=ox[0])+(y[i]<=ox[1]))/2;
if(d0==1)

我认为使用中间变量是没用的,并且需要多一些周期

这是我能想到的最优化的版本,但它完全不可读......

void foo(int n, int m, float y[],const float ox[],int rdx[])
{
    for(int i = 0; i < n && m != 0; i++)
    {
        if(*y >= *ox && *y <= ox[1])
        {
            *rdx=i;
            rdx++;
            m--;
        }
        y++;
    }
}

我认为以下版本具有合适的优化标志应该可以完成工作

void foo(int n, int m,const float y[],const float ox[],int rdx[])
{
    for(int j = 0, i = 0; j < m && i < n; i++) //Reorder to put the condition with the highest probability to fail first
    {
        if(y[i] >= ox[0] && y[i] <= ox[1])
        {
            rdx[j++] = i;
        }
    }
}

答案 1 :(得分:1)

只是为了确保我是正确的:你试图找到[ox [0]范围内的第一个m + 1(如果它实际上是m,做j == m-1)值,牛[1]]?

如果是这样,那不是更好:

for (int i=0, j=0;;++i) {
    if (y[i] < ox[0]) continue;
    if (y[i] > ox[1]) continue;
    rdx[j] = i;
    j++;
    if (j == m || i == n-1) break;
}
  1. 如果y [i]确实在范围内,则必须像我们一样进行两次比较。
  2. 如果y [i]在ox [0]之下,则无需执行第二次比较。
  3. 我避免使用分裂。

答案 2 :(得分:1)

一个。是的,将float数组作为float []传递不仅有效,而且是唯一的方法(并且与float *参数相同)。

A1。 但是在C ++中,您可以使用更好的类型而不会丢失性能。访问向量或数组(标准库容器)不应该比访问纯C样式数组慢。我强烈建议你使用它们。在现代C ++中,还可以使用迭代器和函子;我不是那里的专家,但是如果你能通过更抽象地表达不同元素上的操作的独立性,你可以让编译器有机会生成更适合矢量化的代码。

B中。您应该用逻辑AND,运算符&amp;&amp;替换除法。第一个优点是,如果第一个条件为假,则根本不评估第二个条件 - 这可能是您最重要的性能提升。第二个优点是表现力和可读性。

℃。使用-O3编译时,中间变量d0可能会消失,但它仍然是不必要的。

其余的表现都很好。如惯例所示,还有改进的余地。

d。我不确定使用此处提供的代码进行矢量化的可能性。编译器可能会在-O3处进行一些循环展开;尝试让它发出SSE代码(参见http://gcc.gnu.org/onlinedocs/,特别是http://gcc.gnu.org/onlinedocs/gcc-4.8.2/gcc/i386-and-x86-64-Options.html#i386-and-x86-64-Options)。谁知道。

哦,我刚刚意识到你的原始代码将常量间隔边界作为带有2个元素ox []的数组传递。由于阵列访问不必要的间接,因此可能带来开销,因此这里优选使用两个普通的浮点参数。保持它们像你的数组一样const。你也可以很好地命名它们。