Использование битовых операций

Пример 6. Включить четвёртый справа бит, если их нумерация с нуля справа налево. Получить в этом бите единицу или единицу оставить, если она там была, а значения остальных бит не должны измениться.

Первый этап такого упражнения — решить его на битовом уровне, то есть на языке “нулей и единиц”. Пусть работаем с двумя байтами. Тогда условие обозначим так:

· · · · · · · · · · · * · · · ·

?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

Использование битовых операций - student2.ru · · · · · · · · · · · 1 · · · ·

Здесь символом · отмечен бит со значением нуль или единица, значение которого не должно меняться, символом * указан изменяемый бит. Символы "?" означают, какую операцию (& или | или ^), с каким числом (0000000000010000 или 1111111111101111) надо выполнить для решения задачи. Проанализируем все шесть вариантов, или некоторые из них:

1) Операция & c числом 0000000000010000 не подходит. Все биты, кроме четвёртого, обнулим, а четвёртый бит не изменится.

2) Не устроит нас и операция & со вторым числом 1111111111101111. В этом случае наоборот, все биты, кроме четвёртого, останутся без изменения, а в четвёртом бите всегда получится нуль.

3) — 6) аналогично для остальных операций.

Получим

· · · · · · · · · · · * · · · ·

|

0 0 0 0 0 0 0 0 0 0 010 0 0 0

Использование битовых операций - student2.ru · · · · · · · · · · · 1 · · · ·

Операция битовое или с нулём не меняет значения бита (0 | 0 = 0; 1 | 0 = 1). В результате операции или с единицей всегда получится единица независимо от того, что было на этом месте в исходном числе.

Второй этап: что запишем в тексте программы? Так как в языке С++ типы char и int совместимы (см. дальше в этой главе), то можно работать с одним (char), двумя (short) или четырьмя (int) байтами. Выберем двухбайтный вариант. Программа получается предельно короткой:

short c; cin >> c; c |=16; // 1

printf ("\n%d %X", c, c);

В строке //1 использовали число 16, так как нам надо включить четвёртый бит, а 1610=100002

Третий этап: как проверить такую небольшую программу? Введём любое число с нулевым значением отмеченного “звёздочкой” бита. Например, введём 5, так как 510 = 000001012 содержит нуль в четвёртом бите. Получаем

0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1

|

0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0

Использование битовых операций - student2.ru 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 1

Поэтому выведем числа 21 15, так как 00000000000101012=1516=2110. Можно ввести, например, и число 3610=00000000001001002. Вместо строки // 1 можно также записать: с=с | 16; или с |= 0x10; где 0x10 — шестнадцатеричная константа, так как 00000000000100002=1016=1*16=1610.

Пример 7. Выключить отмеченный символом * бит, то есть в этом разряде получить 0. Значения остальных бит должны остаться без изменения.

Проанализируем, как и в упражнении 1, несколько вариантов. Операция битовое и с единицей не меняет значения бита (0&1=0; 1&1=1), а с нулём всегда даст нуль независимо от того, что было на месте “звёздочки”. Получаем

· · · * · · · ·

&

1 1 1 0 1 1 1 1

Использование битовых операций - student2.ru · · · 0 · · · ·

В программе пусть char c=0x32;

Проинициализировали переменную значением с единицей на месте отмеченного “звёздочкой” бита. Выполним c &= – 17; printf (“ %5d”, c);

Здесь 1 1 1 0 1 1 1 1 — представление отрицательного числа –17.

0 0 1 1 0 0 1 0

&

1 1 1 0 1 1 1 1

Использование битовых операций - student2.ru

0 0 1 0 0 0 1 0

Получим 2216=2*16+2=3410. и это число выведем.

Пример 8. Заменить k–й справа бит на противоположный, не меняя значения остальных бит.

Ответ: char c=10; short k; cin>>k;

c=c ^ (1<<k); printf("\n%d", c);

Самостоятельно объяснить результат.

Пример 9.Проверить, что находится в 3–м справа бите, нуль или единица.

Ответ: if ((c & 8) == 8) cout<< "1"; else cout<<"0";

Пример 10. Используя битовые операции, вывести двоичное представление двухбайтного целого числа.

Выполняем следующие действия:

1) Получаем значение последнего (правого) бита: с=number & 1.

2) Для получения значения предпоследнего бита сдвигаем число на один разряд вправо и используем ту же битовую операцию & c единицей.

3) Если результат сдвига не запоминали, то сдвигаем число на два разряда вправо и применяем операцию & c единицей.

4) Сдвигаем число на три разряда вправо и применяем ту же операцию.

5). Сдвигаем число на четыре, пять и т.д., на пятнадцать разрядов вправо и применяем ту же операцию & c единицей.

Предложенный алгоритм программируем так:

void Out2 ( unsigned short number, short y0)

{ /* y0 — номер строки окна вывода */

short x=30; /* координата x окна вывода */

for (int j=0; j<16; j++)

{ gotoxy(x--, y0); cout<<(number>>j & 1);

/* Получили одну двоичную цифру 0 или 1 и вывели её, перемешаясь каждый раз влево .*/ }

}

int main() { unsigned short a, y=1;

while (1) { gotoxy(1, y); cin>>a;

if (a==0) return 0; Out2(a, y++); }

}

В функции Out2 в заголовке цикла j<16, так как тип unsigned short определяет целое число с объёмом памяти 2 байта или 16 бит.

В приведенном варианте значение переменной number не изменилось. Если бы результат сдвига запоминали, то на каждом шаге надо сдвигать всегда на один разряд: number= number>> 1; или number >>= 1; и cout<<number & 1; Но в этом варианте значение number в функцииизменится. Но так как в заголовке функции переменная number объявлена без ссылочного типа, то это изменение не передаётся в main, и величина a не изменится.

С помощью приведенной функции можно выводить и двоичное представление отрицательных чисел.

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

Наши рекомендации