Простая математика в основе алгоритмов перевода между десятичной и двоичной системами
Если поискать в интернете How to convert from decimal to binary, вы найдёте четыре простых алгоритма: два для целых чисел и два для дробей. Они приведены с примерами ниже, в первой части статьи. Но хотя знания самих алгоритмов почти всегда достаточно, я решил разобраться, почему они работают. Во второй части статьи объясняется элементарная математика, лежащая в основе каждого из них. Понимание её может помочь вам восстановить любой из алгоритмов, если вы вдруг его забудете. Настоятельно советую взять блокнот и ручку и выполнять операции вместе со мной — так математика запомнится лучше. Вот те четыре алгоритма с примерами, которые можно найти в сети.
Перевод десятичного целого в двоичное
Чтобы перевести целое число в двоичную систему, возьмите исходное число и разделите его на 2, отмечая частное и остаток. Продолжайте делить частное на 2, пока не получите частное, равное нулю. Затем просто выпишите остатки в обратном порядке.
Вот пример такого перевода на числе 12. Сначала поделим число на два, указывая частное и остаток:
Теперь остаётся выписать остатки в обратном порядке — 1100. Итак, 12 в десятичной системе представляется как 1100 в двоичной.
Перевод десятичной дроби в двоичную
Чтобы перевести дробь между 0 и 1 в двоичную систему, умножайте дробную часть на 2 и записывайте полученную целую часть. Эти цифры по порядку образуют запись после двоичной запятой. Остановитесь, когда дробная часть станет нулевой или вы получите достаточно битов: у дробей вроде 0.1 двоичное разложение бесконечно периодическое.
Вот пример такого перевода на дроби 0.375.
Теперь просто выпишем получившуюся целую часть на каждом шаге — 0.011. Итак, 0.375 в десятичной системе представляется как 0.011 в двоичной.
Перевод двоичного целого в десятичное
Чтобы перевести двоичное целое в десятичное, начните слева. Возьмите промежуточный результат, умножьте его на два и прибавьте текущую цифру. Продолжайте, пока цифры не закончатся. Вот пример такого перевода на целом числе 1011.
Перевод двоичной дроби в десятичную
Чтобы перевести двоичную дробь в десятичную, начните справа с промежуточного результата, равного 0. Возьмите промежуточный результат, прибавьте текущую цифру и разделите результат на 2. Продолжайте, пока цифры не закончатся. Вот пример такого перевода на дроби 0.1011. Деление на 2 я просто заменил умножением на 1/2.
Вот вам четыре простых алгоритма, которые позволяют переводить двоичные числа в десятичные и обратно.
Разложение числа по основанию q
Ключ к пониманию того, почему эти алгоритмы работают, — это разложение числа по основанию q. Целое число в любой системе счисления можно представить в следующем виде:
где N — целое число, x — цифра (от 0 до 9 для системы по основанию 10, 0 и 1 для системы по основанию 2), q — значение основания (10 для системы по основанию 10, 2 для системы по основанию 2).
Далее в статье эта форма называется разложением числа N по основанию q, или просто разложением по основанию q. Посмотрим, как оно выглядит для числа 12 в десятичной и двоичной системах:
Точно так же дробное число в любой системе счисления можно представить в следующем виде:
где N — дробь, x — цифра (от 0 до 9 для системы по основанию 10, 0 и 1 для системы по основанию 2), q — значение основания (10 для системы по основанию 10, 2 для системы по основанию 2).
Для числа 0.375 в десятичной и двоичной системах представление такое:
Перевод десятичного целого в двоичное
Как выясняется, эту форму разложения по основанию q можно использовать для перевода числа из десятичной системы в двоичную. Сделаем это для того же числа 12. Сначала представим, будто мы не знаем, как оно записывается в двоичной системе, и выпишем его, заменив неизвестные цифры на x:
Наша задача — найти все x. Посмотрим, что здесь можно сделать. Первое, что нужно заметить: все слагаемые, кроме последнего, будут чётными числами, потому что все они кратны двум. Пользуясь этим, мы можем определить значение цифры x0: если переводимое целое чётное, то x0 равен 0, а если нечётное — то x0 должен быть 1. У нас число 12, оно чётное, значит x0 равен нулю. Запишем это:
Дальше нужно найти значение x1. Поскольку все слагаемые от x1 до xN кратны двум, мы можем вынести 2 за скобку, чтобы выделить x1. Сделаем это:
Также легко увидеть, что сумма значений внутри скобок равна 6. Значит, наш первый шаг можно записать так:
Продолжим искать остальные x. Многочлен внутри скобок можно выписать отдельным выражением:
Применяя ту же логику, что и выше, видим, что x1 равен 0. Перепишем это и снова вынесем 2 за скобку:
Итак, наш второй шаг:
Теперь видна закономерность. Мы можем продолжать выносить 2 за скобку, пока частное не станет нулём. Пойдём по этой схеме и посмотрим, что получится.
Поскольку частное равно 1, остаётся лишь одно слагаемое, поэтому перепишем предыдущее выражение:
Итак, наш третий шаг:
В итоге получаем следующее:
Понятно, что x3 равен 1. Но поскольку для нашего алгоритма нужно частное, перепишем предыдущее выражение так, чтобы в нём было частное:
Так как мы получили частное 0, работать больше не с чем, и это был наш последний шаг. Выпишем его:
Итак, перевод закончен. Вот как он выглядит по шагам:
Теперь ясно, что остаток на каждом шаге соответствует значению x в соответствующей позиции: первый остаток соответствует первому x, второй остаток — второму x и так далее. Значит, число 12 в двоичной системе по описанному выше алгоритму представляется как 1100.
Напомню, что мы начинали с намерения показать, почему работает алгоритм с делением на 2. Возьмём описанные выше шаги и перенесём 2 в левую часть выражений:
Вот так и видно, как мы пришли к алгоритму, описанному в начале. Расчёты этих четырёх шагов можно также свести в одно представление, вот такое:
Убедитесь, что вы понимаете, как мы получили это представление — оно понадобится, когда мы будем разбирать, как работает алгоритм перевода из двоичной системы в десятичную.
Перевод десятичной дроби в двоичную
Чтобы показать, почему при переводе дробей в двоичную систему мы умножаем на 2 и берём целую часть, я тоже воспользуюсь формой разложения по основанию q — для дробей. Возьму дробное число 0.375 из первой части статьи. Как и с целой частью, представим, будто мы не знаем, как это число записывается в двоичной системе, и выпишем его, заменив неизвестные цифры на x:
Как и с целыми числами, наша задача — найти все x, выделяя их по одному. Посмотрим, как это сделать. Первое, что стоит заметить: отрицательные степени 2 дают нам дроби, знаменатели которых — положительные степени 2. Перепишем выражение выше:
Сразу очевидно, что в правой части выражения можно просто вынести 1/2 за скобку. Сделаем это:
а затем перенесём 1/2 в левую часть
Итак, мы выделили x1 и знаем, что он может быть либо 1, либо 0. Чтобы определить, какая это цифра, посмотрим на остальные слагаемые:
Подумаем, насколько большой может быть сумма этих чисел. Если максимальное значение цифр x равно 1, то можно просто заменить x единицами и записать сумму так:
Эта конечная геометрическая сумма строго меньше 1. С ростом числа слагаемых она приближается к 1, но при конечном n не достигает её. Поэтому оставшиеся цифры дают только дробную часть:
Теперь должно быть понятно: если правая часть меньше 1, то x1 не может быть равен 1, а значит он равен 0, тогда как остаток равен 0.75.
Это выглядит в точности как первый шаг алгоритма, приведённого в начале:
Возьмём дробную часть 0.75 и вынесем ещё одну 1/2, чтобы выделить x2:
и перенесём 1/2 влево:
Теперь, если x2 равен 0, то сумма правой части выражения не может быть больше 1, но левая часть равна 1.5, значит x2 должен быть 1, а остаток — 0.5. Выпишем это:
И это снова следует схеме алгоритма, приведённого в начале:
Повторим те же действия для оставшейся дробной части 0.5.
По той же логике, что и выше, видим, что x3 равен 1 и дробной части не остаётся:
Поскольку оставшаяся дробная часть равна 0, наш последний шаг выглядит так:
Выпишем ещё раз все шаги:
Это в точности тот алгоритм, который я привёл в начале. Как и с целыми числами, расчёты этих трёх шагов можно свести в одно представление:
И снова важно хорошо понять эту запись — она понадобится при разборе перевода из двоичной системы в десятичную.
Почему не все дроби имеют конечное двоичное представление
Рациональное число имеет конечное разложение по основанию q, если его знаменатель после сокращения делит некоторую степень q. В десятичной системе его простыми множителями могут быть только 2 и 5; в двоичной он должен быть степенью 2. Например, 0.625 можно записать со знаменателем 10³:
А у 1/3 нет конечного десятичного представления:
То же самое и для системы по основанию 2:
Но если взять 0.1, то знаменатель равен 10, а это не степень 2, значит 0.1 в двоичной системе будет бесконечной дробью. Убедимся в этом с помощью алгоритма, который мы разобрали выше:
Так можно продолжать бесконечно, но давайте запишем это как периодическую дробь:
Перевод двоичного целого в десятичное
Я возьму то же двоичное целое 1011 из первого раздела, чтобы показать, почему работает алгоритм с умножением на 2. Здесь мы тоже воспользуемся формой разложения по основанию q. Запишем число в этом виде:
Все слагаемые, кроме последней цифры, содержат множитель 2. Последовательно выносим его из старших разрядов, оставляя каждую последнюю цифру за скобками:
Теперь, если просто соблюдать порядок математических операций, вы получите в точности те же шаги, что я показал в начале, а именно:
Таким образом, 1011 в двоичной системе — это 11 в десятичной.
Перевод двоичной дроби в десятичную
Вот мы и дошли до последнего алгоритма. Возможно, вы уже сами разобрались в его механике. Если нет — посмотрим, почему он работает. Форма разложения по основанию q и здесь оказывается ключом. Возьмём число 0.1011 из первого раздела. Запишем его в развёрнутом виде:
И снова, поскольку все слагаемые кратны 1/2, мы можем выносить 1/2 за скобку, пока не останется дробной части. Сделаем это:
Соблюдение порядка математических операций даёт алгоритм, описанный в начале:
Таким образом, 0.1011 в двоичной системе — это 0.6875 в десятичной.