我在某处读到,在可能的情况下使用按位运算符而不是if语句会更快。我正在研究一个图像处理项目,我有各种方法可以对像素进行数学运算。例如,当我添加一个像素时,我会检查并确保总和不会超过最大值。我把它改成了......
Pixel16 operator+(Pixel16 p) const noexcept
{
uint_fast32_t r = red + p.red;
uint_fast32_t g = green + p.green;
uint_fast32_t b = blue + p.blue;
return Pixel16(r | -(r > 0xffff), g | -(g > 0xffff), b | -(b > 0xffff));
}
你们认为这比编写像...这样的陈述更快吗?
if(r > 0xffff)
r = 0xffff;
FYI红色,绿色和蓝色是uint16_t
类型的成员变量答案 0 :(得分:2)
#include <algorithm>
#include <cstdint>
struct Pixel16 {
uint16_t red;
uint16_t blue;
uint16_t green;
Pixel16(uint16_t red, uint16_t green, uint16_t blue);
};
Pixel16 v1(Pixel16 const & p, Pixel16 const & s) {
uint_fast32_t r = p.red + s.red;
uint_fast32_t g = p.green + s.green;
uint_fast32_t b = p.blue + s.blue;
return Pixel16(r | -(r > 0xffff), g | -(g > 0xffff), b | -(b > 0xffff));
}
Pixel16 v2(Pixel16 const & p, Pixel16 const & s) {
uint_fast32_t r = p.red + s.red;
uint_fast32_t g = p.green + s.green;
uint_fast32_t b = p.blue + s.blue;
r = std::min(r, (uint_fast32_t) 0xFFFF);
g = std::min(g, (uint_fast32_t) 0xFFFF);
b = std::min(b, (uint_fast32_t) 0xFFFF);
return Pixel16(r, g, b);
}
OS X上的Clang将为v1
和v2
生成功能相同的代码。唯一的区别是,对min()
的调用和v1
中的等效工作的顺序以不同的顺序发生。
在这两种情况下,都没有分支。
编写最易理解的代码。使用函数和语言功能以可读的方式表达您的代码。您的按位代码是否比min()
函数更具可读性?
答案 1 :(得分:1)
几乎在所有情况下&#34;更快&#34;将在很大程度上取决于目标系统和使用的编译器,以及运算符可能如何过载。但是,在这种情况下,我非常怀疑会有那么大的差别,因为你仍然使用比较运算符,这应该是比简单的if
分支更昂贵的操作。
上面列出的代码困扰着我。否定比较操作的结果(布尔操作,除非您已经覆盖了操作符)并不是按位或者像您一样安全的操作。此外,它很难理解,这意味着以后某人很难维持。然而,if
版本解释了发生了什么。
答案 2 :(得分:0)
要知道,您必须衡量(配置代码)。
关于为什么按位运算可能更快的理论是,分支预测失败可能是一个重要的性能损失。通过使用按位运算而不是控制流程开关,您可以完全避免条件分支,因此您永远不会在那里发生分支预测错过。
根据具体情况,计算而不是分支也可能稍微缓存一下。
但除非你测量,否则你不会知道实际效果。简单分析代码的因素太多了。