2017-04-02 68 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