Побитовые операции

a b a|b a&b a^b ~a
           
           
           
           

Операция побитового логического отрицания (~) является унарной. В результате этой операции каждый бит, имеющий значение 1, становится равным 0 и наоборот. Данная операция называется также дополнением до единицы или инверсией.

Результатом операции сдвига влево (<<) является левый операнд, сдвинутый влево на число позиций, которое указано в правом операнде. Освобождающиеся младшие разряды заполняются нулями [24, 25]. Данная операция может применяться для умножения на число, равное степени числа 2, в соответствии с правилом:

x << n эквивалентно умножению х на 2 в степени n.

Результатом операции сдвига вправо (>>) является левый операнд, сдвинутый вправо на число позиций, которое указано в правом операнде. Освобождающиеся старшие разряды заполняются нулями для переменных типа unsigned либо значением старшего (знакового) бита для данных другого типа [24, 25]. Данная операция может применяться для деления на число, равное степени числа 2, в соответствии с правилом:

x >> n эквивалентно делению х на 2 в степени n.

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

Листинг 8.1. Для печати содержимого памяти, отведенной под переменную типа unsigned int,может быть использована функция, в которой создается массив, и элементы массива заполняются следующим образом:

§ Создается шаблон, содержащий единицу в старшем разряде.

§ Проверяется побитовое умножение исходного числа на шаблон и в массив заносится символ ‘1’, если это произведение отлично от нуля, и ‘0’ – в противном случае.

§ Затем шаблон сдвигается вправо на один бит.

§ Для более легкого чтения информации после каждых 8 битов в массив заносится пробел.

§ Операция повторяется до тех пор, пока шаблон отличен от нуля.

//L8_1.cpp

void print_bit(unsigned int x)

{

unsigned int sh=~0, i=0, k=0;

sh=~(sh>>1); // Шаблон с 1 в старшем разряде

char s[40];

while(sh>0)

{

s[i++]=sh&x?'1':'0';

k++;

if(k==8)

{

s[i++]=' ';

k=0;

}

sh>>=1; // Сдвиг шаблона в следующий разряд

}

s[i]='\0';

cout<<s<<'\n';

}

Для успешной проверки данной функции следует вводить числа в шестнадцатеричном виде, так как каждая шестнадцатеричная цифра представляется четырьмя двоичными разрядами.

Листинг 8.2. Программа печатает двоичное представление числа с использованием функции, приведенной в листинге 8.1.

//L8_2.cpp

#include <fstream>

#include <iostream>

using namespace std;

int main()

{

setlocale(LC_CTYPE,"russian");

unsigned int n;

do

{

cout<<"Введите неотрицательное n ";

cin>>hex>>n; // Ввол числа в шестнадцатеричной

// системе счисления.

}while(n<0);

print_bit(n); // Печать числа в двоичной системе числения

cin.get();

cin.get();

return 0;

}

Результат работы программы листинга 8.2 приведен на рис. 8.1.

Рис. 8.1. Результат работы программы листинга 8.2

Листинг 8.3. В заданном числе инвертировать n битов с позиции k вправо. При вводе данных следует контролировать, чтобы позиция инвертируемого бита и количество инвертируемых битов не выходили за пределы числа. Для построения необходимо создать шаблон, содержащий 1 в инвертируемых позициях и 0 в остальных.

//L8_3.cpp

#include <stdio.h>

#include <tchar.h>

#include <iostream>

using namespace std;

void print_bit(unsigned int x);

int main()

{

setlocale(LC_CTYPE,"russian");

unsigned int x, n, k, m, sh, y;

m=sizeof(unsigned int)*8;

do

{

cout<<"Введите неотрицательное x ";

cin>>hex>>x;

}while(x<0);

do

{

cout<<"Введите позицию k и число инвертируемых битов n ";

cin>>dec>>k>>n;

}while(!(k<=m&&n<=k));

print_bit(x);

sh=~0;

sh=((sh<<m-k)>>m-n)<<k-n;

y=~(x&sh)&sh;

x=x&(~sh)|y;

print_bit(x);

return 0;

}

void print_bit(unsigned int x)

{

unsigned int sh=~0,k=0,i=0;

char s[40];

sh=~(sh>>1);

cout<<'\n';

while(sh!=0)

{

s[i++]=(sh&x)?'1':'0';

k++;

if(k%8==0)

s[i++]=' ';

sh=sh>>1;

}

s[i]='\0';

cout<<s<<'\n';

}

