Этот вопрос:
Как вы устанавливаете, очищаете и переключаете один бит?
обсуждает три операции над конкретным битом в пределах большего значения, которые прямо соответствуют OR 1, AND 0 и XOR 1 на этом бите. Но что, если мы не знаем, что значение второго бита заранее? Что делать, если мы хотим выполнить назначение , где мы не знаем другой бит операнда во время компиляции? То есть, мы хотим установить один бит в определенной позиции бит-блок на значение нового несвязанного бита, предоставленного во время выполнения?
Я хотел бы иметь самую быструю возможную реализацию для этого, скажем, Intel x86_64 (и игнорирование векторизации, которое, я надеюсь, здесь не имеет значения). Кроме того, предположим, что для простоты тип битового блока - uint32_t
.
Изменить: Сделал мой ответ C, а не C ++, так как на самом деле ничего не сказано об C ++.
Всего 1 ответ
Вот две возможные реализации для случая 32-разрядного типа блока:
#include <cstdint>
uint32_t bit_assign_v1(uint32_t block, uint8_t bit_index, bool x)
{
uint32_t mask = uint32_t { 1 } << bit_index;
return (block & ~mask) | (((uint32_t) x) << bit_index);
}
uint32_t bit_assign_v2(uint32_t block, uint8_t bit_index, bool x)
{
uint32_t mask = uint32_t { 1 } << bit_index;
return x ? (block & ~mask) : (block | mask);
}
Используя GodBolt, я получаю по-разному оптимизированный код для каждого из этих двух вариантов, который также отличается по мере изменения платформ и компиляторов. Вот пример для Skylake (или, еще лучше, посмотрите на эту версию , которая является одним и тем же кодом, но разделена на несколько операторов C, чтобы вы могли лучше связать сборку с кодом C).
GCC 8.2 сборка:
bit_assign_1:
movzx eax, sil
btr edi, eax
movzx edx, dl
shlx eax, edx, eax
or eax, edi
ret
bit_assign_2:
mov ecx, 1
shlx esi, ecx, esi
andn eax, esi, edi
or esi, edi
test dl, dl
cmove eax, esi
ret
clang 7.0 сборка:
bit_assign_1: # @bit_assign_1
btr edi, esi
shlx eax, edx, esi
or eax, edi
ret
bit_assign_2: # @bit_assign_2
mov eax, edi
btr eax, esi
bts edi, esi
test edx, edx
cmovne edi, eax
mov eax, edi
ret
Я пока ничего не сравнил.