Hanno Fietz
Hanno Fietz

Reputation: 31390

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?

Upvotes: 5

Views: 7197

Answers (10)

Nick
Nick

Reputation: 780

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);
}

Upvotes: 8

JoCa
JoCa

Reputation: 1135

I used this solution:

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

All credits go to this website

Upvotes: 2

millibit
millibit

Reputation: 175

I use the following code:

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

(based on example by Tamutnefret)

Upvotes: 1

Tim Bender
Tim Bender

Reputation: 20442

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.

Upvotes: 1

ZZ Coder
ZZ Coder

Reputation: 75496

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));
}

Upvotes: 0

Dewfy
Dewfy

Reputation: 23644

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
}

Upvotes: 0

Trevor Harrison
Trevor Harrison

Reputation: 1764

Works for me:

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

Upvotes: 2

Pete Kirkham
Pete Kirkham

Reputation: 49331

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 Ζ264.

Upvotes: 5

Adam Crume
Adam Crume

Reputation: 15844

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 a-b to 0.

Upvotes: 4

Related Questions