是否可以使用 Java 将负数解析为无符号值BigInteger
?
因此,例如,我将解释-1
为FFFFFFFFFFFFFFFF
.
尝试使用构造函数
public BigInteger(int signum, byte[] magnitude)
第一个参数应设置为 1 以指定您要创建一个正数。字节数组是您在 BIG ENDIAN ORDER 中解析的数字。如果您将第一个参数设置为 1,它应该被解释为一个无符号数。唯一的技巧是将您的数字放入一个字节数组中,但这应该不会太难。
编辑:看起来你必须在这里做一些手动位算术。如果我正确理解您的问题,您需要将 String 解释为 Long,然后将其解释为 unsigned 并将其存储在 BigInteger 类中。我会这样做。
public BigInteger getValue(String numberString)
{
Long longValue = Long.valueOf(numberString);
byte [] numberAsArray = new byte[8];
for(int i = 0; i < 8; i++)
{
numberAsArray[7 - i] = (byte)((longValue >>> (i * 8)) & 0xFF);
}
return new BigInteger(1, numberAsArray);
}
如果您正在考虑二进制补码,则必须指定工作位长度。Java long 有 64 位,但 BigInteger 是无界的。
你可以这样做:
// Two's complement reference: 2^n .
// In this case, 2^64 (so as to emulate a unsigned long)
private static final BigInteger TWO_COMPL_REF = BigInteger.ONE.shiftLeft(64);
public static BigInteger parseBigIntegerPositive(String num) {
BigInteger b = new BigInteger(num);
if (b.compareTo(BigInteger.ZERO) < 0)
b = b.add(TWO_COMPL_REF);
return b;
}
public static void main(String[] args) {
System.out.println(parseBigIntegerPositive("-1").toString(16));
}
但这隐含地意味着您正在使用 0 - 2^64-1 范围内的 BigIntegers。
或者,更一般地说:
public static BigInteger parseBigIntegerPositive(String num,int bitlen) {
BigInteger b = new BigInteger(num);
if (b.compareTo(BigInteger.ZERO) < 0)
b = b.add(BigInteger.ONE.shiftLeft(bitlen));
return b;
}
为了使它更加万无一失,您可以添加一些检查,例如
public static BigInteger parseBigIntegerPositive(String num, int bitlen) {
if (bitlen < 1)
throw new RuntimeException("Bad bit length:" + bitlen);
BigInteger bref = BigInteger.ONE.shiftLeft(bitlen);
BigInteger b = new BigInteger(num);
if (b.compareTo(BigInteger.ZERO) < 0)
b = b.add(bref);
if (b.compareTo(bref) >= 0 || b.compareTo(BigInteger.ZERO) < 0 )
throw new RuntimeException("Out of range: " + num);
return b;
}
该问题有两个答案,具体取决于 OP 是否希望答案与以下内容有关:
String
并将解释的值存储为正数BigInteger
。BigInteger
到 a 。String
BigInteger
首先,重要的是要了解BigInteger
实际上将数字存储为两个单独的值:
这意味着-1存储为{signed, 1}。
其次,同样重要的是要了解,BigInteger
根据用于存储的特定位数,将 a 显示为具有特定位数的十六进制与数字值无关,而与数字表示有关。
也就是说,对于二进制补码 32 位值(即int
),以下表示都表示内存中存储的相同值:
虽然不能这样说BigInteger
:
String
并将解释值存储为正数BigInteger
要读取String
可能包含负数的 a 并将其BigInteger
作为具有特定位数的正数存储在 a 中,请使用以下代码:
BigInteger number = new BigInteger("-1");
int bits = 64;
BigInteger maxValue = BigInteger.valueOf(number).shiftLeft(bits);
number = number.mod(maxValue);
例如,使用 16 位的值 -1BigInteger
将存储为:
BigInteger
转换为正十六进制String
要将 aBigInteger
作为调整为特定位数的十六进制数输出,请使用以下代码:
BigInteger number = new BigInteger("-1");
int bits = 64;
BigInteger maxValue = BigInteger.valueOf(number).shiftLeft(bits);
number = number.mod(maxValue);
String outString String.format("%0" + (bits + 3)/4 + "X", number);
如果您担心上面的代码使用除法来获得结果,那么下面的代码将对可以在范围内表示的数字执行相同的操作(即可以使用指定的位数存储):
BigInteger number = new BigInteger("-1");
int bits = 64;
if (number.signum() < 0) {
number = BigInteger.valueOf(1).shiftLeft(bits).add(number);
}
String outStr = String.format("%0" + (bits + 3)/4 + "X", number);
请注意,上面显示的代码不处理超出预期位范围的数字。
例如 1_000_000 和 -1_000_000 作为 16 位数字将被转换为字符串:
预期值应该在哪里(取模版本实际返回):
以下代码将上述所有内容组合成一种方法:
public String AsAFixedBitsNumber(BigInteger number, int bits) {
BigInteger maxValue = BigInteger.valueOf(1).shiftLeft(bits);
if (maxValue.negate().compareTo(number) >= 0 || maxValue.compareTo(number) <= 0) {
number = number.mod(maxValue);
} else if (number.signum() < 0) {
number = maxValue.add(number);
}
return String.format("%0" + (bits + 3)/4 + "X", number);
}
BigInteger
] 十六进制表示作为相关问题的额外奖励答案:“如何转换byte[]
为十六进制字符串 [使用BigInteger
]?”
以下代码将 a 转换byte[]
为 hex String
:
byte[] buffer = new byte[]{1, 2, 3};
String hex = String.format("%0" + buffer.length*2 + "X", new BigInteger(1, buffer));
请注意,将 signum 参数设置为 1 非常重要,这样才能BigInteger
理解数组中的值将被解析为“无符号”。
另请注意,此方法会创建两个临时缓冲区来创建字符串Character[]
,如果您正在处理非常大的数组,最好将数组直接解析为 a 。
您始终可以手动进行补码。如果数字小于 0,则将所有位取反并加一。
一个 Liner(但是不要忘记考虑源的 endiness 问题,可以使用 ByteBuffer.byteOrder 处理):
new BigInteger(1, ByteBuffer.allocate(Long.SIZE/Byte.SIZE).putLong(Long.parseLong("-1")).array());
要击败new BigInteger(long)
' 将参数解释为以二进制补码编码的方式,您可以首先以避免使用long
' 符号位的方式转换数字的高 63 位,然后“添加”最后一位:
BigInteger unsigned(long value) {
return BigInteger
.valueOf(value >>> 1).shiftLeft(1) // the upper 63 bits
.or(BigInteger.valueOf(value & 1L)); // plus the lowest bit
}
是你什么吗?
public static void main(String[] args) {
BigInteger bg = BigInteger.valueOf(-1);
System.out.println(Integer.toHexString(bg.intValue()));
}
您可以使用此实用程序转换为无符号整数。由于 BigInteger 的大小不受限制,因此必须指定一个大小来确定要在翻译中保留多少符号扩展:
public static BigInteger toPositive(BigInteger num, int sizeInBytes) {
return num.andNot(BigInteger.valueOf(-1).shiftLeft(sizeInBytes * 8));
}
简单的解决方案来自@Ahmet Karakaya,但应该针对更大的数字进行修复:
BigInteger bg = BigInteger.valueOf(-1);
System.out.println(Long.toHexString(bg.intValue()));
结果:ffffffffffffffff
或者简单地说:
System.out.println(Long.toHexString(-1))