26 февраля 2023
Тэги: Java, алгоритмы, головоломки, руководство.
В математике и программировании понятие системы счисления занимает очень важную роль. За столь умным названием кроется довольно простая идея. Система счисления – это способ записи (представления) чисел.
Иными словами, как записать любое сколь угодно большое число, имея в арсенале всего 10 цифр-символов? Правильно, комбинируя эти цифры друг с другом. Причём расположение цифры в записи числа имеет значение, ибо 123 не равно 321. Хотя цифры используются одинаковые.
В повседневной жизни мы используем десятичную систему счисления, хоть и не задумываемся над этим. Просто так исторически сложилось. Десятичной она называется потому что для записи любого числа используется ровно 10 цифр.
Обратите внимание, что любое число в десятичной записи можно разбить на слагаемые и степени числа 10. Например:
Однако помимо десятичной существуют другие системы счисления. И у каждой из них своя область применения.
Наверное, самой первой системой счисления, возникшей на заре человечества, была единичная система счисления. Запись любого числа делалась единственным символом – вертикальной чертой – как если бы мы делали засечки на стволе дерева, подобно потерпевшему крушение на необитаемом острове. Число чёрточек равно значению. Чем больше число – тем длиннее его запись.
В какой-то момент люди задумались, а что, если нам использовать разные символы в записи числа? Как развитие этой мысли, следующая система счисления, которая приходит на ум – римская. Она используется и в наше время. В ней определённые числа обозначались соответствующей буквой:
Число | Обозначение |
---|---|
1 | I |
5 | V |
10 | X |
50 | L |
100 | C |
500 | D |
1000 | M |
В римской системе счисления важно взаимное расположение бОльших и меньших цифр относительно друг друга. Если меньшее число находится слева от большего (и при этом не может повторяться), то оно вычитается из большего, а если справа – прибавляется.
Примечательно, что 0 нельзя записать в виде римского числа.
В вычислительной технике широко распространена двоичная система счисления. Любое число в ней записывается как последовательность нулей и единиц. Это тесно связано с технической реализацией ячеек памяти в комьютере. 0 – низкий заряд, 1 – высокий. Каждая такая ячейка называется битом. Бит – это минимальная единица информации.
Рассмотрим несколько примеров:
Если приглядеться повнимательнее, можно увидеть следующую закономерность. Двоичная запись числа – это сумма чисел, в котором цифра соответствующего разряда умножается на 2 в степени, равной индексу расположения этой цифры. Самая правая цифра умножается на 2 в степени 0, т.е. на 1. Самая левая – на 2 в степени, равной количеству цифр в записи числа минус 1.
Двоичная запись также не отличается компактностью. Поэтому логичным развитием двоичной системы в вычислительной технике стала восьмеричная. Так мы можем одной цифрой записать значение трёх бит. Общий принцип остался прежним, но теперь у нас используется не только 0 и 1, а все цифры от 0 до 7:
В какой-то момент инженеры ЭВМ пошли ещё дальше и решили компактно записывать целый байт данных. 1 байт = 8 бит. Всего 256 возможных комбинаций, а 256 – это 16 в квадрате. Так появилась шестандцатеричная система счисления, в которой используются не только цифры от 0 до 9, но и буквы от A до F. Откуда взялись буквы? Просто нужно было как-то обозначать одним символом цифры от 10 до 16. В остальном прежний принцип сохраняется.
Поскольку в шестандцатеричной записи используются буквы, то некоторые числа в этой системе могут быть записаны только с помощью букв. То есть некоторые слова английского алфавита являются шестнадцатеричными числами! Попробуйте вычислить, чему равны в шестандцатеричной системе слова «BAD», «CAFE», «FACADE».
Следуя приведённой выше логике, реализуем на Java алгоритм для преобразования из двоичной, восьмеричной или шестнадцатеричной системы в привычную нам десятичную.
Метод convertToDecimalNumber() принимает на вход запись числа в виде строки и основание системы счисления (2, 8 или 16).
Здесь мы в начале инициализируем результат decimal нулём. Затем проходимся по каждому символу строки и преобразуем его в соответствующую цифру с помощью метода hexCharToInt(). После этого происходит умножение результата предыдущей итерации на основание системы счисления.
Вспомогательный метод hexCharToInt() выглядит тривиально:
Его можно записать гораздо компактнее, пользуясь тем свойством, что в ASCII кодировке все цифровые символы идут подряд и их можно вычитать друг из друга как цифры. Но я решил привести более общую реализацию.
Теперь проверим работу нашего метода:
Как видите, с шестнадцатеричными значениями бывает очень забавно работать.
Но это «нативная» реализация алгоритма. Её писать совершенно не обязательно, т.к. в стандартной библиотеке есть готовый метод Integer.parseInt(), принимающий те же параметры, что и наш самописный метод.
Напоследок хочу заметить, что на моём сайте есть онлайн-утилита для преобразования из одной системы счисления в другую.
Kotlin, Java, Spring, Spring Boot, Spring Data, SQL, PostgreSQL, Oracle, H2, Linux, Hibernate, Collections, Stream API, многопоточность, чат-боты, нейросети, файлы, devops, Docker, Nginx, Apache, maven, gradle, JUnit, YouTube, новости, руководство, ООП, алгоритмы, головоломки, rest, GraphQL, Excel, XML, json, yaml.
20.09.2023 10:43 Педаля
Где облако тегов в 20 слов по теме системы счисления?
21.09.2023 17:08 devmark
Не хочется плодить лишние тэги без необходимости.