Java 将十六进制转换为BigInteger
我正在尝试将十六进制转换为大整数。基本上我有32个字符=16个字节,所以我希望Java 将十六进制转换为BigInteger,java,Java,我正在尝试将十六进制转换为大整数。基本上我有32个字符=16个字节,所以我希望biginger也有16个字节,但在某些情况下,即十六进制以99开头。。它用0生成额外的字节。我正在使用 new BigInteger(hex, 16) 超过127的字节值不能用java的字节>代码表示,因为它们被签名了(他们可以,但是java会把它们看作负数)。 当biginger将值转换为字节数组时,它将在前面添加一个0字节,以区分正值和负值 这导致128将变成[0][-128],而-128将变成[-128] 如
biginger
也有16个字节,但在某些情况下,即十六进制以99开头。。它用0生成额外的字节。我正在使用
new BigInteger(hex, 16)
<如何避免第十七字节?< p>超过127的字节值不能用java的
biginger
将值转换为字节数组时,它将在前面添加一个0字节,以区分正值和负值
这导致128
将变成[0][-128]
,而-128
将变成[-128]
如果要将生成的字节存储为无符号128位值,只需切掉数组的第一个元素,例如,byte[]sanitizedBytes=Arrays.copyOfRange(myBytes,1,16)代码>来自:
不可变的任意精度整数。所有操作的行为都像
大整数用二的补码表示法(类似于Java的
基元整数类型)
以及:
转换指定格式中BigInteger的字符串表示形式
将基数转换为一个大整数。字符串表示法由
可选的减号或加号,后跟一个或多个序列
指定基数中的数字。字符到数字的映射是
由Character.digit提供。字符串不能包含任何无关的内容
字符(例如空格)
这意味着,如果您使用new biginger(“9900000000000000000000000000000”,16)
调用它,您将得到一个biginger,它保存该值(它是一个正值),就像它是用两位补符号表示的一样。2的补码中的正值不适合16个字节,因此最终结果当然是17个字节长
如果使用介于(包括两个)之间的值调用BigInteger,则保证获得最大值为16字节的BigInteger:
任何高于第一个或低于最后一个的值都将导致超过16个字节。第一个字节不能以1
位开头,因为这意味着一个负数。它们通过在数组的开头添加额外的零字节来防止这种情况。此函数将检查并切掉该字节:
public static byte[] signedToUnsignedBytes(byte[] myBytes) {
return myBytes.length > 1 && myBytes[0] == 0
? Arrays.copyOfRange(myBytes, 1, myBytes.length)
: myBytes;
}
似乎您使用biginger
的唯一目的是将固定长度的十六进制字符串转换为byte[]
数组。这可以通过另一种方式完成,例如,使用ByteBuffer
class:
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();
}
或者在Java-8中使用Long.parseUnsignedLong()
更简单一些:
这样,您就不必关心死角情况(即使对于“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]
我发现很难准确地理解问题所在。如果您发布一个简短但完整的程序来演示问题,即输入、实际输出和预期输出,那么会更容易帮助您。由于Java的符号性,任何以80
或更高开头的值在执行toByteArray()
时都会产生一个“额外”字节,所以没有别的办法,只有这个额外的0(实际上,如果十六进制以000
到007
开头,则字节数也可能少于16。如果是某种哈希函数,则有1/512
的可能。也可以测试这种情况。
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();
}
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]