Reputation: 93968
If I have a Java long
value - say x
- which should be interpreted as an unsigned value (i.e. 0x8000_0000_0000_0000
and higher should be interpreted as positive value) then how can I convert it to BigInteger
?
Obviously, BigInteger.valueOf(x)
would result in a negative value, and conversion to hexadecimals or bytes seems wasteful.
Upvotes: 3
Views: 13055
Reputation: 420981
This conversion is actually implemented in java.lang.Long
in OpenJDK: Long.java:241. It's private though, so pasting it here:
/**
* Return a BigInteger equal to the unsigned value of the
* argument.
*/
private static BigInteger toUnsignedBigInteger(long i) {
if (i >= 0L)
return BigInteger.valueOf(i);
else {
int upper = (int) (i >>> 32);
int lower = (int) i;
// return (upper << 32) + lower
return (BigInteger.valueOf(Integer.toUnsignedLong(upper))).shiftLeft(32).
add(BigInteger.valueOf(Integer.toUnsignedLong(lower)));
}
}
An extensive article on unsigned long
and alternatives is available on my blog: Unsigned long in Java
Upvotes: 6
Reputation: 93968
Actually, the conversion is pretty simple. You can use masking similar to converting unsigned integers to long:
Let's first create the mask as constant (this simply results in the least significant 32 bits set to 1):
private static final long UNSIGNED_INT_MASK = (1L << Integer.SIZE) - 1L;
then we can perform:
int unsignedInt = 0x8000_0000; // sample input value
long l = (long) unsignedInt & UNSIGNED_INT_MASK;
So for BigInteger
we can create the mask like this (64 least significant bits set to 1):
// use "import static java.math.BigInteger.ONE;" to shorten this line
private static final BigInteger UNSIGNED_LONG_MASK = BigInteger.ONE.shiftLeft(Long.SIZE).subtract(BigInteger.ONE);
great, then the rest will be easy:
long unsignedLong = 0x8000_0000_0000_0000L; // sample input value
BigInteger bi = BigInteger.valueOf(unsignedLong).and(UNSIGNED_LONG_MASK);
It's not rocket science, but sometimes you just want to find a quick and easy answer.
Upvotes: 7