mekings
mekings

Reputation: 446

Encoding a set of three integers to one unique number

So, my problem set is very simple. I am working with a set of three integers randomly selected from [0-65535] and my Job is to encode this integers into one unique number. Here is what I have tried so far

I have written a java function called pack to try and encode this numbers as follows

 private long pack(long a, long b, long c) {
        int N = 65535, M = 65536;
        return (a + (b * N) + c * N * M);
    }

And I have also written another java function to unpack or decode the packed number back to the original integers as follows

private long[] unpack(long packed) {
    int N = 65535, M = 65536;
    long a = (packed % N);
    long b = (packed / N) % M;
    long c = (packed % (N * M));
    return new long[]{a, b, c};
}

Now when I ran the code above in my main function using sample data {67, 8192, 7168} I am getting the following as result in my console output

Packing 67, 8192, 7168
Result=30786392678467

UnPacking 30786392678467
Result=[67, 8192, 57411]

From the above, clearly my first and second values are always correct but the last value always appear to be wrong. What am I possibly missing out.Your help is greatly appreciated. Thanks alot.

Upvotes: 4

Views: 1552

Answers (3)

averasko
averasko

Reputation: 970

actually, your solution is almost correct: just make sure that M == N == 65536 and fix the problem in unpacking variable c.

private long pack(long a, long b, long c) {
    long N = 65536;
    return (a + (b * N) + c * N * N);
}

private long[] unpack(long packed) {
  long N = 65536;
  long a = (packed % N);
  long b = (packed / N) % N;
  long c = (packed / (N * N));
  return new long[]{a, b, c};
}

Also, I changed the type of N to long although it would not matter as Java will convert it to long during multiplication anyway.

Upvotes: 1

Jacob G.
Jacob G.

Reputation: 29700

I'm going to give you an alternative solution now, and then I can try to debug your current solution when I'm on a PC instead of a phone (rgettman beat me!).

Because each of the three numbers can be a maximum of 65535, that means that each number will fit into 16 bits. For that reason, you can simply build a unique long with the following:

long encoded = (a << 32L) | (b << 16) | c;

And decoding it would look like the following:

long a = (encoded >> 32) & 0xFFFFL;
long b = (encoded >> 16) & 0xFFFFL;
long c = encoded & 0xFFFFL;

Upvotes: 4

rgettman
rgettman

Reputation: 178263

Your packing and unpacking code is incorrect according to the range [0, 65535] you've given.

There are 65,536 possible numbers, and you don't want the encoding of one integer to change the encoding of another integer. You should use one constant set to 65536 (which is 216).

public static final long PACK = 65536;

Then your pack method changes slightly to:

private long pack(long a, long b, long c) {
    return (a + (b * PACK) + c * PACK * PACK);
}

This "packs" a into the least significant 16 bits of the long (bits 49-64), b into bits 33-48, and c into bits 17-32. (Nothing is packed into bits 0-16, so those bits remain cleared.)

Also, your unpack method changes to:

private static long[] unpack(long packed) {
    long a = (packed % PACK);
    long b = (packed / PACK) % PACK;
    long c = (packed / (PACK * PACK));  // Use / not %.
    return new long[]{a, b, c};
}

Notice that c's operation divides by PACK squared, not using the % operator, but using /. Otherwise both M and N have each been replaced by PACK.

Output with these changes:

Packing 67, 8192, 168
Result=722091376707

UnPacking 722091376707
Result=[67, 8192, 168]

Upvotes: 3

Related Questions