如何在 C 中执行无分支条件算术运算?

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抽象机不读取或写入的可能共享对象的写入,这可能会引入数据竞争并影响其他线程存储的值。

use*_*248 6

一个基本的答案是生成一个无分支表达式,该表达式的计算结果为yif cistrue或运算的同一性(0 表示加法/减法,1 表示乘法/除法),否则然后使用该表达式。

选项 1:乘以布尔值

一个非常简单的解决方案是将布尔值乘以y然后相加:

x += c*y;
Run Code Online (Sandbox Code Playgroud)

选项 2:按位逻辑

从布尔值按位与创建一个掩码,然后添加:

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)

  • @0___________ 问题中将 `c` 指定为 `bool` 类型,这意味着它保证具有值 0 或 1。 (2认同)