Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Representing 3 Integers Using One Byte?

I have three integers {a, b, c} that range (say) between the following values:

a - {1 to 120, in jumps of 1}

b - {-100 to 100, in jumps of 5}

c - {1 to 10, in jumps of 1}

Due to space considerations, I would like to represent these three values using 1-byte ONLY, meaning, a single integer (in the range of -127..128) will represent the results of {a, b, c} and be stored in a binary format to disk.

Later, when I read the binary data, I will know how to 'parse' this 1-byte to get the values of {a, b, c}.

Any idea how to achieve that? (note: if need be, in order to support this design, I can 'compromise' on the ranges; for example, say, a can be in jumps of 5. b can also be in jumps of 10 etc)

like image 630
user3262424 Avatar asked Dec 28 '22 23:12

user3262424


1 Answers

Just from a numbers point of view we have:

a = 120 values, b = 41 values, c = 10 values

That makes for a total of 49,200 unique values. A byte can only represent 256 values, so you'd need to use at least 16-bits (two bytes) to represent your range.

One way to do so would be through bit shifting.

As an example, you can store four 8-bit values in a 32-bit value, and extract them like so:

#include <iostream>
using namespace std;


int pack32(char *v)
{
    return (v[0] << 24) + (v[1] << 16) + (v[2] << 8) + v[3];
}

void unpack32(int a, char *v)
{
    v[0] = a >> 24;
    v[1] = a >> 16;
    v[2] = a >> 8;
    v[3] = a;
}

int main()
{
    char v[4] = {32, 64, 16, 8};

    cout << "Original values: ";
    for (int i = 0; i < 4 ; i++)
        cout << (int)v[i] << " ";
    cout << endl;

    int q = pack32(v);
    cout << "Packed: " << q << endl;

    unpack32(q, v);
    cout << "Unpacked: ";
    for (int i = 0; i < 4; i++)
        cout << (int)v[i] << " ";

    return 0;
}

Code relevant to your needs:

unsigned short pack32(unsigned a, char b, unsigned c)
{
    // Layout:
    // Bits 0 - 5 are reserved for a
    // Bits 6 - 12 are reserved for b
    // Bits 13 - 15 are reserved for c

    // Assumptions:
    // a is [2, 120] in steps of 2
    // b is [-100, 100] in steps of 5
    // c is [1, 10] in steps of 1

    // Shift a from [2, 120] to [0, 59]
    unsigned a2 = (a - 2) >> 1;
    // Shift b from [-100, 100] to [0, 40]
    unsigned b2 = b / 5 + 20;
    // Shift c from [1, 10] to [0, 9]
    unsigned c2 = c - 1;

    return a2 + (b2 << 5) + (c2 << 12);
}
like image 156
Mike Bailey Avatar answered Dec 31 '22 10:12

Mike Bailey