На рис. 8.2 приведен результат выполнения программы листинга 8.3.

Рис. 8.2. Результат работы программы листинга 8.3

Побитовые операции можно использовать для укрупненного начертания слов. Укрупненное начертание какого-либо символа связано с заданием этого символа в виде таблицы [15]. Заполненные клетки таблицы образуют нужный контур символа. Содержимое такой таблицы можно закодировать с помощью 1 (клетка заполнена) и 0 (клетка не заполнена). Пусть такая таблица состоит из 7 × 5 элементов. Тогда для идентификации символа достаточно пяти семиразрядных двоичных чисел. Каждое из них будет кодировать один из пяти вертикальных слоев. Например, начертание символа “ Н” кодируется следующими двоичными числами: 1111111 (первый и пятый вертикальные слои таблицы), 10 (второй, третий и четвертый слои таблицы). При этом переход от младших разрядов к старшим соответствует просмотру исходной таблицы сверху вниз (рис. 8.3).

1       1
Младший разряд
1

       
         
         
         
Старший разряд
1

       
         

Рис. 8.3. Кодирование начертания символа “ Н

Для распечатки символа необходимо установить, какие двоичные цифры находятся в соответствующих разрядах всех пяти чисел: 0 – печатать пробел, 1 – печатать выбранный символ.

Листинг 8.4. Вывести на экран дисплея укрупненное начертание слов: “ННГУ” и “МЕХМАТ”.

//L8_4.cpp

#include "stdafx.h"

#include <stdio.h>

#include <locale>

void _tmain()

{setlocale (LC_ALL, "Russian");

int i, j, k, n;

int B[6][5], D[6][5];

static char s[]="ННГУ", s2[]="МЕХМАТ";

char c, e;

for (n=0; (c=s[n])!='\0'; n++)

switch (c)

{

case 'Н': B[n][0]=B[n][4]=0177;

B[n][1]=B[n][2]=B[n][3]=010;

break;

case 'Г': B[n][0]=0177;

B[n][1]=B[n][2]=B[n][3]=01;

B[n][4]=03;

break;

case 'У': B[n][0]=047;

B[n][1]=B[n][2]=B[n][3]=0110;

B[n][4]=077;

break;

}

for (k=0; k<7; k++) // k – разряд

{ for (i=0; i<n; i++) // i – буква

{ j=0; // j - слой

do

{if (B[i][j] & 01) // Выделение k-го разряда каждого

// из чисел, кодирующих букву.

printf("%c", s[i]);

else

printf("%c", ' ');

B[i][j]=B[i][j]>>1; // Сдвиг вправо на одну позицию

// всех разрядов числа.

j++;

}

while (j<5);

printf("%s", " ");

}

printf ("\n");

}

printf ("\n");

for (n=0; (e=s2[n])!='\0'; n++)

switch (e)

{

case 'М': D[n][0]=D[n][4]=0177;

D[n][1]=D[n][3]=02;

D[n][2]=04;

break;

case 'Е': D[n][0]=0177;

D[n][1]=D[n][2]=D[n][3]=0111;

D[n][4]=0101;

break;

case 'Х': D[n][0]=D[n][4]=0143;

D[n][1]=D[n][3]=024;

D[n][2]=010;

break;

case 'А': D[n][0]=D[n][4]=0176;

D[n][1]=D[n][2]=D[n][3]=011;

break;

case 'Т': D[n][0]=D[n][1]=D[n][3]=D[n][4]=01;

D[n][2]=0177;

break;

}

for (k=0; k<7; k++)

{ for (i=0; i<n; i++)

{ j=0;

do {

if (D[i][j] & 01) // Выделение k-го разряда каждого

// из чисел, кодирующих букву.

printf("%c", s2[i]);

else

printf("%c", ' ');

D[i][j] = D[i][j] >> 1; // Сдвиг вправо на одну позицию

// всех разрядов числа.

j++;

}

while (j<5);

printf("%s", " ");

}

printf ("\n");

}

printf ("\n");

}

Результат выполнения программы листинга 8.4 приведен на рис. 8.4.

Рис. 8.4. Результат работы программы листинга 8.4


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: