Maarten Bodewes
Maarten Bodewes

Reputation: 93968

How to convert an "unsigned" long to BigInteger

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

Answers (2)

aioobe
aioobe

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

Maarten Bodewes
Maarten Bodewes

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

Related Questions