2

I am working in an int[][][] array and I need to return an address of one field of that array from a static function. Given the fact that the dimensions of the Array will stay small (int[32][32][32]) I had the idea to return one number containing all three Values, instead of using an Array containing the three numbers.

I already had a working solution, where i packed my number into a String and unpacked it in the receiving method via Integer.parseInt(String). Unfortunately this didn't work quite, well in terms of runtime, so i thought of bitshifting.

I apologize for my bad english and hope this simple question is worth your time :)

Shree Krishna
  • 8,474
  • 6
  • 40
  • 68
guitarjunk
  • 68
  • 7
  • What code have you tried so far? – ManoDestra May 18 '16 at 16:28
  • Bitshifting will be usable depending on how big the numbers are. I mean, if you need to store values from 0-99, you can save `34`, `72` and `03` in a number like `347203`. – UDKOX May 18 '16 at 16:42
  • you can also use string, it will be much easier to handle – Sarthak Mittal May 18 '16 at 16:52
  • @UDKOX is right - a simple encoding in base 100 is fine for your use case - on many machines division by small constants (100, 1000) isn't expensive at all and this solution has the advantage that it sure as hell is easier to figure out what your encoded index is while debugging if it is in base 100 rather than base 64 or base 256! – davidbak May 18 '16 at 16:52
  • @UDKOX that's exactly what my idea was! my numbers are in a range from 0 to 31 – guitarjunk May 18 '16 at 17:56
  • @Sarthak i already implemented a solution where i converted to a string. That caused problems because my programm is doing this job exactly 100.000.000 times so i had a long runtime, just for this operation. – guitarjunk May 18 '16 at 18:01

2 Answers2

6

If your numbers are in the range 0...255, this example will encode three numbers into one int and then decode it again...

public class BitDemo {

    public static void main(String[] args) {
        int encoded = encode(20, 255, 10);
        int[] decoded = decode(encoded);

        System.out.println(Arrays.toString(decoded));
    }

    private static int[] decode(int encoded) {
        return new int[] {
                encoded & 0xFF,
                (encoded >> 8) & 0xFF,
                (encoded >> 16) & 0xFF
        };
    }

    private static int encode(int b1, int b2, int b3) {
        return (b1 & 0xFF) | ((b2 & 0xFF) << 8) | ((b3 & 0xFF) << 16);
    }
}

(b1 & 0xFF) - Gets the first 8 bits of b1

((b2 & 0xFF) << 8) - Gets the first 8 bits of b2 and shifts them left 8 bits

((b3 & 0xFF) << 16) - Gets the first 8 bits of b3 and shifts them left 16 bits

These three numbers are ORed together.

If you have negative numbers or number more than 255, you'll get different results.

BretC
  • 4,141
  • 13
  • 22
  • Thanks for this solution it works just like intended ! I don't seem too understand why the `int encoded !=2025510` in your example. This would make debugging a lot easier. – guitarjunk May 18 '16 at 18:17
  • Easy to understand and nicely written. +1. Couple questions, this only uses 3 / 4 bytes of the int right ? – UDKOX May 19 '16 at 01:43
  • @UDKOX yes, you can add a fourth bytem i.e. `((b3 & 0xFF) << 24)` – BretC May 19 '16 at 10:15
2

Given N, M and O and assuming N * M * O doesn't overflow, you can pack and unpack your indices like this:

int packed = o * (N * M) + m * N + n;
int o = packed / (N * M);
int m = (packed % (N * M)) / N;
int n = packed % N; // is equal to (packed % (N * M)) % N

If you want to use bit-shifting, make sure you chose N, M, O as powers of 2. Let's say N = 2^NS, M = 2^MS and O = 2^OS packing and unpacking would look like this:

int packed = (o << (NS + MS)) | (m << NS) | n;
int o = (packed >> (NS + MS)) & ((1 << OS) - 1);
int m = (packed >> NS) & ((1 << MS) - 1);
int n = packed & ((1 << NS) - 1);

All of the above assume n=0..N-1, m=0..M-1 and o=0..O-1.

BeyelerStudios
  • 4,243
  • 19
  • 38