【问题标题】:Difference in BigInteger values from a String and a byte array字符串和字节数组中 BigInteger 值的差异
【发布时间】:2016-08-11 16:08:04
【问题描述】:

谁能解释一下下面两个 BigInteger 初始化的区别。

输入:

BigInteger bi1 = new BigInteger("EF", 16);
byte[] ba = new byte[] {(byte)0xEF};
BigInteger bi2 = new BigInteger(ba);
Log.d("BIGINTEGER", "Big Integer1 = " + bi1.toString(16));
Log.d("BIGINTEGER", "Big Integer2 = " + bi2.toString(16));

输出:

Big Integer1 = ef
Big Integer2 = -11

如何使用字节数组中的值“EF”初始化 BigInteger?

【问题讨论】:

    标签: java android string bytearray biginteger


    【解决方案1】:

    来自BigInteger docs

    构造函数和描述

    BigInteger(byte[] val)

    翻译一个包含 二进制补码的字节数组 将 BigInteger 表示为 到 BigInteger。

    补码才是真正的原因。

    让我们看看如何...

    (Byte)0xef 二进制 = 11101111 现在将其转换回 Int,您将得到 -17(以 10 为底)或 -11(以 16 为底)。

    现在看看

    byte[] ba = new byte[] {0, (byte)0xEF};
    

    这有(Byte)0xef,但前面有0。这意味着这个数组有00000000 11101111,转换后会给出正确的结果。

    为什么之前的案例不同?

    查看 2 的补码规则 - SO Answer,强制 Wikipedia link

    另一种思考方式

    0xEF 十进制 = 239

    字节范围 = -127 到 128

    我们有溢出。

    239 - 128 = 111

    现在从后面数这 111(数字数据类型具有这种循环行为,同样是由于 2 的补码表示)。

    例如:129.toByte = -127

    (129 - 128 = 1,倒数第一个值 = -127)

    从后面数的捷径if x>128 && x<256 then x.toByte = (x - 128) - 128

    这里 x = 239 所以 x.toByte = -17

    【讨论】:

      【解决方案2】:

      将前导零放入byte[]

      byte[] ba = new byte[] {0, (byte)0xEF};
      

      Ideone demo

      【讨论】:

      • 谢谢,成功了。你能解释一下这有什么不同吗?
      【解决方案3】:

      您需要在byte[] 数组中添加一个零:

      byte[] myByteArray = new byte[] {0, (byte)0xEF};
      BigInteger bi2 = new BigInteger(ba);
      Log.d("BIGINTEGER", "Big Integer1 = " + bi1.toString(16));
      Log.d("BIGINTEGER", "Big Integer2 = " + bi2.toString(16));
      

      为什么?

      原因与语言规范有关:

      十进制字面量具有十六进制不共享的特定属性,即十进制字面量都是正数 [JLS 3.10.1]

      要编写负十进制常量,您需要将一元否定运算符 (-) 与十进制文字结合使用。

      这样,你可以写任何 int 或 long 值,无论是正数 或负,十进制形式,负十进制常量可以通过减号清楚地识别。

      十六进制或八进制文字并非如此。 它们可以采用正值和负值。十六进制和八进制文字是 如果设置了高位,则为负数。

      话说回来,0xFE其实是个负数……

      【讨论】:

        【解决方案4】:

        public BigInteger(byte[] val)

        将包含 BigInteger 的 two's-complement 二进制表示的字节数组转换为 BigInteger。输入数组假定为 big-endian 字节顺序:最高有效字节位于第零个元素中。

        public BigInteger(String val, 整数基数)

        将指定基数中 BigInteger 的 String 表示形式转换为 BigInteger。 [...]

        来源:Oracle Java 7 文档

        您从 bytearray 初始化的行为与预期不符,因为 0xEF 转换为 bytearray 返回 {1, 1, 1, 0, 1, 1, 1, 1}。

        按照上面提到的规范制作成整数的方法如下:

        1*2^0 + 1*2^1 + 1*2^2 + 1*2^3 + 0*2^4 + 1*2^5 + 1*2^6 - 1*2^7 = -17 = -0x11
        

        二进制的恭维导致最高字节被减去,而不是被添加。所以在字节数组的开头添加一个 0 应该可以解决问题:

        byte[] ba = new byte[] {0, (byte)0xEF};
        

        【讨论】:

          猜你喜欢
          • 2014-08-11
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-10-23
          • 1970-01-01
          • 2011-01-14
          相关资源
          最近更新 更多