Урок №47. Конвертація чисел з двійкової системи числення в десяткову і навпаки

  Юрій  | 

  Оновл. 2 Тра 2020  | 

 407

Щоб навчитися конвертувати числа з двійкової (бінарної) системи числення в десяткову та навпаки, перш за все необхідно зрозуміти, як цілі числа представлені в двійковій системі. Ми вже трохи говорили про це, коли розглядали цілочисельні типи даних.

Представлення чисел в двійковій системі числення

Розглянемо звичайне десяткове число, наприклад, 5623. Інтуїтивно зрозуміло, що означають всі ці цифри: (5 * 1000) + (6 * 100) + (2 * 10) + (3 * 1). Так як в десятковій системі числення всього 10 цифр, то кожне значення множиться на множник 10 у степені n. Вираз вище можна записати ще так: (5 * 103) + (6 * 102) + (2 * 101) + (3 * 1).

Двійкові числа працюють за аналогічною схемою, за винятком того, що в системі всього 2 числа (0 і 1) і множник не 10, а 2. Так само як коми (або пробіли) використовуються для поліпшення читабельності великих десяткових чисел (наприклад: 1, 427, 435), двійкові числа пишуться групами (в кожній по 4 цифри), наприклад, 1101 0101.

Десяткове значення Двійкове значення
0 0
1 1
2 10
3 11
4 100
5 101
6 110
7 111
8 1000
9 1001
10 1010
11 1011
12 1100
13 1101
14 1110
15 1111

Конвертація чисел з двійкової системи числення в десяткову

У прикладах нижче ми працюємо з цілочисельними значеннями unsigned.

Розглянемо 8-бітне (1-байтове) двійкове число: 0101 1110. Воно означає (0 * 128) + (1 * 64) + (0 * 32) + (1 * 16) + (1 * 8) + (1 * 4 ) + (1 * 2) + (0 * 1). Якщо підсумувати, то отримаємо десяткове 64 + 16 + 8 + 4 + 2 = 94.

Ось той же процес, але в таблиці. Ми множимо кожну двійкову цифру на її значення, яке визначається її місцезнаходженням. Конвертуємо двійкове 0101 1110 в десяткову систему:

Двійковий символ 0 1 0 1 1 1 1 0
* Значення символу 128 64 32 16 8 4 2 1
= Результат (94) 0 64 0 16 8 4 2 0

А тепер конвертуємо двійкове 1001 0111 в десяткову систему:

Двійковий символ 1 0 0 1 0 1 1 1
* Значення символу 128 64 32 16 8 4 2 1
= Результат (151) 128 0 0 16 0 4 2 1

Отримуємо:

1001 0111 (двійкове) = 151 (десяткове)

Таким способом можна легко конвертувати і 16-бітні, і 32-бітні двійкові числа, просто додаючи стовпчики. Зверніть увагу, найпростіше починати відлік справа наліво, множачи на 2 кожне наступне значення.

Спосіб №1: Конвертація чисел з десяткової системи числення в двійкову

Перший спосіб конвертації чисел з десяткової системи числення в двійкову полягає в безперервному діленні числа на 2 і записуванні остачі. Якщо залишок (“r” від англ. “remainder”) є, то пишемо 1, якщо немає, то пишемо 0. Потім, читаючи залишки знизу вгору, ми отримаємо готове двійкове число.

Наприклад, конвертуємо десяткове число 148 в двійкову систему числення:

148 / 2 = 74 r0
74 / 2 = 37 r0
37 / 2 = 18 r1
18 / 2 = 9 r0
9 / 2 = 4 r1
4 / 2 = 2 r0
2 / 2 = 1 r0
1 / 2 = 0 r1

Записуємо залишки знизу вгору: 1001 0100.

148 (десяткове) = 1001 0100 (двійкове)

Ви можете перевірити цю відповідь шляхом конвертації двійкового числа назад в десяткову систему:

(1 * 128) + (0 * 64) + (0 * 32) + (1 * 16) + (0 * 8) + (1 * 4) + (0 * 2) + (0 * 1) = 148

Спосіб №2: Конвертація чисел з десяткової системи числення в двійкову

