优化 "i = b ? (i | mask) : (i & ~mask)"
Optimising "i = b ? (i | mask) : (i & ~mask)"
我希望能够设置或清除 uintX_t t
的(多个)位。
i
是一个运行时变量 (uintX_t
)。
b
是一个运行时变量 (uintX_t
),它被限制为 0
或 1
.
mask
是编译时常量。
有没有更好的方法:
i = b ? (i | mask) : (i & ~mask)
如果可能的话,我希望避免分支。如果重要的话,目标是 ARM。
这里的想法是用乘法代替分支,我们可以根据 b 的值将每一边归零:
i = (i | (mask * b)) & (~mask | (mask * b));
另一种选择:始终将位设置为 0(左侧部分)并可选择将位设置为 1(右侧部分)。
i = (i & ~mask) | (mask * b);
利用 -1u
是设置了所有位的值这一事实:
i = (i & ~mask) | (mask & -b);
或
i ^= (i ^ -b) & mask;
第二种方法减少了操作次数和代码大小。第一种方法在超标量架构上可能仍然更快,因为一些操作可以并行执行。
最易读的方法是分几个步骤执行此操作 - 这样做不会影响性能,但会提高可读性。
与按位运算符一样,您必须小心隐式类型提升。例如,不小心使用 ~
往往会产生隐式提升错误。 (?:
运算符还通过平衡第二个和第三个操作数来默默地提升结果。)
可读、可移植、安全的代码:
uintx_t i = ... ;
uintx_t b = ... ; // 1 or 0
i &= (uintx_t)~mask; // always clear the bit
i |= mask * b; // if b is 1, set the bit, otherwise OR with 0
我希望能够设置或清除 uintX_t t
的(多个)位。
i
是一个运行时变量 (uintX_t
)。
b
是一个运行时变量 (uintX_t
),它被限制为 0
或 1
.
mask
是编译时常量。
有没有更好的方法:
i = b ? (i | mask) : (i & ~mask)
如果可能的话,我希望避免分支。如果重要的话,目标是 ARM。
这里的想法是用乘法代替分支,我们可以根据 b 的值将每一边归零:
i = (i | (mask * b)) & (~mask | (mask * b));
另一种选择:始终将位设置为 0(左侧部分)并可选择将位设置为 1(右侧部分)。
i = (i & ~mask) | (mask * b);
利用 -1u
是设置了所有位的值这一事实:
i = (i & ~mask) | (mask & -b);
或
i ^= (i ^ -b) & mask;
第二种方法减少了操作次数和代码大小。第一种方法在超标量架构上可能仍然更快,因为一些操作可以并行执行。
最易读的方法是分几个步骤执行此操作 - 这样做不会影响性能,但会提高可读性。
与按位运算符一样,您必须小心隐式类型提升。例如,不小心使用 ~
往往会产生隐式提升错误。 (?:
运算符还通过平衡第二个和第三个操作数来默默地提升结果。)
可读、可移植、安全的代码:
uintx_t i = ... ;
uintx_t b = ... ; // 1 or 0
i &= (uintx_t)~mask; // always clear the bit
i |= mask * b; // if b is 1, set the bit, otherwise OR with 0