为什么floor()这么慢?

33 c performance x86 intel visual-c++

我最近写了一些代码(ISO/ANSI C),并对它所取得的糟糕表现感到惊讶.长话短说,事实证明罪魁祸首就是这个floor()功能.它不仅速度慢,而且没有矢量化(使用英特尔编译器,也称为ICL).

以下是为2D矩阵中的所有单元格执行底板的一些基准:

VC:  0.10
ICL: 0.20
Run Code Online (Sandbox Code Playgroud)

将其与简单的演员比较:

VC:  0.04
ICL: 0.04
Run Code Online (Sandbox Code Playgroud)

怎么会floor()比简单演员慢得多?!它基本上是相同的(负数除外).第二个问题:有人知道超快的floor()实施吗?

PS:这是我进行基准测试的循环:

void Floor(float *matA, int *intA, const int height, const int width, const int width_aligned)
{
    float *rowA=NULL;
    int   *intRowA=NULL;
    int   row, col;

    for(row=0 ; row<height ; ++row){
        rowA = matA + row*width_aligned;
        intRowA = intA + row*width_aligned;
#pragma ivdep
        for(col=0 ; col<width; ++col){
            /*intRowA[col] = floor(rowA[col]);*/
            intRowA[col] = (int)(rowA[col]);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Nil*_*nck 42

一些事情比投射更慢,防止矢量化.

最重要的一个:

楼层可以修改全局状态.如果传递的值太大而无法以float格式表示为整数,则errno变量将设置为EDOM.还完成了对NaN的特殊处理.所有这些行为都适用于想要检测溢出情况并以某种方式处理情况的应用程序(不要问我怎么做).

检测这些有问题的条件并不简单,占地面执行时间的90%以上.实际的舍入很便宜,可以内联/矢量化.此外,它还有很多代码,因此内联整个函数会使您的程序运行速度变慢.

一些编译器具有特殊的编译器标志,允许编译器优化一些很少使用的c标准规则.例如,可以告诉GCC你根本不对errno感兴趣.这样做传递-fno-math-errno-ffast-math.ICC和VC可能有类似的编译器标志.

顺便说一句 - 您可以使用简单的演员阵容滚动自己的地板功能.你只需要以不同的方式处理消极和积极的情况.如果您不需要特殊处理溢出和NaN,那可能会快得多.


dgo*_*bbi 17

如果要将floor()操作的结果转换为int,并且如果您不担心溢出,则以下代码比以下代码快得多(int)floor(x):

inline int int_floor(double x)
{
  int i = (int)x; /* truncate */
  return i - ( i > x ); /* convert trunc to floor */
}
Run Code Online (Sandbox Code Playgroud)

  • 你应该使用`static inline`而不是`inline`如果你想将它放入头文件中 - 请参阅http://stackoverflow.com/a/10245969/48015 (2认同)

Pol*_*015 10

无枝地板和天花板(更好地利用pipiline)没有错误检查

int f(double x)
{
    return (int) x - (x < (int) x); // as dgobbi above, needs less than for floor
}

int c(double x)
{
    return (int) x + (x > (int) x);
}
Run Code Online (Sandbox Code Playgroud)

或使用地板

int c(double x)
{
    return -(f(-x));
}
Run Code Online (Sandbox Code Playgroud)