簡體   English   中英

對移位感到困惑(以字節為單位計數位)

[英]Confused About Bit Shifting (Counting Bits in Byte)

我正在嘗試計算一個字節中設置的位數,但似乎遇到了一些無法找到答案的問題。

我的代碼目前看起來像

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

在我嘗試x = -1之前,它似乎工作正常。

由於插入了值1位,最終導致了無限循環。 所以我偶然發現

Java:負數右移

以我的解釋,這意味着我應該使用input >>>= 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 這是因為上述操作符發生類型強制。 為了防止這種情況影響您,您可以屏蔽input的位以確保僅使用前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

這都是由有符號整數作為二進制值存儲的方式引起的。 數字的最高位確定符號的方式(某種程度上為零,使事情變得怪異),並且通過算術移位來保留符號。 您的打印語句給出了奇怪的結果,因為結果被提升為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將其替換為內部函數。 即它使用單個機器代碼指令。 如果您復制此方法並進行比較,它將調用原始方法,它的速度要慢3倍,因為JVM僅替換了硬編碼的方法列表,因此它將替換Integer.bitCOunt,而不是副本。

簡而言之,請使用內置方法而不是重新發明它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM