2017-04-02 24 views
0

考慮下面的代碼(java8):BigInteger,以位集合和它們的位和字節順序

@Test 
public void testBigIntegerVsBitSet() throws Throwable 
{ 
    String bitString529 = "00000010 00010001";  // <- value = 529 (LittleEndian) 
    byte[] arr529 = new byte[] { 0x02, 0x11 };  // <- the same as byte array (LittleEndian) 
    BigInteger bigIntByString = new BigInteger(bitString529.replace(" ", ""), 2); // throws if there is a blank! 
    BigInteger bigIntByArr = new BigInteger(arr529); 
    BitSet bitsetByArr = BitSet.valueOf(arr529); // interpretes bit-order as LittleEndian, but byte-order as BigEndian !!! 

    System.out.println("bitString529  : " + bitString529);    // bitString529  : 00000010 00010001 
    System.out.println("arr529.toString : " + Arrays.toString(arr529)); // arr529.toString : [2, 17] 
    System.out.println("bigIntByString : " + bigIntByString);   // bigIntByString : 529 
    System.out.println("bigIntByArr  : " + bigIntByArr);    // bigIntByArr  : 529 
    System.out.println("bitsetByArr  : " + bitsetByArr.toString()); // bitsetByArr  : {1, 8, 12} 
    System.out.println("expecting  : {0, 4, 9}");     // expecting  : {0, 4, 9} 

    String bigIntByStringStr = toBitString(bigIntByString::testBit); 
    String bigIntByArrStr = toBitString(bigIntByArr::testBit); 
    String bitsetByArrStr = toBitString(bitsetByArr::get); 

    System.out.println("bigIntByStringStr: " + bigIntByStringStr);   // bigIntByStringStr: 1000100001000000 
    System.out.println("bigIntByArrStr : " + bigIntByArrStr);   // bigIntByArrStr : 1000100001000000 
    System.out.println("bitsetByArrStr : " + bitsetByArrStr);   // bitsetByArrStr : 0100000010001000 
} 

private String toBitString(Function<Integer, Boolean> aBitTester) 
{ 
    StringBuilder sb = new StringBuilder(); 
    for (int i = 0; i < 16; i++) 
    { 
     sb.append(aBitTester.apply(i) ? "1" : "0"); 
    } 
    return sb.toString(); 
} 

其中prooves該位集合解析字節數組作爲BIG_ENDIAN而它interpretes比特順序(一個字節)爲LITTLE_ENDIAN 。相反,BigInteger在LITTLE_ENDIAN中解釋了這兩種情況,即使通過位串加載也是如此。

特別是兩個類的位索引(BitInteger :: testBit與BitSet :: get)的迭代提供了不同的結果。

是否有這種不一致的原因?

回答

3

Endianess主要指的是字節的排序,而不是單個位的排序。後者在大多數應用中並不相關,因爲你不能在內存中尋址各個位。因此,一個字節中的位的字節序僅在重要的情況下使用,例如串行數據總線,否則字節通常被視爲沒有任何字節順序的數字(cf. WikipediaCan endianness refer to bits order in a byte?的答案)。

如此,因爲BitSet對待的字節,同時,他們最低顯著位第一,這樣當你給它字節0x01你具有最低位設置的預期效果,不管是什麼ENDIANNESS它使用的排序字節。這就是爲什麼您使用BigIntegerBitSet的輸出僅在字節順序上有所不同。

請注意,對於字節順序,BitSet使用little-endianness,而BigInteger使用大字節順序(與您聲稱的不同)。

至於爲什麼BitSet使用與BigInteger不同的排列順序,我們只能推測。請注意,推薦的BitSet方法更新(僅在Java 1.7中引入),因此自引入BigInteger以來,可能認爲小大小寫的重要性已發生變化。

+0

對不起,我總是對BIG_ENDIAN這個詞感到困惑。我上面的說法是基於最後一個最重要的字節的想象。顯然,常識是相反的,你是對的。 – Heri

+0

但是我的問題是:爲什麼BitSet以相反的方式運行是否有充分的理由? – Heri

+0

是的,在某些情況下,位排序很重要。例如編碼base64串中的RSA模數(將比特流分成6比特字)或QR碼編碼(將比特流分成11比特字)。 – Heri