Joã*_*ela 13 c c++ integer bit-manipulation
有时我需要确定某个整数是偶数.因此我可以使用以下代码:
int number = /* magic initialization here */;
// make sure the number is even
if ( number % 2 != 0 ) {
number--;
}
Run Code Online (Sandbox Code Playgroud)
但这似乎并没有被非常有效的最有效的方式做到这一点,所以我可以做到以下几点:
int number = /* magic initialization here */;
// make sure the number is even
number &= ~1;
Run Code Online (Sandbox Code Playgroud)
但(除了不可读)我不确定该解决方案是否完全可移植.
注意:此代码应该只适用于正整数,但有一个解决方案也适用于负数将是一个加号.
sus*_*att 31
就个人而言,我会使用内联辅助函数.
inline int make_even(int n)
{
return n - n % 2;
}
// ....
int m = make_even(n);
Run Code Online (Sandbox Code Playgroud)
我会使用第二种解决方案.在任何二进制表示中,无论位数,big-endian与little-endian或其他架构差异如何,该操作都将具有将最低位设置为零的效果.它快速且完全便携.如果遇到任何无法弄清楚它意味着什么的可怜C程序员,可以通过评论来解释代码的意图.
int even_number = (number / 2) * 2;
Run Code Online (Sandbox Code Playgroud)
只要优化器不妨碍(不应该但是谁知道),这应该适用于任何架构.
在接受答案之前,我将做自己的尝试,以总结并完成此处找到的一些信息:
描述了四种可能的方法(以及其中的一些细微变化)。
if (number % 2 != 0) {
number--;
}number&= ~1number = number - (number % 2);number = (number / 2) * 2;在继续进行任何操作之前,让我先澄清一下:即使可以证明一种方法比另一种方法快200%,最坏的方法也是如此之快,以至于只有这种方法才能获得可见的增益,但是使用这些方法中的任何一种方法的预期收益都是最小的。如果在受CPU约束的应用程序中多次调用此方法,则速度最快。因此,这比真正的优化更有趣。
就可读性而言,我将方法1评为最易读,将 方法4评为次优,将方法2评为最差。人们可以自由地不同意,但我之所以对他们进行排名是因为:
考虑到这一点,我要补充一点,我通常认为,实现此目标的最佳方法是使用inline函数,并且没有一个选择是不可读,可读性不是真正的问题(在代码中的直接使用是明确且清晰的,阅读方法永远不会那么难)。
如果您不想使用inline方法,我建议您仅使用
方法1或方法4。
已经提到,方法1可能会下溢,具体取决于处理器表示整数的方式。只是为了确保您可以STATIC_ASSERT在使用方法1时添加以下内容
。
STATIC_ASSERT(INT_MIN % 2 == 0, make_even_may_underflow);
Run Code Online (Sandbox Code Playgroud)
对于方法3,INT_MIN取决于结果是否具有除数或除数相同的符号,即使在甚至不是时也可能不会下溢。具有相同除数符号的永远不会下溢,因为
INT_MIN - (-1)它接近于0。请添加以下内容STATIC_ASSERT以确保:
STATIC_ASSERT(INT_MIN % 2 == 0 || -1 % 2 < 0, make_even_may_underflow);
Run Code Online (Sandbox Code Playgroud)
当然,如果STATIC_ASSERT失败,您仍然可以使用这些方法,因为只有将INT_MIN传递给您的make_even方法时这才是问题,但是我强烈建议您这样做。
使用方法2时,应确保编译器的位表示形式符合预期:
STATIC_ASSERT( (1 & ~1) == 0, unsupported_bit_representation);
// two's complement OR sign-and-magnitude.
STATIC_ASSERT( (-3 & ~1) == -4 || (-3 & ~1) == -2 , unsupported_bit_representation);
Run Code Online (Sandbox Code Playgroud)
我还使用Unix time实用程序进行了一些幼稚的速度测试。我对每种不同的方法(及其变体)运行了4次并记录了结果,因为结果变化不大,所以我认为没有必要运行更多的测试。
所获得的结果表明方法4和方法2是所有方法中最快的。
根据提供的信息,我建议使用方法4。它可读性强,我不知道任何兼容性问题,并且表现出色。
我希望您喜欢这个答案,并使用此处包含的信息做出自己明智的选择。:)
该源代码,如果你想检查我的结果是可用的。请注意,这些测试是使用g++Mac OS X 编译并在Mac OS X上运行的。不同的平台和编译器可能会给出不同的结果。