将十六进制转换为BigInteger

时间:2015-08-28 10:54:10

标签: java

我正在尝试将十六进制转换为Big Integer。基本上我有32个字符= 16个字节,所以我希望BigInteger也有16个字节,但在某些情况下,即十六进制从99开始..它生成0的附加字节。我用

new BigInteger(hex, 16)

如何避免第17个字节?

4 个答案:

答案 0 :(得分:2)

来自BigInteger's javadoc

  

不可变的任意精度整数。所有操作都表现得好像   BigIntegers用二进制补码表示(如Java的   原始整数类型)。

description of the constructor you are using

  

转换指定的BigInteger的String表示形式   基数为BigInteger。字符串表示由一个   可选的减号或加号后跟一个或多个序列   指定基数中的数字。字符到数字的映射是   由Character.digit提供。字符串可能不包含任何无关的内容   字符(例如空格)。

这意味着如果你用new BigInteger( "99000000000000000000000000000000", 16)调用它,你将得到一个BigInteger,它保存该值(这是一个正值),好像它用二进制补码表示法表示一样。二进制补码中的正值不适合16个字节,因此当然最终结果是17个字节长。

如果你用一个值(两者都包括在内)之间调用它,你可以保证获得一个最大16字节的BigInteger:

 - new BigInteger( "7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 16)
 - new BigInteger("-80000000000000000000000000000000", 16)

任何高于第一个值或低于最后一个值的值将导致超过16个字节。

答案 1 :(得分:1)

第一个字节不能以1位开头,因为这意味着一个负数。它们通过在数组的开头添加额外的零字节来防止这种情况。该函数将检查并切断该字节:

public static byte[] signedToUnsignedBytes(byte[] myBytes) {
    return myBytes.length > 1 && myBytes[0] == 0
        ? Arrays.copyOfRange(myBytes, 1, myBytes.length)
        : myBytes;
}

答案 2 :(得分:0)

超过127的字节值无法用Java byte表示,因为它们已经签名(好吧,它们可以但Java会将它们视为负数)。

BigInteger将值转换为字节数组时,它会在前面添加一个0字节,以区分正值和负值。

这导致128将变为[0][-128],而-128将变为[-128]

如果您打算将结果字节存储为无符号的128位值,则可以切断数组的第一个元素,例如: byte[] sanitizedBytes = Arrays.copyOfRange(myBytes, 1, 16);

答案 3 :(得分:0)

似乎您使用BigInteger仅用于将固定长度的十六进制字符串转换为byte[]数组。这可以通过其他方式完成,例如,使用ByteBuffer类:

static byte[] toByteArray(String s) {
    ByteBuffer bb = ByteBuffer.allocate(16);
    bb.asIntBuffer().put((int) Long.parseLong(s.substring(0, 8), 16))
                    .put((int) Long.parseLong(s.substring(8, 16), 16))
                    .put((int) Long.parseLong(s.substring(16, 24), 16))
                    .put((int) Long.parseLong(s.substring(24), 16));
    return bb.array();
}

使用Long.parseUnsignedLong()

在Java-8中稍微简单一些
static byte[] toByteArray8(String s) {
    ByteBuffer bb = ByteBuffer.allocate(16);
    bb.asLongBuffer().put(Long.parseUnsignedLong(s.substring(0, 16), 16))
                     .put(Long.parseUnsignedLong(s.substring(16), 16));
    return bb.array();
}

这样你就不应该关心极端情况(即使对于"000...000"字符串也总是会得到16个字节)并且可能会有更少的堆分配。样品用法:

System.out.println(Arrays.toString(toByteArray("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")));
// [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1]
System.out.println(Arrays.toString(toByteArray("80000000000000000000000000000000")));
// [-128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
System.out.println(Arrays.toString(toByteArray("123FFFFFFFFFFFFFFFFFFFFFFFFFFFFF")));
// [18, 63, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1]
System.out.println(Arrays.toString(toByteArray("007FFFFFFFFFFFFFFFFFFFFFFFFFFFFF")));
// [0, 127, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1]
System.out.println(Arrays.toString(toByteArray("00000000000000000000000000000001")));
// [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]