【问题标题】:BigInteger, BitSet and their bit and byte orderBigInteger、BitSet 及其位和字节顺序
【发布时间】:2017-04-02 18:21:32
【问题描述】:

考虑以下代码(java8):

@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();
}

这证明了 BitSet 将字节数组解析为 BIG_ENDIAN,而将(单个字节的)位顺序解释为 LITTLE_ENDIAN。相比之下,BigInteger 在 LITTLE_ENDIAN 中解释两者,即使由位字符串加载也是如此。

尤其是对两个类的位索引(BitInteger::testBit vs. BitSet::get)的迭代会产生不同的结果。

这种不一致有什么原因吗?

【问题讨论】:

    标签: java endianness


    【解决方案1】:

    字节序主要仅指字节的顺序,而不是单个位的顺序。后者在大多数应用程序中不相关,因为您不能例如寻址内存中的各个位。因此,字节中位的字节序仅在重要的情况下使用,例如串行数据总线,否则字节通常被视为它们所代表的数字而没有任何字节序(cf. WikipediaCan endianness refer to bits order in a byte? 的答案)。

    因此,BitSet 将字节视为首先具有其最低有效位,这样当您将字节 0x01 提供给它时​​,您将获得设置最低位的预期结果,而不管它使用什么字节序字节的顺序。这就是为什么使用 BigIntegerBitSet 的输出仅在字节顺序上有所不同。

    请注意,对于字节顺序,BitSet 使用小端,BigInteger 使用大端(与您声称的不同)。

    至于为什么BitSet 使用与BigInteger 不同的字节序,我们只能推测。请注意,受人尊敬的 BitSet 方法要更新得多(仅在 Java 1.7 中引入),因此自引入 BigInteger 以来,小端与大端的重要性可能发生了变化。

    【讨论】:

    • 抱歉,我总是对 BIG_ENDIAN 这个词感到困惑。我上面的陈述是基于最高有效字节出现在末尾的想象。显然常识是相反的,你是对的。
    • 但我的问题是:BitSet 反过来运作是否有充分的理由?
    • 是的,在某些情况下,位排序确实很重要。例如在 base64 字符串中编码 RSA 模数(将比特流分成 6 位字),或 QR 码编码(将比特流分成 11 位字)。
    • @Heri 当然,有些应用程序的位顺序很重要(我没有另外声明),但它们相对较少。我添加了一段关于为什么 BitSet 可以使用与 BigInteger 不同的字节序。
    猜你喜欢
    • 1970-01-01
    • 2012-11-21
    • 1970-01-01
    • 2020-01-13
    • 1970-01-01
    • 2019-05-08
    • 2015-06-14
    • 1970-01-01
    • 2016-02-21
    相关资源
    最近更新 更多