views:

464

answers:

7

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?

+1  A: 

http://www.darksleep.com/player/JavaAndUnsignedTypes.html

Jesse
The workaround that darksleep offers is to cast the signed type to a type that uses twice as many bytes, e.g. use a short (2 bytes) to hold an unsigned byte, or an int (4 bytes) to hold an unsigned short. However, Java doesn't have a built-in 16-byte numeric type that the OP could use to store unsigned longs (8 bytes) in.
Matt Ball
That link is interesting but Matt is right.
Hanno Fietz
+4  A: 
Pete Kirkham
do you really have to throw around phrases like "homomorphic"? :-)
Trevor Harrison
"Homomorphic" is a word, not a phrase.
Matt Ball
+1  A: 

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.

Adam Crume
Adding and subtracting is really the only thing I need. I store the delta to later reconstruct the original value from it.
Hanno Fietz
+3  A: 

Works for me:

long a = 0x7fffffffffffffffL;
long b = 0x8000000000000000L;
b - a = (long) 1
a - b = (long) -1
Trevor Harrison
Totally correct, I had a bug in the code I extracted the example from. See my comment above.
Hanno Fietz
A: 

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
}
Dewfy
+1  A: 

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));
}
ZZ Coder
+1  A: 

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.
Tim Bender