
- •Часть 2
- •18 Сентября 2012 г., протокол № 1
- •Предисловие
- •Глава 6 простые типы данных § 1. Целый тип
- •1.1. Битовые операции
- •Использование битовых операций
- •1.3. Упаковка и распаковка информации
- •§ 2. Логический тип
- •§ 3. Символьный тип
- •§ 4. Вещественный тип
- •§ 5. Преобразование типов
- •Преобразование типов в выражениях
- •Преобразование типов при присваивании
- •Г л а в а 7 введение в указатели
- •§ 1. Понятие указателя. Операции разыменования и разадресации
- •§ 2. Инициализация и присваивание указателей
- •§ 3. Распределение динамической памяти
- •Операция new
- •Операция delete
- •§ 4. Параметры-указатели. Функция ввода scanf
- •Упражнения, тесты
- •Г л а в а 8 одномерные массивы, указатели и функции
- •§ 1. Связь указателей и одномерных массивов. Передача массива в качестве параметра функции
- •§ 2. Сортировка одномерных массивов
- •§ 3. Сортировка массива по параметру числа
- •§ 4. Сортировка массива выбором.
- •§ 5. Сортировка массива вставками
- •§ 6. Динамические одномерные массивы
- •6.1. Порядок работы с динамическим массивом
- •6.2. Работа с динамическим массивом в классе. Деструктор
- •§ 7. Введение в строки
- •Глава 9 мАтрицы
- •§ 1. Объявление, способы определения матриц
- •§ 2. Вывод матриц
- •§ 3. Типы алгоритмов
- •3.1. Построчная обработка
- •Обработка матрицы по столбцам
- •3.3. Обработка всей матрицы
- •3.4. Обработка части матрицы
- •Преобразование матрицы
- •Построение матриц
- •§ 4. Матрицы, указатели и функции
- •Упражнения и тесты
- •Обработка матрицы по столбцам.
- •Список реКоМендуемой литературы
- •Сборники задач по программированию
- •Оглавление
- •Методы программирования:
- •Лекции, примеры, тесты
- •Пособие для студентов механико-математического факультета
- •В двух частях
- •Часть 2
Использование битовых операций
Пример 6. Включить четвёртый справа бит, если их нумерация с нуля справа налево. Получить в этом бите единицу или единицу оставить, если она там была, а значения остальных бит не должны измениться.
Первый этап такого упражнения — решить его на битовом уровне, то есть на языке “нулей и единиц”. Пусть работаем с двумя байтами. Тогда условие обозначим так:
*
?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
1
Здесь символом отмечен бит со значением нуль или единица, значение которого не должно меняться, символом * указан изменяемый бит. Символы "?" означают, какую операцию (& или | или ^), с каким числом (0000000000010000 или 1111111111101111) надо выполнить для решения задачи. Проанализируем все шесть вариантов, или некоторые из них:
1) Операция & c числом 0000000000010000 не подходит. Все биты, кроме четвёртого, обнулим, а четвёртый бит не изменится.
2) Не устроит нас и операция & со вторым числом 1111111111101111. В этом случае наоборот, все биты, кроме четвёртого, останутся без изменения, а в четвёртом бите всегда получится нуль.
3) — 6) аналогично для остальных операций.
Получим
*
|
0 0 0 0 0 0 0 0 0 0 010 0 0 0
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
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
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
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 не изменится.
С помощью приведенной функции можно выводить и двоичное представление отрицательных чисел.
Можно усложнить программу таким образом, чтобы для положительных чисел незначащие нули слева не выводились. В качестве упражнения предлагается внести соответствующие изменения.