Лекция 8

Битовые операции


Наименьшая адресуемая ячейка памяти — байт (адреса 0, 1, 2, …)


Байт — обычно 8 битов

Зачем нужен доступ к битам?

1. Компактное хранение информации (вместо 1 байта — 1 бит, размер расходуемой памяти уменьшается в 8 раз)

2. Операции с числами — удобно выполнять при помощи битовых операций.Добавить


Пример 1. Деление на 2:

char x; unsigned char y; /* x – в [-126, 127], y – в [0, 255] */

x /= 2;

x >>= 1; /* x = x >> 1; */


x:

Номер бита

7

6

5

4

3

2

1

0

Значение бита

0

0

0

0

1

1

0

1


Отрицательные числа (в прямом представлении):

-1 = 10000001 (знак 1, в младших 7 битах - абсолютное значение: 1)


Отрицательные числа (в дополнительном представлении):

-1 = 11111111 (знак 1, абсолютное значение — в дополнительном коде)

-2 = 11111110

-3 = 11111101

-128 = 10000000


1

Номер бита

7

6

5

4

3

2

1

0

Значение бита

0

0

0

0

0

0

0

1


-1

Номер бита

7

6

5

4

3

2

1

0

Значение бита

1

1

1

1

1

1

1

1


1 + (-1):


Номер бита

7

6

5

4

3

2

1

0

Значение бита

0

0

0

0

0

0

0

0



Битовые операции:
1. Логические

а) И (&)

б) ИЛИ (|)

в) Исключающее ИЛИ (^)

г) НЕ (~)


2. Сдвига

а) Влево (<<) - в сторону старших битов

б) Вправо (>>) - в сторону меньших битов


И

0

1

0

0

0

1

0

1



ИЛИ

0

1

0

0

1

1

1

1



Исключющее ИЛИ

0

1

0

0

1

1

1

0



НЕ


0

1

1

0





Задача 1. Найти количество битов со значением 1 в целом числе.


N

Значение бита

0

1

0

1

1

0

0

0


1) mask

Значение бита

0

0

0

0

0

0

0

1

N&mask:

Значение бита

0

0

0

0

0

0

0

0



2) mask

Значение бита

0

0

0

0

0

0

1

0

N&mask:

Значение бита

0

0

0

0

0

0

0

0



3) mask

Значение бита

0

0

0

0

0

1

0

0

N&mask:

Значение бита

0

0

0

0

0

0

0

0


4) mask

Значение бита

0

0

0

0

1

0

0

0

N&mask != 0

Значение бита

0

0

0

0

1

0

0

0


...

8) mask

Значение бита

1

0

0

0

0

0

0

0

N&mask != 0

Значение бита

0

0

0

0

0

0

0

0


9) mask

Значение бита

0

0

0

0

0

0

0

0



#include <stdio.h>


int main(void) {

int N, res = 0, mask = 1;

printf("Input number\n");

scanf("%d", &N);

while(mask) { /* != 0 */

if (N & mask) { /* !=0 */

++res; /* Non-zero bit found */

}

mask <<= 1;

}

printf("%d bits\n", res);

return 0;

}



Задача 2. Найти количество битов в целом числе


#include <stdio.h>


int main(void) {

int res = 0, mask = 1;

printf("Input number\n");

while(mask) { /* != 0 */

++res;

mask <<= 1;

}

printf("%d bits in integer\n", res);

return 0;

}


Сдвиг — эффективнее, чем умножение (и тем более деление) на два, так как это одна ассемблерная инструкция (ассемблер — язык машинных кодов в записи, понятной человеку)


ARM (RISC – Restricted Instruction Set):

ASL – сдвиг влево на 1 бит

ASR – сдвиг вправо

ROL – циклический сдвиг

ROR – циклический сдвиг



Задача 3. Быстрое возведение в степень — используя O(log2(N)) умножений

Справа налево (от младших степеней)

Слева направо (от старших степеней) — схема Горнера


K**N = A*A*A*...*A – N-1 умножение

K**(2**l) = (A*

K**32 = ((A**2)**2)**2)**2)**2) – 5 умножений = log2(32)


O(N**2) – при увеличении N в 2 раза — количество операций вырастет в 4 раза


N = an-1 * 2**(n-1) + an-2 * 2**(n-2) + … + a2 * 2**2 + a1 * 2**1 + a0 * 2**0



A**N = A ** (an-1 * 2**(n-1) + an-2 * 2**(n-2) + … + a2 * 2**2 + a1 * 2**1 + a0 * 2**0) =


= ((...((A**an-1)**2*(A** an-2)**2)…)*(A** a1)**2)*(A** a0 )



Задача 4. Найти беззнаковое целое число, у которого самый старший бит — 1, остальные все биты 0


M:

Номер бита

7

6

5

4

3

2

1

0

Значение бита

1

1

1

1

1

1

1

1


M>>1:

Номер бита

7

6

5

4

3

2

1

0

Значение бита

0

1

1

1

1

1

1

1


M-(M>>1):

Номер бита

7

6

5

4

3

2

1

0

Значение бита

1

0

0

0

0

0

0

0




#include <stdio.h>


int main(void) {

unsigned int M = -1;

M -= (M>>1);

printf("res: %x\n", M);

return 0;

}




Решение задачи 3:


#include <stdio.h>


int main(void) {

int A, N, res = 1;

unsigned int M = -1;

M -= (M>>1);

/* printf("res: %x\n", M); */

printf("Input number and degree:\n");

scanf("%d%d", &A, &N);

while (M) {

if (res > 1) { /* log2(N) multiplications */

res *= res;

}

if (N & M) { /* <= log2(N) multiplications */

res *= A;

}

M >>= 1;

}

printf("Res: %d\n", res);

return 0;
}