Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/345.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 混淆了位移位(按字节计算位)_Java - Fatal编程技术网

Java 混淆了位移位(按字节计算位)

Java 混淆了位移位(按字节计算位),java,Java,我试图计算一个字节中的设置位数,但我似乎遇到了一些找不到答案的问题 我的代码目前看起来像 public static int numBits(byte input){ int count = 0; while (input != 0){ if ((input & 1)==1){ count++; } input >>= 1; }

我试图计算一个字节中的设置位数,但我似乎遇到了一些找不到答案的问题

我的代码目前看起来像

   public static int numBits(byte input){
       int count = 0;
       while (input != 0){
           if ((input & 1)==1){
               count++;
           }
           input >>= 1;
       }
       return count;
   }
在我尝试x=-1之前,它似乎工作得很好

当值1位被插入时,这最终创建了一个无限循环。所以我偶然发现

根据我的解释,这意味着我应该使用输入>>=1;但这仍然导致了一个无限循环

所以我试着去弄清楚到底发生了什么

byte x = -1;
System.out.println(x >>> 1);
System.out.println(x >> 1);
导致

2147483647
-1
让我更加困惑。2147483647是从哪里来的?我可能在哪里犯了一个逻辑错误?

>>>运算符表示向右移位,但不表示扩展

您的试用非常接近,但实际上您并没有修改x,因此您可以:

int x = -1;
x = x >>> 1;
System.out.println(x);
x = x >> 1; // highest bit = 0 now
System.out.println(x);
这将产生

2147483647
1073741823
请注意,我在这里使用int而不是byte,因为位移位的结果强制输入至少为整数大小

有趣的是,当你跑步时:

byte input = -1;
input = (byte) (input >>> 1);
结果仍然是-1。这是因为上面提到的这个操作符发生了类型强制。为了避免影响您,您可以屏蔽输入位,以确保只接受前8位:

byte input = -1;
input = (byte) ((input & 0xFF) >>> 1);
如果您要运行,请将这些放在一起:

byte input = -1;
input = (byte) ((input & 0xFF) >>> 1);
System.out.println(input);
input = (byte) ((input & 0xFF) >> 1);
System.out.println(input);
您将获得预期的结果:

127
63

这一切都是由有符号整数存储为二进制值的方式造成的。数字的最高位决定零的符号排序的方式使事情变得奇怪,并且符号被保留在算术移位中。您的print语句给出了奇怪的结果,因为结果被提升为int值而不是字节

如果您想要一个非常简单的解决方案,您可以使用int来存储您的值,但请确保屏蔽除最低顺序字节以外的所有内容:

public static int numBits(byte inByte){
   int count = 0;
   int input = inByte & 0xFF;
   while (input != 0){
       if ((input & 1)==1){
           count++;
       }
       input >>= 1;
   }
   return count;
}

正如我在上面的评论中所说,您应该真正了解有符号数字在二进制中的表示。如果您了解负数是如何表示的,以及算术/逻辑移位之间的差异,那么所有这些都将非常有意义。

您可能会发现JVM实际上是如何做的,这很有趣。注意:只有8位,所以不需要循环

public static int bitCount(int i) {
    // HD, Figure 5-2
    i = i - ((i >>> 1) & 0x55555555);
    i = (i & 0x33333333) + ((i >>> 2) & 0x33333333);
    i = (i + (i >>> 4)) & 0x0f0f0f0f;
    i = i + (i >>> 8);
    i = i + (i >>> 16);
    return i & 0x3f;
}
注意:在x86/x64上,JVM将其替换为一个内在的。i、 它使用单一的机器代码指令。如果复制此方法并将其与原始方法进行比较,则速度会慢3倍,因为JVM只替换硬编码的方法列表,因此它将替换Integer.bitCOunt,而不是副本

简而言之,使用内置方法,而不是重新发明它。

您应该阅读有关二进制符号数字表示的内容。如果您了解负数是如何表示的,以及算术/逻辑移位之间的差异,那么所有这些都将非常有意义。下面是您的操作方法: