3

我正在尝试使用按位运算确定下一个和上一个偶数。

例如,对于下一个功能:

x    nextEven(x)
1       2
2       2
3       4
4       4

对于以前的:

x    previousEven(x)
1       0
2       2
3       2
4       4

我有这样的nextEven功能的想法:value = ((value+1)>>1)<<1;

对于previousEven功能,例如:value = ((value)>>1)<<1

有更好的方法吗?无需比较和查看值是偶数还是奇数。

谢谢你。

4

6 回答 6

4

执行右移后左移以清除 LSB 效率不高。

我会使用类似的东西:

previous: value &= ~1;
next: value = (value +1) & ~1;

can(并且通常会)在~1编译时预先计算,因此previous在运行时将最终作为单个按位操作。最终next可能会成为两个操作(增量,and),但仍然应该很快。

您可以从这些转变中获得的最大希望是编译器将认识到您显然只是 LSB,并将其优化到您期望它无论如何都会产生的结果。

于 2013-05-23T05:09:22.510 回答
3

你可以做这样的事情

对于以前的甚至

unsigned prevev(unsigned x)
{
    return x-(x%2);//bitwise counterpart x-(x&1);
}

下一个甚至

unsigned nxtev(unsigned x)
{
    return (x%2)+x; //bitwise counterpart x+(x&1);
}
于 2013-05-23T05:20:25.367 回答
1

假设您正在使用unsigned ints, previous even (匹配您的值 - 我们可以争论 2 的前一个 even 是否应该是 0 等)只是x & ~1u. 下一个偶数是 x + 1 的前一个偶数。

于 2013-05-23T05:06:56.107 回答
1

Duff's Device 之类的技巧,或者用 XOR 交换两个变量,或者用按位运算计算下一个和上一个偶数看起来很聪明,但它们很少。

作为开发人员,您可以做的最好的事情是首先优化可读性,并且只有在您确定导致实际问题的特定瓶颈时才解决性能问题。

获取前一个偶数的最佳代码(根据您的定义,前一个偶数 2 为 2)只需编写如下内容:

if ((num % 2) == 1) num--; // num++ for next.

或(稍微高级一点):

num -= num % 2;            // += for next.

并让疯狂的优化编译器找出最佳的底层代码。

除非您需要每秒执行数十亿次这些操作,否则可读性应该始终是您最关心的问题。

于 2013-05-23T05:12:13.707 回答
1

以前的偶数:
对于以前的偶数,我更喜欢Jerry Coffin回答

// Get previous even number
unsigned prevEven(unsigned no)
{
    return (no & ~1);
}

下一个偶数:
我尝试只使用按位运算符,但我仍然使用一个一元减号(-)运算符来获得下一个数字。

// Get next even number
unsigned nextEven(unsigned no)
{
    return (no & 1) ? (-(~no)) : no ;
}

方法 nextEven() 的工作:

  • 如果数字是偶数,则返回相同的数字,
    如果不是,则它的 LSB 是,0否则1
    获取数字的 LSB =>number & 1
  • 如果数字是奇数,则返回数字 + 1,
    数字加 1 =>-(~number)
于 2013-05-23T07:59:27.997 回答
0
unsigned int previous(unsigned int x)
{
    return x & 0xfffffffe;
}

unsigned int next(unsigned int x)
{
   return previous(x + 2);
}
于 2013-05-23T05:49:07.533 回答