Работа с двумя шортами одновременно путем объединения их в целое число - PullRequest
0 голосов
/ 03 января 2019

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

inline uint32_t to_score(int16_t mg, int16_t eg) {
    return ((1u * mg) << 16 | (eg & 0xFFFF));
}

inline int16_t extract_mg(uint32_t score) {
    return int16_t(score >> 16);
}

inline int16_t extract_eg(uint32_t score) {
    return int16_t(score & 0xFFFF);
}

Мне нужно выполнить различные вычисления на обоихmg и eg частей одновременно, перед интерполяцией двух частей в конце функции.

Насколько я понимаю, до тех пор, пока нет переполнения, было бы безопасно добавить две uint32_t s создал to_score, а затем извлек int16_t s, чтобы найти результаты отдельных вычислений: то есть результаты, если бы я добавил значения для mg и eg отдельно.

IЯ не уверен, верно ли это предположение, если либо mg, либо eg отрицательны, либо этот метод можно использовать для вычитания, умножения и / или деления.

Какие операции можно ожидать для правильного функционирования?Существуют ли альтернативные способы представления двух целых чисел, которые можно быстро сложить / вычесть / умножить?

Ответы [ 2 ]

0 голосов
/ 03 января 2019

Будет проблема с переносом из нижней половины в верхнюю, но этого можно избежать с помощью дополнительных операций, как подробно описано, например, chessprogramming.org / SIMD_and_SWAR_Techniques

z = ((x &~H) + (y &~H)) ^ ((x ^ y) & H)

Где в этом случае H = 0x80008000.

В качестве другой альтернативы это можно сделать с двумя добавлениями, но с оптимизированным извлечением / рекомбинацией:

// low half addition, leaving upper half corrupted but it will be ignored
l = x + y
// high half addition, adding 0 to the bottom so no carry
h = x + (y & 0xFFFF0000)
// recombine
z = (l & 0xFFFF) | (h & 0xFFFF0000)

Вычитание равнонезначительное изменение при добавлении.

Умножение, к сожалению, заботится об абсолютных битовых позициях, поэтому значения должны быть перемещены (смещены) в их условную позицию, чтобы это работало. Фактический SIMD все еще можно использовать, например, _mm_mullo_epi16 с SSE2.

0 голосов
/ 03 января 2019

C ++ целые числа со знаком являются дополнением к двум, они находятся на пути к стандартизации в C ++ 20, на практике вы уже можете предположить, что.

Некоторые случаи сложения и вычитания будут работать, те случаи, которыене вызывайте одно из следующих: например, переполнение, мг - переполнение, мг - изменение знака.

Оптимизация не имеет большого смысла.

Если массив больше, вы можете попытаться векторизовать свои операции с помощью правильной SIMD-инструкции, если они доступны для вашей платформы, включив оптимизацию компилятора или используя встроенные функции (_mm_adds_pi16 может быть тем, что вам нужно).

Если у вас есть только два целых числа, просто вычислите их одно за другим.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...