Цей спосіб добре підходить для невеликих двійкових чисел. Розглянемо десяткове 148 ще раз. Яке найбільше число, помножене на 2 (з ряду: 1, 2, 4, 8, 16, 32, 64, 128, 256 і т.д.), менше 148? Відповідь: 128.

148 >= 128? Так, тому 128-й біт дорівнює 1. 148 − 128 = 20
20 >= 64? Ні, тому 64-й біт дорівнює 0.
20 >= 32? Ні, тому 32-й біт дорівнює 0.

20 >= 16? Так, тому 16-й біт дорівнює 1. 20 − 16 = 4
4 >= 8? Ні, тому 8-й біт дорівнює 0.
4 >= 4? Так, тому 4-й біт дорівнює 1. 4 − 4 = 0, що означає, що всі інші біти дорівнюють 0.

Примітка: Якщо відповіддю є “Так”, то ми маємо true, що означає 1. Якщо відповіддю є “Ні”, то ми маємо false, що означає 0. Детальніше про це в уроці про логічний тип даних bool.

Результат:

148 = (1 * 128) + (0 * 64) + (0 * 32) + (1 * 16) + (0 * 8) + (1 * 4) + (0 * 2) + (0 * 1) = 1001 0100

Те ж, але в таблиці:

Двійковий символ 1 0 0 1 0 1 0 0
* Значення символу 128 64 32 16 8 4 2 1
= Результат (148) 128 0 0 16 0 4 0 0

Ще один приклад

Конвертуємо десяткове 117 в двійкову систему числення, використовуючи спосіб №1:

117 / 2 = 58 r1
58 / 2 = 29 r0
29 / 2 = 14 r1
14 / 2 = 7 r0
7 / 2 = 3 r1
3 / 2 = 1 r1
1 / 2 = 0 r1

Запишемо число з залишків (знизу вгору):

117 (десяткове) = 111 0101 (двійкове)

А тепер виконаємо ту ж конвертацію, але використовуючи спосіб №2:

Найбільше число, помножене на 2, але яке менше 117 — це 64.

117 >= 64? Так, тому 64-й біт дорівнює 1. 117 − 64 = 53.
53 >= 32? Так, тому 32-й біт дорівнює 1. 53 − 32 = 21.
21 >= 16? Так, тому 16-й біт дорівнює 1. 21 − 16 = 5.

5 >= 8? Ні, тому 8-й біт дорівнює 0.
5 >= 4? Так, тому 4-й біт дорівнює 1. 5 − 4 = 1.
1 >= 2? Ні, тому 2-й біт дорівнює 0.
1 >= 1? Так, тому 1-й біт дорівнює 1.

Результат:

117 (десяткове) = 111 0101 (двійкове)

Додавання двійкових чисел

У деяких випадках (один з них ми розглянемо нижче) вам може знадобитися виконати операцію додавання двох двійкових чисел. Хоча спочатку це може здатися трохи дивним, але ви швидко до цього звикнете.

Розглянемо додавання наступних двох невеликих двійкових чисел:

0110 (6 в десятковій системі) +
0111 (7 в десятковій системі)

По-перше, числа потрібно записати в стовпчик (як показано вище). Потім, справа наліво і зверху вниз ми додаємо кожен стовпець з цифрами, як ніби це десяткові числа. Так як в бінарній системі є тільки два числа: 0 і 1, то всього є 4 можливих результати:

   0 + 0 = 0

   0 + 1 = 1

   1 + 0 = 1

   1 + 1 = 0, 1 переносимо в наступну колонку

Почнемо з першої колонки (стовпця):

0110 (6 в десятковій системі) +
0111 (7 в десятковій системі)
----

   1

0 + 1 = 1. Легко.

Друга колонка:

 1
0110 (6 в десятковій системі) +
0111 (7 в десятковій системі)
----

  01

1 + 1 = 0, 1 залишається в пам’яті до наступної колонки.

Третя колонка:

11
0110 (6 в десятковій системі) +
0111 (7 в десятковій системі)
----

 101

А ось тут вже трохи складніше. Зазвичай 1 + 1 = 0 і залишається одиниця, яку ми переносимо в наступну колонку. Проте, у нас вже є 1 з попереднього стовпчика і нам потрібно додати ще 1. Що робити? А ось що: 1 залишається, а ще 1 ми переносимо далі.

