简体   繁体   中英

How do I compare two longs as unsigned in Java?

I'm storing bit patterns of unsigned 64-bit numbers in a long variable and want to calculate the distance between two of them on the unsigned range. Because Java interprets long as a two's complement signed integer, I can't just do a - b , as the following example shows:

// on the unsigned range, these numbers would be adjacent
long a = 0x7fffffffffffffffL;
long b = 0x8000000000000000L;

// but as two's complement (or any representation that 
// stores the sign in the first bit), they aren't
assert b - a == 1;

What's the correct way to do this?

As the arithmetic wraps round, it works out the same for the case you give. If you interpret the result as an unsigned value, it will be true for all cases - you're just changing the interpretation of the bit pattern, it's still a set homomorphic to 2 64 . 2 64同态的集合。

Starting with Java 8 , the comparison of long as unsigned integers can be done via Long.compareUnsigned(x, y) .

Here is a simple backport for Java 7 and earlier:

public static int compareUnsigned(long x, long y) {
   return Long.compare(x + Long.MIN_VALUE, y + Long.MIN_VALUE);
}

If you're dealing with addition and subtraction, it doesn't matter whether you're using signed or unsigned types, as long as the arguments are both signed or both unsigned. If you need to compare a and b, compare ab to 0.

Works for me:

long a = 0x7fffffffffffffffL;
long b = 0x8000000000000000L;
b - a = (long) 1
a - b = (long) -1

I used this solution:

if (longA == longB) return 0;
return (longA < longB) ^ (longA < 0) ^ (longB< 0) ? 1 : -1;

All credits go to this website

As previously mentioned, you won't have a problem with subtraction, so if that is all you are trying to do, then don't worry.

But, by your example, addition will overflow, and none of the relational operators will work properly. If this is a concern then you can write your own relational ops, or use a better box type than Long.

Solutions: 1. Use BigInteger instead of Long. BigInteger was created for doing calculations with large numbers and can easily support 128bit calculations.

  1. Write your own relational operations and exclude the used of addition or multiplication as a possibility. Writing your own relational operator is really not that hard. First you compare the most significant bit. If the most significant bit is the same for both numbers, you can mask it by doing a bitwise and (&) with 0X7FFFFFFFFFFFFFFF and then compare the masked values.

I use the following code:

static boolean unsignedLessThan(long left, long right) { 
    return (left < right) ^ (left < 0) ^ (right < 0);
}

(based on example by Tamutnefret)

Obviously you need deal with bits.

static boolean compare(long a, long b)
{
    if(( a &  (Long.MAX_VALUE + 1)) != 0)
        return ( b & (Long.MAX_VALUE + 1) )  != 0
            ? (a < b) //same sign 
            : true; //a is greater b
    else 
        return ( b & (Long.MAX_VALUE + 1) )  != 0
            ? false //b is greater a
            : a < b; //same sign
}

Or you can do half and half like this,

public static long unsignedDiff(long a, long b) {
    long mask = 0xFFFFFFFFL;
    return (( ((a >> 32) & mask) - ((b >> 32) & mask) ) << 32) +
       + ((a & mask) - (b & mask));
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM