BigInteger as unsigned long in Java

I’m working on processing video files in Java.  Often, video files will have "unsigned int" or other types that don’t exist in Java.  Unsigned int is easy enough to simulate (using a long), but what about an unsigned long?  No Java primitive integer type is large enough to hold the value of an unsigned long.  Double could do it, but then you lose the ability to use bitwise shift operators and have them do what you expect.

Enter java.math.BigInteger.  BigInteger is a standard, but often overlooked, part of the Java.  The following sample shows how I use BigInteger to simulate an unsigned long in Java.

import java.math.*;

public class ReadUnsignedLong {

    public static void main(String[] args) {
        byte input[] = {(byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff}; // 64 bits, signed long = -1
        BigInteger signed = new BigInteger(input);
        BigInteger unsigned = new BigInteger(1, input);
        System.out.println("Max Long : " + Long.MAX_VALUE);
        System.out.println("Min Long : " + Long.MIN_VALUE);
        System.out.println("Signed   : " + signed);
        System.out.println("Unsigned : " + unsigned);
        
        System.out.println("Unsigned > Long.MAX_VALUE ? " + ((unsigned.compareTo(BigInteger.valueOf(Long.MAX_VALUE))==1) ? "true" : "false"));
        System.out.println("Signed == -1 ? " + (signed.compareTo(BigInteger.valueOf(-1)) == 0 ? "true" : "false"));
                
        System.out.println("Signed * 2 : " + (signed.multiply(BigInteger.valueOf(2))));
        System.out.println("Unsigned * 2 : " + (unsigned.multiply(BigInteger.valueOf(2))));

    }

}

Note that the trick here is to use the BigInteger(signum, byte[]) constructor.  By forcing the signum to positive (using a 1), you get the unsigned value of the byte array.

The output:

Max Long : 9223372036854775807

Min Long : -9223372036854775808

Signed   : -1

Unsigned : 18446744073709551615

Unsigned > Long.MAX_VALUE ? true

Signed == -1 ? true

Signed * 2 : -2

Unsigned * 2 : 36893488147419103230