Остання колонка:

11
0110 (6 в десятковій системі) +
0111 (7 в десятковій системі)
----
1101

0 + 0 = 0, але так як є ще 1, то результат: 1101.

13 (десяткове) = 1101 (двійкове)

Ви запитаєте: “А як додати десяткову одиницю до будь-якого іншого двійкового числа (наприклад, до 1011 0011)?”. Точно так же, як ми це робили вище, тільки числом знизу є двійкова одиниця, наприклад:

       1 (переносимо в наступну колонку)
1011 0011 (двійкове число)
0000 0001 (1 в двійковій системі)
---------
1011 0100

Числа signed і метод “two’s complement”

У прикладах вище ми працювали тільки з цілими числами unsigned, які можуть бути тільки додатними. Зараз же ми розглянемо те, як працювати з числами signed, які можуть бути як додатними, так і від’ємними.

З цілими числами signed використовується метод “two’s complement”. Він означає, що найлівіший (найголовніший) біт використовується в якості знакового біту. Якщо значенням знакового біту є 0, то число додатне, якщо 1 — число від’ємне.

Додатні числа signed зберігаються так само, як і додатні числа unsigned (з 0 в якості знакового біту). А ось від’ємні числа signed зберігаються у вигляді зворотних додатних чисел +1. Наприклад, виконаємо конвертацію -5 з десяткової системи числення в двійкову, використовуючи метод “two’s complement”:

Спочатку з'ясовуємо двійкове представлення 5: 0000 0101
Потім інвертуємо всі біти (конвертуємо в протилежні): 1111 1010
Після цього додаємо до числа одиницю: 1111 1011

Конвертація -76 з десяткової системи числення в двійкову:

Представлення додатнього числа 76: 0100 1100
Інвертуємо всі біти: 1011 0011
Додаємо до числа одиницю: 1011 0100

Чому ми додаємо одиницю? Розглянемо це на прикладі 0 (нуля). Якщо протилежністю від’ємного числа є його додатна форма, то 0 має два представлення 0000 0000 (додатний нуль) і 1111 1111 (від’ємний нуль). При додаванні одиниці, в 1111 1111 відбудеться переповнення, і значення зміниться на 0000 0000. Додавання одиниці запобігає 0 від наявності двох представлень і спрощує внутрішню логіку, необхідну для виконання арифметичних обчислень з від’ємними числами.

Перед тим, як конвертувати двійкове число (використовуючи метод “two’s complement”) назад в десяткову систему числення, потрібно спочатку подивитися на знаковий біт. Якщо ним є 0, то сміливо використовуйте способи вище для цілих чисел unsigned. Якщо ж знаковим бітом є 1, то тоді потрібно інвертувати всі біти, потім додати одиницю, потім конвертувати в десяткову систему, і вже після цього змінювати знак десяткового числа на від’ємний (бо знаковий біт спочатку був від’ємним).

Наприклад, виконаємо конвертацію двійкового 1001 1110 (використовуючи метод “two’s complement”) в десяткову систему числення:

Маємо: 1001 1110
Інвертуємо біти: 0110 0001
Додаємо одиницю: 0110 0010
Конвертуємо в десяткову систему числення: (0 * 128) + (1 * 64) + (1 * 32) + (0 * 16) + (0 * 8) + (0 * 4) + (1 * 2) + (0 * 1 ) = 64 + 32 + 2 = 98

Так як вихідний знаковий біт був від’ємним, то результатом є -98.

Чому так важливий тип даних?

Розглянемо двійкове число 1011 0100. Що це за число в десятковій системі числення? Ви, напевно, подумаєте, що це 180, і, якби це було стандартне двійкове число unsigned, то ви були б праві. Однак, якщо тут використовується метод “two’s complement”, то результат буде інший, а саме -76. Також значення ще може бути інше, якщо воно закодовано якимось третім способом.

Так як же C++ розуміє в яке число конвертувати 1011 0100: в 180 чи в -76?

