java 使用 BigInteger 将负数解释为无符号数
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10886962/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Interpret a negative number as unsigned with BigInteger
提问by One Two Three
Is it possible to parse a negative number into an unsigned value with Java's BigInteger
?
是否可以使用 Java 将负数解析为无符号值BigInteger
?
So for instance, I'd to interpret -1
as FFFFFFFFFFFFFFFF
.
因此,例如,我会解释-1
为FFFFFFFFFFFFFFFF
.
回答by Akron
Try using the constructor
尝试使用构造函数
public BigInteger(int signum, byte[] magnitude)
The first parameter should be set to 1 to specify you want to create a positive number. The byte array is the number you are parsing in BIG ENDIAN ORDER. It should be interpreted as an unsigned number if you set the first parameter to 1. The only trick is getting your number into a byte array, but that shouldn't bee too difficult.
第一个参数应设置为 1 以指定您要创建一个正数。字节数组是您在大端顺序中解析的数字。如果您将第一个参数设置为 1,它应该被解释为一个无符号数。唯一的技巧是将您的数字放入一个字节数组中,但这应该不会太难。
EDIT: Looks like you have to do some manual bit arithmetic here. If I understand your problem correctly, you need to interpret a String as a Long and then interpret that long as unsigned and store that in the BigInteger class. I would do this.
编辑:看起来您必须在这里进行一些手动位算术运算。如果我正确理解您的问题,您需要将 String 解释为 Long,然后将该长解释为无符号并将其存储在 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);
}
回答by leonbloy
If you are thinking of a two's complement, you must specify a working bit length. A Java long has 64 bits, but a BigInteger is not bounded.
如果您正在考虑二进制补码,则必须指定工作位长度。Java long 有 64 位,但 BigInteger 没有界限。
You could do something as this:
你可以这样做:
// 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));
}
But this would implicitly mean that you are working with BigIntegers in the 0 - 2^64-1 range.
但这意味着您正在使用 0 - 2^64-1 范围内的 BigInteger。
Or, more general:
或者,更一般的:
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;
}
To make it more fooproof, you could add some checks, eg
为了使其更加简单,您可以添加一些检查,例如
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;
}
回答by Atli Guemundsson
There are two answers to the question, depending on whether the OP wants the answer to pertain to:
该问题有两个答案,具体取决于 OP 是否希望答案与以下内容有关:
- Reading/Parsing a
String
and storing the interpreted value as a positiveBigInteger
. - Outputting a negative
BigInteger
to aString
as a positive hex number.
- 读取/解析 a
String
并将解释的值存储为正数BigInteger
。 - 输出负
BigInteger
的String
是一个积极的十六进制数。
The Java BigInteger
爪哇 BigInteger
First of it is important to understand that BigInteger
actually stores numbers as two separate values:
首先,重要的是要了解BigInteger
实际上将数字存储为两个单独的值:
- a flag that indicates that the number is:
- signed
- zero
- positive
- an array of integers that contains the positive value of the number in big-endian order.
- 一个标志,表明该数字是:
- 签
- 零
- 积极的
- 一个整数数组,其中包含按大端顺序排列的数字的正值。
This means that -1is stored as {signed, 1}.
这意味着-1存储为{signed, 1}。
Secondly, it is also important to understand that displaying a BigInteger
as hex with a specific number of digits based on a specific number of bits used for storage has nothing to do with the number value, but everything to do with the number representation.
其次,了解BigInteger
基于用于存储的特定位数显示具有特定位数的十六进制也很重要,这与数值无关,而与数字表示有关。
That is to say that for twos complement 32-bit values (i.e. int
) the following representations all represent the same stored value in memory:
也就是说,对于二进制补码 32 位值(即int
),以下表示都表示内存中相同的存储值:
- -1
- 4_294_967_295
- ffffffff
- -1
- 4_294_967_295
- 噗噗噗
While the same can not be said for BigInteger
:
虽然不能说相同的BigInteger
:
- -1(stored as {negative, 1})
- 4_294_967_295(stored as {positive, 4_294_967_295})
- ffffffff(stored as {positive, 4_294_967_295})
- -1(存储为{negative, 1})
- 4_294_967_295(存储为{positive, 4_294_967_295})
- ffffffff(存储为{positive, 4_294_967_295})
Reading/Parsing a String
and storing the interpreted value as a positive BigInteger
读取/解析 aString
并将解释的值存储为正数BigInteger
To read a String
that might contain a negative number and store it in a BigInteger
as a positive number with a specific number of bits use the following code:
要读取String
可能包含负数的 a 并将其BigInteger
作为具有特定位数的正数存储在 a 中,请使用以下代码:
BigInteger number = new BigInteger("-1");
int bits = 64;
BigInteger maxValue = BigInteger.valueOf(number).shiftLeft(bits);
number = number.mod(maxValue);
E.g. The value -1 in BigInteger
using 16 bits would be stored as:
例如,BigInteger
使用 16 位的值 -1将存储为:
- {positive, 65535}(ffff in hex)
- {positive, 65535}(ffff 十六进制)
Converting a [negative] BigInteger
to a positive hex String
将 [negative]BigInteger
转换为正十六进制String
To output a BigInteger
as a hexadecimal number adjusted to a specific number of bits use the following code:
要将 a 输出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);
Performance
表现
If you are concerned over the fact that the above code uses division to get the result then the following code will do the same for numbers that can be represented within the range (i.e. that can be stored using the specified number of bits):
如果您担心上面的代码使用除法来获得结果,那么以下代码将对可以在范围内表示的数字执行相同的操作(即可以使用指定的位数存储):
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);
Note that the code shown above does not deal with numbers that fall outside of the intended bit range.
请注意,上面显示的代码不处理超出预期位范围的数字。
E.g. 1_000_000 and -1_000_000 as a 16-bit numbers will be converted to the strings:
例如 1_000_000 和 -1_000_000 作为 16 位数字将被转换为字符串:
- F4240
- -E4240
- F4240
- -E4240
Where the expected values should be (which the modulo version actually returns):
预期值应该在哪里(模版本实际返回):
- 4240
- BDC0
- 4240
- BDC0
The full solution
完整的解决方案
The following code combines all of the above into one method:
以下代码将上述所有内容合并为一种方法:
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);
}
Buffer to a [BigInteger
] hex representation
缓冲到 [ BigInteger
] 十六进制表示
As an additional bonus answer to the related question: "How to convert byte[]
to a hex string [using BigInteger
]?"
作为对相关问题的额外奖励回答:“如何byte[]
[使用BigInteger
]转换为十六进制字符串?”
The following code will convert a byte[]
to a hex String
:
以下代码将 a 转换byte[]
为十六进制String
:
byte[] buffer = new byte[]{1, 2, 3};
String hex = String.format("%0" + buffer.length*2 + "X", new BigInteger(1, buffer));
Note that it is very important to set the signum argument to 1 so that BigInteger
understands that the values in the array are to be parsed in as 'unsigned'.
请注意,将 signum 参数设置为 1 非常重要,以便BigInteger
理解数组中的值将被解析为“无符号”。
Note also that this method creates two temporary buffers to create the string and that you might be better off parsing the array directly into a Character[]
, if you are dealing with very large arrays.
另请注意,此方法会创建两个临时缓冲区来创建字符串Character[]
,如果您正在处理非常大的数组,最好将数组直接解析为 a 。
回答by John Vasileff
To defeat new BigInteger(long)
's interpretation of the argument as being encoded in two's complement, you can first convert the upper 63 bits of the number in a way that avoids using long
's sign bit, and then "add" the last bit:
要破坏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
}
回答by LINEMAN78
One Liner(however don't forget to consider endiness issues with the source, which can be handled using ByteBuffer.byteOrder):
一个班轮(但是不要忘记考虑源的endiness问题,可以使用ByteBuffer.byteOrder处理):
new BigInteger(1, ByteBuffer.allocate(Long.SIZE/Byte.SIZE).putLong(Long.parseLong("-1")).array());
回答by Gerhard Powell
You can always manually do two's complement. If the number is smaller than 0, then inverse all the bits and add one.
您始终可以手动进行二进制补码。如果数字小于 0,则将所有位取反并加 1。
回答by Ahmet Karakaya
Is it what you what?
是你什么?
public static void main(String[] args) {
BigInteger bg = BigInteger.valueOf(-1);
System.out.println(Integer.toHexString(bg.intValue()));
}
回答by user3158036
You can use this utility to convert to an unsigned integer. Since BigIntegers have unlimited size, a size must be specified to determine how much sign extension to keep in the translation:
您可以使用此实用程序转换为无符号整数。由于 BigIntegers 的大小不受限制,因此必须指定一个大小来确定要在翻译中保留多少符号扩展:
public static BigInteger toPositive(BigInteger num, int sizeInBytes) {
return num.andNot(BigInteger.valueOf(-1).shiftLeft(sizeInBytes * 8));
}
回答by MariuszS
The simples solution is from @Ahmet Karakaya, but should be fixed for bigger numbers:
简单的解决方案来自@Ahmet Karakaya,但应该针对更大的数字进行修复:
BigInteger bg = BigInteger.valueOf(-1);
System.out.println(Long.toHexString(bg.intValue()));
Result: ffffffffffffffff
结果: ffffffffffffffff
or simply:
或者干脆:
System.out.println(Long.toHexString(-1))