trunc 函数是否很慢?

Is the trunc function very slow?

tl;dr: double b=a-(size_t)(a)double b=a-trunc(a)

我正在为图像实现旋转功能,我注意到 trunc 功能似乎非常慢。

图像的循环代码,像素的实际影响在性能测试中被注释掉了,所以我什至不访问像素。

double sina(sin(angle)), cosa(cos(angle));
int h = (int) (_in->h*cosa + _in->w*sina);
int w = (int) (_in->w*cosa + _in->h*sina);
int offsetx = (int)(_in->h*sina);

SDL_Surface* out = SDL_CreateARGBSurface(w, h); //wrapper over SDL_CreateRGBSurface

SDL_FillRect(out, NULL, 0x0);//transparent black
for (int y = 0; y < _in->h; y++)
    for (int x = 0; x < _in->w; x++){
            //calculate the new position
            const double destY = y*cosa + x*sina;
            const double destX = x*cosa - y*sina + offsetx;

所以这是使用 trunc

的代码
size_t tDestX = (size_t) trunc(destX);
size_t tDestY = (size_t) trunc(destY);
double left = destX - trunc(destX);
double top = destY - trunc(destY);

这是更快的等价物

size_t tDestX = (size_t)(destX);
size_t tDestY = (size_t)(destY);
double left = destX - tDestX;
double top = destY - tDestY;

答案建议在转换回整数时不要使用 trunc 所以我也尝试了这种情况:

size_t tDestX = (size_t) (destX);
size_t tDestY = (size_t) (destY);
double left = destX - trunc(destX);
double top = destY - trunc(destY);

快速版本似乎平均需要 30 毫秒来浏览完整图像 (2048x1200),而使用 trunc 的慢速版本处理同一图像大约需要 135 毫秒。只有两次调用 trunc 的版本仍然比没有调用的版本慢得多(大约 100 毫秒)。

据我了解 C++ 规则,两个表达式应该 return 始终是同一件事。我在这里错过了什么吗? dextXdestY 被声明为 const 因此只应调用一次 trunc 函数,即使那样它本身也不能解释超过三倍的慢因素。

我正在使用 Visual Studio 2013 进行优化编译 (/O2)。是否有任何理由使用 trunc 函数?即使使用整数来获取小数部分似乎也更快。

按照您的使用方式,您根本没有理由使用 trunc function。它将双精度转换为双精度,然后将其转换为积分并丢弃。替代方案更快这一事实并不令人惊讶。

在现代 x86 CPUs 上,int <-> float 转换非常快 - 通常会为转换生成内联 SSE 代码,成本约为几个指令周期。1

但是 trunc 需要函数调用,而且函数调用本身的开销几乎肯定大于内联 float -> int 转换的开销。此外,trunc 函数本身可能成本相对较高——它必须完全符合 IEEE-754,因此必须正确处理整个范围的浮点值,如 NaN、INF、 denorms,超出范围的值等。所以总的来说,我预计 trunc 的成本约为数十个指令周期,即比内联浮点数的成本大一个数量级左右-> 整数转换。


1. 请注意,float <-> int 转换并不总是很便宜 - 其他 CPU 系列,甚至更早的 x86 CPUs,可能没有 ISA 支持此类转换,在这种情况下,库函数将通常使用,成本与 trunc 相似。现代 x86 CPUs 是这方面的特例。