Ще в уроці №31 ми говорили: “Коли ви вказуєте тип даних змінної, компілятор і процесор піклуються про деталі кодування цього значення в відповідну послідовність біт певного типу даних. Коли ви просите ваше значення назад, то воно “відновлюється” з відповідної послідовності біт в пам’яті”.

Тип змінної використовується для конвертації двійкового представлення числа назад в очікувану форму. Так що, якщо ви вказали цілочисельний тип даних unsigned, то компілятор знає, що 1011 0100 — це стандартне двійкове число, а його представленням в десятковій системі числення є 180. Якщо ж типом змінної є цілочисельний тип signed, то компілятор знає, що 1011 0100 закодований за допомогою методу “two’s complement” і його представленням в десятковій системі числення є число -76.

Тест

Завдання №1: Конвертуйте двійкове 0100 1101 в десяткову систему числення.

Завдання №2: Конвертуйте десяткове 93 в 8-бітне двійкове число unsigned.

Завдання №3: Конвертуйте десяткове -93 в 8-бітне двійкове число signed (використовуючи метод “two’s complement”).

Завдання №4: Конвертуйте двійкове 1010 0010 в десяткове unsigned.

Завдання №5: Конвертуйте двійкове 1010 0010 в десяткове signed (використовуючи метод “two’s complement”).

Завдання №6: Напишіть програму, яка просить користувача ввести число від 0 до 255. Виведіть його як 8-бітне двійкове число (в парах по 4 цифри). Не використовуйте побітові оператори.

Підказка №1: Скористайтеся способом конвертації №2. Припустимо, що найменшим числом для порівняння є 128.

Підказка №2: Напишіть функцію для перевірки вхідних чисел: чи є вони більше чисел, помножених на 2 (тобто 1, 2, 4, 8, 16, 32, 64 і 128). Якщо це так, то виводиться 1, якщо ні — виводиться 0.

Відповіді

Відповідь №1

Двійковий символ 0 1 0 0 1 1 0 1
* Значення символу 128 64 32 16 8 4 2 1
= Результат (77) 0 64 0 0 8 4 0 1

Відповідь: 77.

Відповідь №2

Використовуючи спосіб №1:

93 / 2 = 46 r1
46 / 2 = 23 r0
23 / 2 = 11 r1
11 / 2 = 5 r1
5 / 2 = 2 r1
2 / 2 = 1 r0
1 / 2 = 0 r1

Остача знизу вгору: 101 1101.

Використовуючи спосіб №2:

Найбільше число, помножене на 2, але яке менше 93 — це 64.

93 >= 64? Так, 64-й біт дорівнює 1. 93 - 64 = 29.
29 >= 32? Ні, 32-й біт дорівнює 0.
29 >= 16? Так, 16-й біт дорівнює 1. 29 - 16 = 13.
13 >= 8? Так, 8-й біт дорівнює 1. 13 - 8 = 5.
5 >= 4? Так, 4-й біт дорівнює 1. 5 - 4 = 1.
1 >= 2? Ні, 2-й біт дорівнює 0.
1 >= 1? Так, 1-й біт дорівнює 1.

Відповідь: 0101 1101.

Відповідь №3

Ми вже знаємо з попереднього прикладу, що 93 — це 0101 1101
Тому інвертуємо біти: 1010 0010
І додаємо одиницю: 1010 0011

Відповідь: 1010 0011.

Відповідь №4

Працюючи справа наліво:

1010 0010 = (0 * 1) + (1 * 2) + (0 * 4) + (0 * 8) + (0 * 16) + (1 * 32) + (0 * 64) + (1 * 128) = 2 + 32 + 128 = 162

Відповідь: 162.

Відповідь №5

Маємо: 1010 0010
Інвертуємо біти: 0101 1101
Додаємо одиницю: 0101 1110
Конвертуємо в десяткову систему числення: 16 + 64 + 8 + 4 + 2 = 94

Так як тут використовується метод “two’s complement”, а знаковий біт є від’ємним, то результатом є -94

Відповідь: -94.

Відповідь №6

Оцінити статтю:

1 Зірка2 Зірки3 Зірки4 Зірки5 Зірок (1 оцінок, середня: 5,00 з 5)
Loading...

Залишити відповідь

Ваш E-mail не буде опублікований. Обов'язкові поля відмічені *