Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pack/unpack short into int

I want to pack/unpack two signed 16 bit integers into a 32 bit integer. However, I'm not getting it to quite work.

Any ideas as to what I might be doing wrong?

template <typename T>
int read_s16(T& arr, int idx) restrict(amp)
{
    return static_cast<int>((arr[idx/2] >> ((idx % 2) * 16)) << 16) >> 16;
}

template<typename T>
void write_s16(T& arr, int idx, int val) restrict(amp)
{
    // NOTE: arr is zero initialized
    concurrency::atomic_fetch_or(&arr[idx/2], (static_cast<unsigned int>(val) & 0xFFFF) << ((idx % 2) * 16));
}

The function return/arguments must be as I have defined. The lo and hi are written from different threads (thus the atomic_or), and the read must return a single 32 bit value.

16 bit integer arithmetics are not supported on the target platform.

Example:

array<int> ar(1); // Container

write_s16(ar, 0, -16);
write_s16(ar, 1, 5);

assert(read_s16(ar, 0) == -16);
assert(read_s16(ar, 1) == 5);
like image 411
ronag Avatar asked Sep 02 '25 15:09

ronag


1 Answers

It seems overly complicated, and there are strange operations in there.

Usually, you'd just do it like this:

int32_t Pack(int16_t a, int16_t b)
{
   return (int32_t)((((uint32_t)a)<<16)+(uint32_t)b);
}

int16_t UnpackA(int32_t x)
{
   return (int16_t)(((uint32_t)x)>>16);
}

int16_t UnpackB(int32_t x)
{
   return (int16_t)(((uint32_t)x)&0xffff);
}

Note that I used the types with explicit bit sizes to illustrate what's going on. I also took the liberty to assume that you want an "integer", not an "unsigned integer".

like image 81
Christian Stieber Avatar answered Sep 05 '25 07:09

Christian Stieber