Java:在long中检查位是0还是1

81

您会使用哪种方法来确定代表2^x的位是1还是0?

14个回答

188

我会使用:

if ((value & (1L << x)) != 0)
{
   // The bit was set
}

(你也许可以少用一些括号,但我从来不记得按位运算的优先级。)


54
这取决于编程语言。在Java中,这种情况并不成立。 - harmanjd
12
应该是1升,否则(1 << 32)会得到与(1 << 0)相同的值。 - Matt K
4
没什么奇怪的。请不要发布愚蠢的反Java挑衅言论。 - amischiefr
12
我在想 ((value>>>x) & 1) != 0 是否更好,因为它不考虑值是否为长整型,但是也许更不易懂。 - Tom Hawtin - tackline
4
@ArtOfWarfare: 有时我会将 == 打成 =,这会导致赋值一个值的有效表达式,而这不是我想要的。在Java中,这是非法的(假设它不是一个 boolean 变量)。按位运算符是Java的一部分,我认为这是件好事。有很多情况下你需要用到按位运算符。没有必要将这与 whileif 等条件表达式的类型是否应该为 boolean 进行混淆 - 我认为应该为 boolean - Jon Skeet
显示剩余9条评论

101

另一个选择:

if (BigInteger.valueOf(value).testBit(x)) {
    // ...
}

9
如果这段代码需要经常调用,那么这不是一个很好的解决方案。你只是用一行替换了另一行,而且位移操作并不难理解。 - wds
3
行的长度并不等于行的易读性。你可能是对的,前一个解决方案更有效,但差异可能微不足道,特别是如果testBit()被内联。 - Isabelle Wedin
8
需要注意的是,这种解决方案需要分配内存,远不如位运算符高效。虽然通常情况下影响不大,但有时为了避免不必要的垃圾回收和/或低效的代码(例如在Android应用程序、游戏主循环中),避免使用该方法是很重要的。 - NateS
6
资源浪费。如果你不能信任“未来的维护者”理解位运算,那么你在项目中面临的人力资源问题比这更严重。位运算并不神奇,它是程序员技能基础中的一部分。 - dolmen
2
@dolmen,如果分析器将其标记为占用大量CPU时间的内容,我会用更快的东西来替换它。在此之前,这并不重要。 - finnw
显示剩余2条评论

15

我在想:

  if (((value >>> x) & 1) != 0) {

  }

.. 更好是因为它不在乎值是长的还是短的,或者即使更糟糕也因为它不那么明显。

Tom Hawtin - tackline Jul 7 at 14:16


我认为这样做更好,因为出错的可能性较小 - 如果你认为不明显,你可以将测试提取到一个适当命名的函数中(例如:boolean isBitSet(long value, int x))。 - hjhill

13
你也可以使用。
bool isSet = ((value>>x) & 1) != 0;

编辑:"(value>>x) & 1" 和 "value & (1<<x)" 的不同之处在于当 x 大于 "value" 类型的大小时 (在您的情况下为 32),它们的行为是不同的。

在那种情况下,使用 "(value>>x) & 1" 会得到 value 的符号,而使用 "value & (1<<x)" 则会得到0(如果 x 太大,有时获取比特符号很有用)。

如果您希望在这种情况下得到 0,则可以使用 ">>>" 运算符,而不是 ">>"。

因此,"((value>>>x) & 1) != 0" 和 "(value & (1<<x)) != 0" 是完全等价的。


8

对于第n位最低有效位(LSB),以下方法应该适用:

boolean isSet = (value & (1 << n)) != 0;

9
应该是1升,或者(1 << 32)与(1 << 0)得到相同的值。 - Matt K

7

4
在Java中,以下内容可以正常工作:
if (value << ~x < 0) {
   // xth bit set
} else {
   // xth bit not set
}

valuex可以是intlong(不需要相同)。

非Java程序员请注意:前面的表达式在Java中有效,因为在该语言中,位移操作符仅适用于右手边操作数的5个(或6个,在long的情况下)最低位。这会将表达式隐式转换为value << (~x & 31)(如果valuelong,则为value << (~x & 63))。

Javascript:它也可以在javascript中工作(与java一样,只应用移位计数的最低5位)。在javascript中,任何number都是32位的。

特别是在C语言中,负移位计数会引发未定义的行为,因此此测试不一定有效(尽管根据您的编译器/处理器的特定组合可能有效)。

它是如何工作的?

这个答案的巧妙之处在于,整数的符号位非常容易读取:当该位被设置时,值为负;如果未设置,则值为零或正数。

因此,整个思路是将第x位恰好移入符号位。这意味着向左移动31-x(如果value宽度为64位,则为63-x)。

在Java(以及其他语言中),运算符计算按位 NOT 操作,在算术上等于-x-1(无论x有多宽)。

此外,java的<<运算符仅使用右侧操作数的最低5(或6)位(5或6取决于左侧操作数的宽度:对于int,则为5;对于long,则为6)。在算术上,这与除以32(或64)的余数相同。

这里是关于编程的内容:(-x - 1) % 32 = 31 - x(对于64位的value,则为(-x - 1) % 64 = 63 - x)。


为什么在if语句中使用~x。如果(value << ~x < 0){ - dcarl661
@dcarl661,我已经添加了“它是如何工作的?”这一部分。希望能有所帮助。 - rslemos

4

2

2的x次方位的值为“变量 & (1 << x)”。


正如Matt Kane在相同的解决方案中所说:应该是1L,否则(1 << 32)将得到与(1 << 0)相同的值。 - drvdijk

1

我的贡献 - 忽略之前的

public class TestBits { 

    public static void main(String[] args) { 

        byte bit1 = 0b00000001;     
        byte bit2 = 0b00000010;
        byte bit3 = 0b00000100;
        byte bit4 = 0b00001000;
        byte bit5 = 0b00010000;
        byte bit6 = 0b00100000;
        byte bit7 = 0b01000000;

        byte myValue = 9;                        // any value

        if (((myValue >>> 3) & bit1 ) != 0) {    //  shift 3 to test bit4
            System.out.println(" ON "); 
        }
    } 
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接