是否可以使用Java BigInteger
将负数解析为无符号值?
例如,我要将-1
解释为FFFFFFFFFFFFFFFF
。
答案 0 :(得分:6)
尝试使用构造函数
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);
}
答案 1 :(得分:6)
如果您考虑的是二进制补码,则必须指定工作位长度。 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;
}
答案 2 :(得分:3)
这个问题有两个答案,具体取决于OP是否希望该答案与以下内容有关:
String
并将解释后的值存储为正BigInteger
。BigInteger
输出为String
作为正十六进制数。BigInteger
首先重要的是要了解BigInteger
实际上将数字存储为两个单独的值:
这意味着 -1 存储为 {signed,1} 。
第二,理解BigInteger
为十六进制,并根据用于存储的特定位数显示的特定位数与数字值无关,这一点也很重要,但是所有相关的事情带有数字表示。
也就是说,对于二进制补码32位值(即int
),以下表示均表示相同的存储值:
BigInteger
不能说相同:
String
并将解释后的值存储为正BigInteger
要读取可能包含负数的String
并将其存储为BigInteger
作为具有特定位数的正数,请使用以下代码:
BigInteger number = new BigInteger("-1");
int bits = 64;
BigInteger maxValue = BigInteger.valueOf(number).shiftLeft(bits);
number = number.mod(maxValue);
例如BigInteger
中使用16位的值-1将存储为:
BigInteger
转换为正数String
要输出一个BigInteger
作为已调整为特定位数的十六进制数,请使用以下代码:
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);
请注意,上面显示的代码不会处理超出预期位范围的数字。
例如将16位数字1_000_000和-1_000_000转换为字符串:
期望值应在哪里(模数版本实际返回的值):
以下代码将以上所有内容组合为一个方法:
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
转换为十六进制字符串?”
以下代码会将byte[]
转换为十六进制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[]
。
答案 3 :(得分:1)
你总是可以手动做两个补码。如果数字小于0,则反转所有位并加1。
答案 4 :(得分:1)
One Liner(但不要忘记考虑源的持久性问题,可以使用ByteBuffer.byteOrder处理):
new BigInteger(1, ByteBuffer.allocate(Long.SIZE/Byte.SIZE).putLong(Long.parseLong("-1")).array());
答案 5 :(得分:1)
要击败new BigInteger(long)
将该参数解释为二进制补码,您可以首先转换数字的高63位,避免使用long
的符号位,然后“添加”最后一位:
BigInteger unsigned(long value) {
return BigInteger
.valueOf(value >>> 1).shiftLeft(1) // the upper 63 bits
.or(BigInteger.valueOf(value & 1L)); // plus the lowest bit
}
答案 6 :(得分:0)
你的意思是什么?
public static void main(String[] args) {
BigInteger bg = BigInteger.valueOf(-1);
System.out.println(Integer.toHexString(bg.intValue()));
}
答案 7 :(得分:0)
您可以使用此实用程序转换为无符号整数。由于BigIntegers具有无限大小,因此必须指定大小以确定要在翻译中保留多少符号扩展名:
public static BigInteger toPositive(BigInteger num, int sizeInBytes) {
return num.andNot(BigInteger.valueOf(-1).shiftLeft(sizeInBytes * 8));
}
答案 8 :(得分:0)
简单的解决方案来自@Ahmet Karakaya,但是应该修复更大的数字:
BigInteger bg = BigInteger.valueOf(-1);
System.out.println(Long.toHexString(bg.intValue()));
结果:ffffffffffffffff
或简单地说:
System.out.println(Long.toHexString(-1))