Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I read a Java long as unsigned and store its value in a BigInteger?

Tags:

java

types

I have to handle an 8-byte unsigned integer type in Java somehow.

My 8-byte unsigned integer is stored in a byte array wrapped by ByteBuffer. It comes from a data logger database and contains very big numbers.

This is how I deal with 4-byte integers to read them them as unsigned:

((long) (bytebuffer.getInt() & 0xFFFFFFFFL));

Unfortunately this:

((BigInteger) (bytebuffer.getLong() & 0xFFFFFFFFFFFFFFFFL));

doesn't work.

How can I store the number 2^64-1 and read it as 2^64-1?

like image 244
Kamil Avatar asked Jul 06 '18 23:07

Kamil


People also ask

Does Java have unsigned long?

Although Java has no unsigned long type, you can treat signed 64-bit two's-complement integers (i.e. long values) as unsigned if you are careful about it. Many primitive integer operations are sign agnostic for two's-complement representations.

What is unsigned BigInteger?

Description. A large integer. The signed range is -9223372036854775808 to 9223372036854775807 . The unsigned range is 0 to 18446744073709551615 . If a column has been set to ZEROFILL, all values will be prepended by zeros so that the BIGINT value contains a number of M digits.

What is the difference between long and BigInteger?

BigInteger is capable of holding far bigger numbers than Long. BigInteger seems capable of holding (2 ^ 32) ^ Integer. MAX_VALUE, though that depends on the implementation (and, even if truly unbounded in the implementation, there will eventually be a physical resource limit) See explanation here.

How do you convert long to big integers?

To convert a given long value to BigInteger we can use the method java. math. BigInteger. valueOf() which instantiates a BigInteger from a given long value.


2 Answers

You can convert it to an unsigned string and then parse it to BigInteger:

new BigInteger(Long.toUnsignedString(bytebuffer.getLong()))

Probably not the most efficient solution, but possibly the simplest.

Or you can borrow this implementation out of the Long class:

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)));
    }
}
like image 59
shmosel Avatar answered Nov 10 '22 02:11

shmosel


In Java's signed longs, the most significant bit is worth -(263). If it were unsigned, then that bit would be worth positive 263. The difference is 264.

First, create a BigInteger using the long value. Then, if it's negative, apply the unsigned correction by adding 264, or 1 << 64, to the BigInteger.

BigInteger result = BigInteger.valueOf(bytebuffer.getLong());
if (result.compareTo(BigInteger.ZERO) < 0) {
    result = result.add(BigInteger.ONE.shiftLeft(64));
}
like image 36
rgettman Avatar answered Nov 10 '22 04:11

rgettman