Упаковать/распаковать short в int

Я хочу упаковать/распаковать два 16-битных целых числа со знаком в 32-битное целое число. Тем не менее, я не заставляю его работать.

Любые идеи относительно того, что я могу делать неправильно?

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));
}

Возврат/аргументы функции должны быть такими, как я определил. lo и hi записываются из разных потоков (таким образом, atomic_or), и чтение должно возвращать одно 32-битное значение.

Целая 16-битная арифметика не поддерживается на целевой платформе.

Пример:

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);

person ronag    schedule 31.08.2012    source источник
comment
Не могли бы вы привести пример ввода и вывода?   -  person Jens Agby    schedule 31.08.2012
comment
Что-то внутри меня возражает против идеи одновременной упаковки данных в один int...   -  person Kerrek SB    schedule 31.08.2012
comment
Керрек С.Б.: Код запускается на графическом процессоре.   -  person ronag    schedule 31.08.2012
comment
Вы просто хотите сохранить их и передать кому-то другому? Как вы относитесь к знакам? Можете ли вы просто поместить его в uint16_t[2]? Судя по вашему вопросу, вы просто их упаковываете, поэтому я бы рекомендовал работать с неподписанными данными.   -  person Josh Petitt    schedule 31.08.2012
comment
Данные подписаны, что делает это немного сложным, и их нужно поместить в беззнаковый массив int или int.   -  person ronag    schedule 31.08.2012


Ответы (4)


Эти атомарные операции в C++ AMP также имеют следующие ограничения:

  • Не следует смешивать атомарные и обычные (неатомарные) операции чтения и записи. При обычном чтении могут не отображаться результаты атомарной записи в ту же ячейку памяти. Обычную запись не следует смешивать с атомарной записью в одну и ту же ячейку памяти. Если ваша программа не соответствует этим критериям, это приведет к неопределенному результату.
  • Атомарные операции не предполагают каких-либо ограждений памяти. Атомарные операции могут быть переупорядочены. Это отличается от поведения взаимосвязанных операций в C++.

Похоже, вы нарушаете первое из них.

person Ade Miller    schedule 04.09.2012
comment
Ада, конечно, права. По любым другим проблемам с atomics обращайтесь к сообщению в блоге, в котором есть эта и другая информация: blogs.msdn.com/b/nativeconcurrency/archive/2012/01/04/ - person Daniel Moth; 07.09.2012

Это кажется слишком сложным, и там есть странные операции.

Обычно вы просто делаете это так:

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);
}

Обратите внимание, что я использовал типы с явными битовыми размерами, чтобы проиллюстрировать, что происходит. Я также позволил себе предположить, что вам нужно «целое число», а не «целое число без знака».

person Christian Stieber    schedule 31.08.2012

Код ниже отлично работает для меня в MSVC. Как видите, в принципе он такой же, как ваш код.

Может ли проблема заключаться в том, что вы забыли инициализировать содержимое массива нулем? Как ваша платформа обрабатывает отрицательные числа и приведение к беззнаковому целому?

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

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

int main()
{
    int ar[2] = { 0,0 }; // container

    write_s16<int [2]>(ar, 0, -16);
    write_s16<int [2]>(ar, 1, 5);

    assert(read_s16<int [2]>(ar, 0) == -16);
    assert(read_s16<int [2]>(ar, 1) == 5);

    return 0;
}
person Jens Agby    schedule 31.08.2012
comment
Хм, у меня это тоже работает при работе на процессоре, ломается на графическом процессоре. Возможно, GPU по-другому обрабатывает знак сдвига вправо. - person ronag; 31.08.2012

Попробуйте это для упаковки:

int_32 = (int16_1 & 0x0000FFFF) | (int16_2 & 0xFFFF0000);

Для распаковки:

int16_MSB = (int_32 >> 16) & 0xFFFF;
int16_LSB = int_32 & 0xFFFF;
person Harsh Wardhan    schedule 29.05.2014