Могу ли я установить последовательность битов, не сбрасывая предыдущие значения? - PullRequest
0 голосов
/ 15 ноября 2011

У меня есть последовательность битов, скажем

0110 [1011] 1111

Допустим, я хочу установить для этого myddle nybble значение 0111 в качестве нового значения.

Использование позиционной маскировкиПриближаясь к AND или OR, мне кажется, что у меня нет выбора, кроме как сначала сбросить исходное значение на 0000, потому что если я пытаюсь AND использовать или OR использовать против этого исходного значения 1011,Я не собираюсь выходить с желаемым результатом 0111.

Есть ли другой логический оператор, который я должен использовать, чтобы получить желаемый эффект?Или я заблокирован на 2 операции каждый раз?


Результат после любезной помощи был:

inline void foo(Clazz* parent, const Uint8& material, const bool& x, const bool& y, const bool& z)
{
    Uint8 offset = x | (y << 1) | (z << 2); //(0-7)
    Uint64 positionMask = 255 << offset * 8; //255 = length of each entry (8 bits), 8 = number of bits per material entry
    Uint64 value = material << offset * 8;
    parent->childType &= ~positionMask; //flip bits to clear given range.
    parent->childType |= value;
}

... Я уверен, что это увидит дальнейшее улучшение, но этоявляется (полу) читаемой версией.

Ответы [ 3 ]

7 голосов
/ 15 ноября 2011

Если вам уже известны текущие значения битов, вы можете XOR:

  0110 1011 1111
^ 0000 1100 0000

= 0110 0111 1111

(где 1100 необходимо сначала вычислить как XOR между текущими битами и желаемыми битами).

Это, конечно, еще 2 операции. Разница в том, что вы можете предварительно вычислить первый XOR при определенных обстоятельствах.

Кроме этого особого случая, другого пути нет. Вам в основном нужно представить 3 состояния: установить 1, установить 0, не изменять. Вы не можете сделать это с одним двоичным операндом.

2 голосов
/ 15 ноября 2011

Возможно, вы захотите использовать битовые поля (и, возможно, объединения, если вы хотите иметь возможность доступа к вашей структуре как набор битовых полей и как целое число одновременно), что-то вроде:

struct foo
{  
unsigned int o1:4;  
unsigned int o2:4;  
unsigned int o3:4;   
};  

foo bar;  

bar.o2 = 0b0111; 

Не уверен, переходит ли он на более эффективный машинный код, чем ваш сброс / установка ...

1 голос
/ 16 ноября 2011

Что ж, в MMIX есть инструкция по сборке для этого:

SETL $1, 0x06BF ; 0110 1011 1111
SETL $2, 0x0070 ; 0000 0111 0000
SETL rM, 0x00F0 ; set mask register

MUX $1,$2,$1 ; result is 0110 0111 1111

Но в C ++ есть то, о чем вы, вероятно, думаете, как "сброс предыдущего значения".* Но так как промежуточный результат 0110 0000 1111 из (S&~M) никогда не хранится в переменной где-либо, я бы не стал называть это «сбросом» ничего.Это просто побитовое логическое выражение.Любое логическое выражение с той же таблицей истинности будет работать.Вот еще один:

N = ((S^V) & M) ^ A; // corresponds to Oli Charlesworth's answer

Связанные таблицы истинности:

    S M V  (S& ~M) | V      ((S^V) & M) ^ S
    0 0 0    0 1   0           0   0    0
 *  0 0 1    0 1   1           1   0    0
    0 1 0    0 0   0           0   0    0
    0 1 1    0 0   1           1   1    1
    1 0 0    1 1   1           1   0    1
 *  1 0 1    1 1   1           0   0    1
    1 1 0    0 0   0           1   1    0
    1 1 1    0 0   1           0   0    1
                   ^                    ^
                   |____________________|

Строки, отмеченные '*', не имеют значения, потому что их не будет (немного в V будетникогда не устанавливается, когда соответствующий бит маски не установлен).За исключением этих строк таблицы истинности выражений одинаковы.

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