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 | |||||
| ||||||
| ||||||
Рис. 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