use*_*248 1 c bit-manipulation micro-optimization twos-complement branchless
我有一个值int x,我想有条件地添加(例如)一个值int y,具体取决于bool c. 我可以写这样的代码:
bool c; // C23, or stdbool.h macro for _Bool. Converts to integer 0 or 1
int x, y; // x could be a global or something
...
if (c)
x += y;
Run Code Online (Sandbox Code Playgroud)
如果没有分支我怎么能写这个?
ifx是一个没有其他线程可以引用的局部变量,如果编译器认为这样更有效,则可以将 if 转换为无分支。(特别是在自动向量化的情况下,但也适用于标量。)但这对于全局变量来说不是线程安全的,或者如果x实际上是*x带有int *. 编译器无法发明类似于*x += 0抽象机不读取或写入的可能共享对象的写入,这可能会引入数据竞争并影响其他线程存储的值。
一个基本的答案是生成一个无分支表达式,该表达式的计算结果为yif cistrue或运算的同一性(0 表示加法/减法,1 表示乘法/除法),否则然后使用该表达式。
一个非常简单的解决方案是将布尔值乘以y然后相加:
x += c*y;
Run Code Online (Sandbox Code Playgroud)
从布尔值按位与创建一个掩码,然后添加:
x += -c&y;
Run Code Online (Sandbox Code Playgroud)
这样,如果布尔值为 false,则对该值取反仍将是 0,并且对任何数字进行按位与 0 都会得到 0,因此这将导致该值加 0。否则,求反true将给出-12 的补码中全为 1,这将给出y按位与的后面,并与y相加x。
笔记:该问题以加法为例,但如果所讨论的运算是除法或乘法,则!c必须将值添加到增强赋值的右侧操作数。这是因为乘法恒等式是 1 而不是 0。
例如
x *= -c&y+!c;
Run Code Online (Sandbox Code Playgroud)