Reputation: 31390
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
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
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
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
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.
Upvotes: 1
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
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
Reputation: 1764
Works for me:
long a = 0x7fffffffffffffffL;
long b = 0x8000000000000000L;
b - a = (long) 1
a - b = (long) -1
Upvotes: 2
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
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