В этом гайде разберемся, что такое системы счисления, для чего программисты используют непривычные способы для записи чисел и как их понимать.
- Что такое системы счисления
- Кодирование целых чисел
- Зачем нужна двоичная система
- Как переводить десятичные числа в двоичные
- Шестнадцатеричная система счисления
- Как переводить двоичные числа в десятичные
- Сервисы для перевода из системы в систему
- Восьмеричная система счисления
- Конвертация чисел в программах
- Python
- JavaScript
- От десятичных чисел к двоичным
- Заключение
Что такое системы счисления
С давних пор людям нужно было записывать числа. В торговле числа нужны, чтобы знать, сколько товаров есть на складе и сколько денег принесла сделка. Записи о положении небесных тел помогли шумерам составить первый календарь, а календарь, в свою очередь, пригодился, чтобы заранее готовиться к посевным и сбору урожая. Строительные сметы, переписи населения, распределение наследства — числа оказались очень востребованными даже в самых древних государствах.
Так что люди научились записывать числа в незапамятные времена. Небольшие числа легко записывались зарубками или насечками, но если в числе несколько знаков, требуется иная система записи. Эту проблему в разных странах решали по-разному.
Сейчас разные способы записи чисел называются системами счисления.
Систем счисления было придумано довольно много, и даже в наши дни мы используем две системы, возникшие в далёкой древности. Из Древнего Рима к нам пришла римская система счисления, где цифры обозначаются буквами латинского алфавита. За основу римляне взяли количество пальцев на одной руке — 5, и на двух руках — 10. Числа 1, 5 и 10 в римской системе обозначаются буквами I, V и X, и с помощью них можно записать любое число от 1 до 49. Например, VII это 7, а XIX — 19.
От Древних Шумеров мы научились делить дроби на шестьдесят частей. Именно из-за них в нашем часе 60 минут, а в минуте 60 секунд. Шумерская система счисления так и называется — шестидесятеричная. Но, конечно, наиболее привычной выглядит численная запись в системе, которую придумали в Древней Индии. Сейчас ее называют арабской или десятичной системой счисления.
Современные компьютеры могут обрабатывать только дискретную информацию, поэтому любой вид информации преобразуется в числовую форму, которая затем кодируется в двоичном виде.
Кодированием данных называется представление данных с помощью условных знаков. Система двоичного кодирования заключается в представлении данных произвольного типа двоичным кодом, в виде последовательности нулей и единиц.
В настоящей главе рассматриваются методы двоичного кодирования целых и действительных чисел, а также текстовой информации.
В сокращенном виде двоичный код представляется в шестнадцатеричном формате, для этого используются таблицы тетрад. Шестнадцатеричный формат обозначается , от , десятичный — или .
Кодирование целых чисел
Рассмотрим способы кодирования целых чисел. Для кодирования используется не менее 1 байта, или 8 двоичных разрядов. Типы данных, в которых хранятся целые числа, обычно состоят из 1, 2, 4 или 8 байт.
Кодирование целых неотрицательных чисел
Рассмотрим типы данных, в которых хранятся целые неотрицательные, или беззнаковые, числа. С помощью двоичных разрядов может быть представлено
различных значений, с кодами от 00dots0 до 11dots1, поэтому в них хранятся целые числа в пределах от 0 до
Пример 1. В четырех байтах число 33 кодируется в виде:
, или ().
Кодирование целых чисел со знаком
Рассмотрим типы данных, которые используются для хранения положительных и отрицательных целых чисел, или целых чисел со знаком. Диапазоны чисел для этих типов данных, которые можно закодировать с помощью 1, 2, 4 или 8 байт, а также минимальные и максимальные числа показаны в таблице 2.2. В первом столбце указывается число байт.
Если количество разрядов в типе данных равно , то диапазон кодируемых чисел составляет от
. Неотрицательные числа кодируются так же, как и в случае беззнаковых чисел, коды этих чисел начинаются с 0 (см. диапазон). Соответственно, коды отрицательных чисел начинаются с 1. Множество отрицательных чисел так же, как и множество положительных, представляется множеством двоичных кодов, упорядоченных по возрастанию.
Рассмотрим, например, тип данных, в котором для кодирования целых чисел со знаком используется 2 разряда. В нем могут быть закодированы числа — 2, — 1, 0, 1 с помощью кодов 10, 11, 00, 01, соответственно. Если тип данных содержит 3 разряда, то в нем могут быть представлены числа — 4, — 3, — 2, — 1, 0, 1, 2, 3 соответственно с помощью кодов 100, 101, 110, 111, 000, 001, 010, 011.
В общем случае левая граница диапазона кодируется двоичным словом 100dots0, а правая — двоичным словом 011dots1.
Итак, если двоичный код числа начинается с 1, то он представляет отрицательное целое число, а если с 0, — то неотрицательное. Старший разряд двоичного кода называется знаковым разрядом. Код, который используется для кодирования неотрицательных целых чисел, называется прямым, а для кодирования отрицательных — дополнительным. Дополнительные коды позволяют заменить операцию вычитания операцией сложения и сделать возможной реализацию операций сложения и вычитания одинаковыми для знаковых и беззнаковых чисел (см. ниже).
Рассмотрим понятия прямого и дополнительного кода в общем случае для системы счисления с основанием , где — целое, .
Пусть для -ичного кодирования , т. е. для представления целого числа в системе счисления с основанием , используется разрядов, и диапазон кодируемых чисел составляет от
Для целого числа x, такого что
, для i = 0, 1, dots, k — 1.
Прямым кодом числа называется его представление в -ичном виде с помощью слова длины :
Обратным кодом числа () называется код
Дополнительным кодом отрицательного числа () называется -ичное представление положительного числа
или -ичное представление суммы
Отсюда, в частности, следует, что
Например, найдем дополнительный код числа
— левой границы диапазона. Прямой код числа
. Поэтому обратный код числа —
Аналогично, найдем дополнительный код числа (- 1). Число 1 имеет прямой код 00dots1, следовательно, обратный код для (- 1) имеет вид:
. Поэтому дополнительным кодом числа (- 1) является
. Найдем также дополнительный код числа 0. Это число имеет прямой код
и, соответственно, обратный код
. Следовательно, дополнительный код равен 1
, так что
. Отметим, что в -разрядной целочисленной арифметике полагают
, т. е. все числа рассматриваются как остатки от деления на
Пример 2. Найдем дополнительный код числа (- 127) при двоичном кодировании в 1 байте. Имеем:
прямой код числа 127: 01111111;
обратный код: 10000000;
дополнительный код: 10000000 + 1 = 10000001;
Пример 3. Найдем дополнительный код числа (- 12) при двоичном кодировании в 4 байтах типа данных . Имеем:
прямой код числа 12: 00000000 00000000 00000000 00001100;
обратный код: 11111111 11111111 11111111 11110011;
дополнительный код: 11111111 11111111 11111111 11110100,
или fffffff4 (hex).
Пример 4. Пусть p = 10. Тогда с помощью 4 разрядов можно закодировать целые числа в пределах от
, т. е. от — 1000 до 999. Найдем дополнительный код при десятичном кодировании числа (- 812). Имеем:
прямой код для 812: 0812;
обратный код: 9187;
дополнительный код: 9188 (= 10000 — 812).
Пример 5. Пусть p = 16. Тогда с помощью 3 разрядов можно закодировать числа в пределах от — 256 до 255. Найдем дополнительный код при 16-ричном кодировании числа (- 50). Имеем:
прямой код числа 50: 032;
обратный код: ;
дополнительный код: .
Зачем нужна двоичная система
Двоичная система выглядит очень непривычно и числа, записанные в ней, получаются огромными. Зачем она вообще нужна? Разве компьютеры не могут работать с привычной нам десятичной системой?
Оказывается, когда-то они именно так и работали. Самый первый компьютер ENIAC, разработанный в 1945 году, хранил числа в десятичной системе счисления. Для хранения одной цифры применялась схема, которая называется кольцевым регистром, она состояла из десяти радиоламп.
Чтобы записать все числа до миллиона — от 0 до 999 999 — надо шесть цифр, значит, для хранения таких чисел нужно целых 60 ламп.
Инженеры заметили, что если бы они кодировали числа в двоичной системе, то для хранения таких же больших чисел им бы потребовалось всего двадцать радиоламп — в три раза меньше!
Первое преимущество двоичных чисел — простота схем. Второе, и не менее важное — быстродействие. Сложение чисел, хранящихся в кольцевом регистре, требует до десяти тактов процессора на каждую операцию. Сложение двоичных чисел можно выполнить за один такт — то есть в десять раз быстрее.
Группа инженеров, создавших первый компьютер, в 1946 году опубликовала статью, где обосновала преимущество двоичной системы для представления чисел в компьютерах. Первой среди авторов была указана фамилия американского математика Джона фон Неймана. Поэтому сейчас принципы проектирования компьютеров называются архитектурой фон Неймана, хотя это не совсем справедливо по отношению к другим изобретателям компьютера.
При разработке программы с двоичной записью столкнуться довольно сложно: компьютер в подавляющем большинстве случаев сам переводит двоичные числа в десятичные и обратно. Можно долго писать код, даже не подозревая, что внутри компьютера данные хранятся каким-то особым образом.
Зачем изучать двоичную систему, если компьютер делает всю работу за нас? Иногда программистам приходится писать программы, которые работают напрямую с оборудованием. Например, разработчики игр должны знать, как работают видеокарты, чтобы сделать компьютерную графику быстрее. А разработчики операционных систем понимают, как устроены диски, чтобы надежно хранить данные.
Программы, которые работают с железом напрямую, называются системными или низкоуровневыми. Для их создания разработчик должен понимать, как устроен компьютер. Поэтому изучение систем счисления позволяет программисту расширить свой профессиональный диапазон и стать специалистом широкого профиля.
Поэтому для того, чтобы писать сложные системные программы, нужно понимать, как устроена двоичная система счисления.
Как переводить десятичные числа в двоичные
Эта задача похожа на математическую загадку, и её можно встретить на олимпиаде для школьников.
Чтобы научиться её решать, давайте ещё раз посмотрим на первые натуральные числа в двоичной и десятичной записи.
Обратим внимание на следующую закономерность: все чётные числа — 2, 4, 6 и 8 — в двоичной записи заканчиваются на 0. Все нечётные числа 1, 3, 5, 7 и 9 — на 1. Этому есть простое объяснение — в двоичной записи число 2 это как 10 в десятичной. Если двоичное число делится на два, оно круглое. Математики говорят, что чётные числа делятся на 2 без остатка (или с остатком 0), а нечётные — с остатком 1:
Попробуем перевести десятичное число 26 в двоичную систему. Для этого используем деление уголком на 2.
Если 26 разделить на 2, то в результате получится 13, остаток от деления 0. Продолжаем дальше:
Из остатков 1, 1, 0, 1 и 0 складывается нужная нам двоичная запись.
Шестнадцатеричная система счисления
Мы знаем, что компьютер использует числа для представления любой информации. Например, цвета хранятся в виде трёх чисел — яркости красной, зелёной и синей компонентов цвета. На каждый компонент отводится восемь двоичных позиций, поэтому максимальная яркость компонента равна 11111111₂ или 255. Цвет целиком описывается большим 24-х разрядным двоичным числом, например, 11111010 10000000 01110010. Это цвет Salmon из таблицы цветов HTML, он же лососевый цвет.
Старшие восемь позиций отводятся для хранения красного компонента, средние восемь — зелёного, и младшие восемь — синего. Мы видим, что такая запись очень громоздка и неудобна.
Кажется, что цвет удобнее записать как десятичное число 16416882. Хотя оно занимает меньше места, по нему трудно понять, какова яркость каждого компонента.
Чтобы записывать большие двоичные числа, программисты придумали использовать шестнадцатеричную систему счисления:
Как и в случае с двоичной системой, цифры 0, 1, 2, 3, 4, 5, 6, 7, 8 и 9 заимствуются из десятичной системы. Но в данном случае этих цифр не хватает: нужно ещё шесть. Их в шестнадцатеричной системе принято обозначать первыми буквами английского алфавита:
Шестнадцатеричная система счисления хороша тем, что группа из четырёх двоичных цифр кодируется одной шестнадцатеричной цифрой. Таким образом, лососевый цвет выглядит как:
В шестнадцатеричной системе счисления он записывается так:
Вначале трудно понять, каков порядок у шестнадцатеричного числа FA. Как и в случае с двоичными числами, программисты обычно помнят порядки круглых шестнадцатеричных чисел. Но можно не запоминать, а подглядывать в эту таблицу:
Чтобы переводить числа из десятичной системы в шестнадцатеричную и обратно, двоичное представление можно использовать как промежуточное. Часто это самый простой способ: двоичное и шестнадцатеричное представления без труда переводятся друг в друга.
Как переводить двоичные числа в десятичные
Разберемся, как быстро переводить двоичные числа в десятичные. Для примера потребуется достаточно большое двоичное число, чтобы мы не могли вычислить его на пальцах.
Запишем его в математической записи, помня, что вместо основания 10, мы используем основание 2.
Из этого примера видно, что у всех слагаемых только два множителя — 0 и 1. Слагаемые с множителем 0 равны нулю, поэтому их можно отбросить, оставив только слагаемые с множителем 1.
У слагаемых с множителем 1 этот множитель можно не записывать.
Теперь нетрудно посчитать сумму.
Вывод: число 11010 в двоичной записи — то же самое, что 26 в десятичной.
Ещё раз повторим, как перевести двоичное число в десятичное.
Программисты иногда запоминают некоторые степени числа два, чтобы уметь оценивать порядок двоичных чисел. Вы можете подглядывать в эту таблицу:
С помощью этой таблицы можно переводить числа из двоичной системы в десятичную практически «в уме».
Сервисы для перевода из системы в систему
Существует множество сервисов для перевода чисел из системы в систему. Это умеет даже Google.
Чтобы перевести двоичное число, например, 11010 в десятичную систему, надо ввести запрос 0b11010 decimal.
Чтобы перевести десятичное число, например, 26 в двоичную систему, надо ввести запрос 26 binary.
Обратите внимание, что Google использует префикс 0b, чтобы отличать двоичные числа от десятичных.
Чтобы перевести десятичное число 137 в шестнадцатеричную систему, введите запрос 137 hex.
Чтобы перевести шестнадцатеричное число 2BAD в десятичную систему, введите запрос 0x2BAD decimal.
Google использует префикс 0x для того, чтобы отличать шестнадцатеричные числа от всех прочих.
Чтобы перевести число 121 в восьмеричную систему, введите запрос 121 octal.
Чтобы перевести число обратно, введите в строке поиска запрос 0o171 decimal.
Мы видим, что Google для представления чисел в двоичной, шестнадцатеричной и восьмеричной системах счисления использует такие же префиксы, которые мы видели в примерах на Python и JavaScript.
Восьмеричная система счисления
Восьмеричная система когда-то использовалась наравне с шестнадцатеричной. Из названия понятно, что она использует всего восемь цифр: 0, 1, 2, 3, 4, 5, 6 и 7. Восьмеричная система подходит для представления шести-, девяти- и двенадцатиразрядных двоичных чисел.
Такие числа встречаются нечасто. Один из самых известных примеров использования восьмеричных чисел — права доступа в операционной системе UNIX. Они записываются девятизначным двоичным числом, например 110100100 или 111101100. Запоминать и передавать такие числа неудобно, поэтому программисты предпочитают восьмеричную систему счисления, и записывают права доступа в виде 644 или 754.
Популярные операционные системы Linux и MacOS берут своё начало в UNIX, поэтому там права доступа также задаются восьмеричным числом.
Пользователи UNIX используют команду stat, чтобы узнать права доступа, и команду chmod, чтобы изменить их. На рисунке вы видите, что команды stat и chmod используют восьмеричные числа. Подробный рассказ об этих командах выходит за рамки нашей статьи. Узнаете больше о правах доступа, и о том, что означают эти числа, можно изучив командную строку Linux.
Подводя итог, можно сказать, что восьмеричные числа сейчас используются редко. В подавляющем большинстве случаев программисты используют шестнадцатеричную запись.
Конвертация чисел в программах
Языки программирования умеют работать с числами, записанными в разных системах счисления, и переводить их из одной системы в другую. Для примера рассмотрим работу с разными системами счисления на Python и JavaScript.
Python
Чтобы записать в Python двоичное число, добавьте перед ним префикс 0b. Десятичное число 26 можно записать в виде 0b11010. У шестнадцатеричных чисел префикс 0x, а у восьмеричных — 0o.
Во всех случаях, чтобы записать число, мы пишем сначала цифру ноль «0», а затем букву, которая определяет систему счисления. Буква «b» — первая в слове binary (двоичный), а буква «o» — в слове octal (восьмеричный). Буква «x» выбивается из общего правила — это третья буква в слове hexadecimal (шестнадцатеричный).
Функции bin(), hex() и oct() преобразуют число в двоичную, шестнадцатеричную и восьмеричную системы.
Благодаря префиксной записи и функциям bin(), hex() и oct(), мы можем преобразовывать числа из любой системы в любую.
JavaScript
В JavaScript для представления чисел используются те же самые префиксы, что и в Python. 0b11010, 0x1a и 0o32 — записи числа 26 в двоичной, шестнадцатеричной и восьмеричной системах счисления.
Для преобразования чисел в другую систему счисления нужно вызывать метод toString(), передав в качестве параметра основание системы.
Обычно в JavaScript мы можем вызвать метод у объекта с помощью точки. Например, если мы сохранили число в переменной i, мы можем узнать его шестнадцатеричное представление, вызвав метод i.toString(16). Но мы не можем вызывать метод у числа 2 — 2.toString(16) — потому что в JavaScript точка в записи чисел разделяет целую и дробную части. Если дробная часть равна нулю, её можно не записывать, поэтому «2.» означает то же самое, что и «2.0».
В примере вы видите три корректных способа обойти эту проблему, и вызвать метод toString() у числа 26.
От десятичных чисел к двоичным
Разберемся, как устроена десятичная система, на примере произвольного большого числа.
Это четырехзначное число, потому что оно состоит из четырёх цифр. И, поскольку речь идёт о десятичной системе, мы можем использовать десять различных цифр.
Величина, которая скрывается за каждой цифрой, зависит от её позиции, поэтому такую систему счисления называют также и позиционной. Справа мы записываем самые младшие значения — единицы, слева от них десятки, затем сотни, и так далее. Запись 1702 означает буквально следующее.
Цифры, записанные в соседних позициях, различаются в десять раз — это и есть десятичная система. Однако, как мы говорили ранее, привычная нам десятичная система — далеко не единственная. Однако, опираясь на неё, нам будет проще понять принципы работы других систем счисления. Например, для записи того же самого числа 1702 в двоичной системе надо придерживаться тех же правил, но вместо десяти цифр нам потребуется всего две — 0 и 1.
Цифры, записанные в соседних позициях, будут различаться не в десять раз, а в два. То есть там, где в десятичной системе мы видим 1, 10, 100, 1 000, 10 000, в двоичной будут числа 1, 2, 4, 8, 16 и так далее.
Это очень большое двоичное число. Давайте запишем его в привычной форме:
Это число могло бы быть очень большим десятичным числом, потому что состоит из тех же цифр. Чтобы отличать двоичные числа от десятичных, в качестве индекса у них указывают основание системы счисления, то есть 2.
Это особенно важно, когда в тексте одновременно встречаются десятичные и двоичные числа.
Заключение
Люди изобрели разные способы записывать числа. Мы называем их системами счисления. Привычный для нас способ записи называется десятичной системой счисления.
Компьютеры, которые работали в десятичной системе, оказались сложными и медленными. Хранение чисел в двоичной системе позволило упростить схемы и ускорить работу компьютеров.
Обычно нам не нужно знать, как именно компьютер хранит числа, потому что он умеет переводить их в привычную нам форму. Но если мы хотим разрабатывать программы, которые работают с оборудованием напрямую — системные утилиты или компьютерные игры, — нужно разобраться, как устроены двоичная и шестнадцатеричная системы.
Существует ряд алгоритмов, которые помогают перевести число из одной системы в другую, но они достаточно запутанные. Проще использовать Google.
Двоичная запись чисел очень громоздкая, поэтому программисты предпочитают записывать числа в шестнадцатеричной системе счисления. Восьмеричная запись чисел сейчас используется очень редко.
Вы можете конвертировать числа из системы в систему на своём любимом языке программирования.