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, Linux, Hibernate, Collections, Stream API, многопоточность, файлы, Nginx, Apache, maven, gradle, JUnit, YouTube, новости, руководство, ООП, алгоритмы, головоломки, rest, GraphQL, Excel, XML, json, yaml.
20.09.2023 10:43 Педаля
Где облако тегов в 20 слов по теме системы счисления?
21.09.2023 17:08 devmark
Не хочется плодить лишние тэги без необходимости.