Урок №44. Конвертация чисел из двоичной системы в десятичную и наоборот

  Юрий  | 

    | 

  Обновл. 14 Апр 2019  | 

 26722

 ǀ   20 

Чтобы научиться конвертировать числа из двоичной (бинарной) системы счисления в десятичную и наоборот, прежде всего необходимо понять, как целые числа представлены в двоичной системе. Мы уже немного говорили об этом в уроке №31.

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

Рассмотрим обычное десятичное число, например, 5 623. Интуитивно понятно, что означают все эти цифры: (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. Детальнее об этом в уроке №34.

Результат:

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?

Ещё в уроке №28 мы говорили: «Когда вы указываете тип данных переменной, компилятор и процессор заботятся о деталях кодирования этого значения в соответствующую последовательность битов определённого типа данных. Когда вы просите ваше значение обратно, то оно «восстанавливается» из соответствующей последовательности битов в памяти».

Тип переменной используется для конвертации бинарного представления числа обратно в ожидаемую форму. Так что, если вы указали целочисленный тип данных 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 (75 оценок, среднее: 4,73 из 5)
Загрузка...

Комментариев: 20

  1. Аватар zvezdonom:

    Всем доброго времени суток. Добавлю и свою программку, которая переводит десятичное целое число, введенное пользователем, в самые распространенные позиционные системы счисления: 2 — двоичную, 3 — троичную, 8 — восьмеричную и 16 — шестнадцатеричную.
    Хотя может пересчитывать в любую позиционную.
    Добавил несколько проверок на вводимое число и на повторное вычисление.
    Компилятор — Qt Creator.

    calculate.h

    calculate.cpp

    main.cpp

    Результат работы программы:

    Please enter a number(integer) over the range 0 to 2 147 483 647: 1023
    1023 convert to 2 numerical system: 1111111111
    1023 convert to 3 numerical system: 1101220
    1023 convert to 8 numerical system: 1777
    1023 convert to 16 numerical system: 3FF

    Please enter
    'y' - if you want repeat conversion or
    'n' - if you want quit

  2. Аватар Pere_Strelka:

    Жесть, что только не выкладывают, хотя может и верно все это)
    Сделал программку, которая переводит десятичное число в двоичное, причем использует всю мощь 4-х байтов 🙂
    Перевод осуществляется вторым способом, так как делал до этого урока.

    Calc+.cpp:

    functions.h:

    functions.cpp:

  3. Аватар Денис:

  4. Аватар Владимир:

    То самое чувство, когда все просто выводили двоичное представления десятичного числа через cout, а ты запихивал его в int32_t…

  5. Аватар Евгений:

    Опять усложнил немного, считает любую цифру из десятичной в двоичную.

    Основной файл:

    Файл с функцией:

    Что думаете? Можно как то облегчить или замечания какие-нибудь?

  6. Аватар Camio:

    С имеющимися знаниями вышло вот что:

  7. Аватар Алексей:

  8. Аватар Константин:

    …рассмотрим 148 ещё раз. Какое наибольшее число, УМНОЖЕННОЕ НА 2(из ряда 1, 2, 4, 8, 16, 32, 64, 128, 256 и т.д.), меньше 148? Ответ: 128. Дык ить ежели 128 удвоить оно того 148мого на сто пудов большее будет!!! У меня тихо шифером шурша…

  9. Аватар Максим:

  10. Аватар Nikolai:

    Не надо писать фразы типа "является ли число x больше ОПРЕДЕЛЁННОГО ЧИСЛА, УМНОЖЕННОГО НА 2", очень размытый смысл у такой фразы. ОПРЕДЕЛЁННОЕ ЧИСЛО, умноженное на 2 может быть 50? 50*2=100. Или 40*2=80. Что за определённое число? Если имеется ввиду ряд чисел 2, 4, 8, 16, 32, 64, 128, 256, 512 и т.д., то эти числа лучше называть "степенью двойки".

  11. Аватар Katerina:

    Огромное спасибо за ваши уроки! Учусь в университете в Германии, безумно сложно и этот сайт — просто спасение! Немного не поняла задание… вводит в заблуждение "число, умноженное на 2"… непонятно какое же число умножается на 2. Подсказку 2 поняла так, что надо отдельную функцию написать для первого числа. Похоже, неправильно )) Хотелось узнать имеет ли право на жизнь следующий код.

    Файл Convert.h

    Convert.cpp

    ConvertMain.cpp

    И еще раз огромное спасибо за сайт!

  12. Аватар YuriiJ:

    У меня получился такой код:

    Но прога зацикливается. Почему?

  13. Аватар master114:

    Не совсем понял вторую подсказку, поэтому фантазировал как мог.
    Рад, что в итоге получилось, хоть и не так компактно как уже предложенные варианты, зато рабочий код -)))

    Код — onlinegdb.com/Hkeby3KTG.

    1. Юрий Юрий:

      Имелись в виду числа 1, 2, 4, 8, 16, 32, 64 и 128. Код рабочий, как вариант, может быть — у вас всё просто более развернуто получилось 🙂

  14. Аватар Anton:

    1. Юрий Юрий:

      Да, можно и так.

    2. Аватар АлександЕр:

      Я чуть дополнил , просто для интереса:

      1. Юрий Юрий:

        Код не рабочий.

      2. Аватар Роман:

        Боюсь дальше уже стоит использовать циклы, а также можно попробовать первый способ, на котором у меня уже есть такая прога, я в неё ёще впихну второй способ и скину сюда

    3. Аватар master114:

      мне кажется на этапе цикла while может возникнуть ситуация бесконечного ввода
      Вдруг пользователь не понимает что от него хотят -))
      Тогда нужно добавить какое-то количество попыток после чего программа автоматом должна прерываться

Добавить комментарий

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