【问题标题】:Implementing if - else if using bitwise operators使用按位运算符实现 if - else if
【发布时间】:2013-05-28 13:17:43
【问题描述】:

假设test 的值为1 或0。在这里,我可以使用如下的位运算符来实现以下 if 语句。

if (test)
    output = a;
else
    output = b;

使用位运算符

output = (((test << 31) >> 31) & a) | (((test << 31) >> 31) & b);

现在我想使用位运算符实现以下 if 语句。

if (test1)
    output = a;
else if (test2)
    output = b;
else if (test3)
    output = c;
else
    output = d;

test1、test2、test3 的值是 0 或 1。

有什么建议吗?

【问题讨论】:

  • 可以不使用!吗?
  • + 不是位运算符。
  • 另外,这里没有循环。
  • test 的类型是什么?
  • @noufal:谢谢,但您还没有解决上面的第一条评论。这个要求的动机是什么?是回避分支、智力锻炼、家庭作业还是其他什么?

标签: c loops if-statement logic bit-manipulation


【解决方案1】:

我假设您的意思是您原来的 if 语句。

output = (((test << 31) >> 31) & a) | (((!test << 31) >> 31) & b);

不在 test 前面,因此当 test 为 1 时这不是 a+b,当 test 为 0 时不是 0,我将 + 替换为 | 因为每个案例都应该是 0,除了你想要的那个。

要执行级联 if else if else 语句,您可以重写表达式,以便 它们依赖于之前的测试。

if (test1)
    output = a
if (!test1 & test2)
    output = b
if (!test1 & !test2 & test3)
    output = c
if (!test1 & !test2 & !test3)
    output = d

这导致所有 if else if 的表达式都是这样的。

output = (((test1 << 31) >> 31) & a)
         | ((((!test1 & test2) << 31) >> 31) & b)
         | ((((!test1 & !test2 & test3) << 31) >> 31) & c)
         | ((((!test1 & !test2 & !test3) << 31) >> 31) & d)

【讨论】:

  • 为什么使用浪费且不可移植的 ((test > 31) 而不是 (test & 1) ?
  • @LeeDanielCrocker 它非常不便携,但它应该使真值 0xFFFFFFFF 和假值 0x00000000。发生这种情况是因为 test1 被假定为带符号的 32 位。将 1 一直移动到最高位置,然后将其向后移动会填充 1,因为计算机正在进行有符号移位。这不等于 (test & 1)
  • 那就是 (-(test & 1))。大转变似乎很浪费。
  • @LeeDanielCrocker 这会将 1 变为 0xFFFFFFFE,将 0 变为 0xFFFFFFFF。这些不一样。此外,&amp; 1 的测试毫无意义,因为根据问题假设测试为 0 或 1
  • 嗯,不,再看一遍。 (test & 1) 计算结果为 0 或 1,然后负号使其为 0 或 -1,即 0xFFFFFFFF。如果我们已经知道它是 0 还是 1,那就更好了,那么我们只需要 -test。
【解决方案2】:

是否有位运算符?怎么样:

output = (    test1) * a +
         (1 - test1) * ((    test2) * b +
                        (1 - test2) * ((    test3) * c +
                                       (1 - test3) * d));

另一种可能性,只使用位运算符,是这样的:

switch ((test1 << 2) | (test2 << 1) | test3) {
    case 0: output = d; break;
    case 1: output = c; break;
    case 2:
    case 3: output = b; break;
    case 4:
    case 5:
    case 6:
    case 7: output = a; break;
}

如果你很幸运(如果它加快了速度),编译器将使用跳转表来实现切换。

不过,您确实不得不质疑这些棘手的解决方案是否提供了足够的减速带(如果有的话)来证明额外的复杂性是合理的。我假设您正在尝试避免分支。

【讨论】:

    猜你喜欢
    • 2016-08-20
    • 1970-01-01
    • 2022-01-09
    • 1970-01-01
    • 2017-03-25
    • 2010-12-12
    • 2011-09-06
    • 2021-01-03
    • 1970-01-01
    相关资源
    最近更新 更多