Позиционные системы счисления

Введение

Пусть \(d\) — целое положительное число, большее единицы.

Позиционной системой счисления с основанием \(d\) (или, как ещё говорят, \(d\)-ичной системой счисления) называется множество \(D\) (которое далее мы будем называть множеством цифр) и преобразование \(v:D\to\mathbb{N}\), сопоставляющее каждой цифре её числовое значение.

При этом \(v\) должно осуществлять биекцию между \(D\) и числами от \(0\) до \(d-1\). Это означает, что каждое число этого промежутка должно соответствовать ровно одной цифре.

Традиционно множество цифр состоит из знаков 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 и букв латинского алфавита. Числовые значения «арабских» цифр стандартны. Числовые значения «латинских» цифр начинаются с десяти и идут в том же порядке, в котором идут латинские буквы. То есть, например, числовое значение буквы «z» равно тридцати пяти.

Под записью мы будем понимать преобразование

\[ W(n) = x_{k}x_{k-1} \ldots x_{0} \]

такое, что:

  • если \(n=0\), то \(k=0\) и \(v(x_0)=0\)
  • если \(n>0\), то \(x_{k}\ne0\) и выполнено равенство

\[ n = v(x_k) d^k + v(x_{k-1}) d^{k-1} + \ldots + v(x_0) d^0 \]

Например, \(W(42)=2a\) для шестнадцатиричной системы счисления (значком «42» на входе \(W\) обозначено число сорок два).

Чтение устроено чуть проще:

\[ R(x_{k}x_{k-1}\ldots x_{0}) = v(x_k) d^k + v(x_{k-1}) d^{k-1} + \ldots + v(x_0) d^0 \]

Нетрудно заметить, что \(R(W(x))=x\) (а вот с другим порядком \(R\) и \(W\) это неверно).

Если одновременно рассматривается несколько систем счисления, то обычно их помечают нижним индексом. Например, \(R_{3}\) — троичное чтение, а \(W_{2}\) — двоичная запись. Переводом из системы счисления с основанием \(a\) в систему счисления с основанием \(b\) называют последовательное применение \(R_{a}\) и \(W_{b}\)

Во избежание путаницы договоримся далее, что последовательности цифр внутри формул, не сопровождённые нижним индексом, в числовом контексте следует воспринимать как числа, десятично считанные с этих последовательностей. Последовательности цифр же, сопровождённые индексом \(d\), в числовом контексте следует воспринимать как числа, считанные \(d\)-ично.

Это означает, что формулу

\[ 27+14_5+1101_2 \]

следует интерпретировать как

\[ R_{10}(27) + R_{5}(14) + R_{2}(1101) \]

что, в свою очередь, равно сумме двадцати семи, девяти и тринадцати.

Считывание числа

Операция считывания достаточно примитивна: чтобы считать число, достаточно вычислить значение многочлена

\[ v(x_{k}) d^k + v(x_{k-1}) d^{k-1} + \ldots + v(x_{0}) d^0 \]

Единственное, о чём стоит напомнить: иногда многочлен проще вычислять при помощи так называемой схемы Горнера

\[ \sum_k x^k c_k = (\ldots((c_n x + c_{n-1}) x + c_{n-2}) x + \ldots) x + c_0 \]

Для тех, кому эта формула кажется нечитаемой, приведём аналогичный код (на языке Python):

def evaluate(p,x):
    n = degree(p)
    
    total = coeff(p,n)
    for i in range(n,0,-1):
        total = current * x + coeff(p,i-1)
    
    return total

Например, \(123_{7}\) можно считать по схеме Горнера так:

\[ 123_{7} = (1\cdot 7 + 2)\cdot 7 + 3 = 63 + 3 = 66 \]

Запись числа

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

Сейчас мы приведём два эквивалентных способа записи числа. Первый из них вычисляет цифры, начиная с самой младшей, второй — наоборот, начиная с самой старшей.

Способ первый

Пусть \(N = \sum_k d^k v(a_k)\). Требуется найти цифры \(a_i\) (или хотя бы их числовые значения; будем считать операцию восстановления цифры по числовому значению тривиальной).

Младшую цифру легко определить, если заметить, что

\[ v(a_0) = v(a_0)\bmod d = \left(\sum_k d^k v(a_k)\right)\bmod d \]

Правое из этих двух равенств очевидно, а левое следует из неравенств \(0\leqslant v(a_0) < d\).

Вычтя \(v(a_0)\) из левой и правой частей равенства

\[ N = \sum_k d^k v(a_k) \]

и разделив их на \(d\), получаем такую же по виду задачу для числа \((N-v(a_0))/d\).

Пример

Для того, чтобы записать число \(42\) в троичной системе счисления, можно сделать следующее.

Найдём нулевую цифру: \(v(a_0) = 42 \bmod 3 = 0\).

Далее имеем \(v(a_1) + 3v(a_2) + \ldots = (42-0)/3 = 14\).

Найдём первую цифру: \(v(a_1)=14\bmod 3 = 2\).

Далее имеем \(v(a_2) + 3v(a_3) + \ldots = (14-2)/3 = 4\).

Найдём вторую цифру: \(v(a_2)=4\bmod 3 = 1\).

Далее имеем \(v(a_3) = (4-1)/3 = 1\).

То есть \(W_3(42)=1120\).

Способ второй

Старшую цифру числа \(N\) можно найти так: ищем максимальное \(m\), для которого \(d^m\leqslant N\). Далее ищем максимальное \(c\), для которого \(c d^m\leqslant N\). Это \(c\) и будет числовым значением старшей цифры. Осталось таким же образом найти цифры числа \(N-c d^m\).

Пример

Поскольку \(3^3=27\) «умещается» ровно один раз в числе \(42\), старшая троичная цифра этого числа равна 1.

Остаётся \(42-27=15\). \(3^2=9\) «умещается» в \(15\) тоже один раз. Поэтому следующая троичная цифра числа \(42\) тоже равна 1.

Остаётся \(15-9=6\). \(3^1=3\) «умещается» в \(6\) два раза. Поэтому следующая троичная цифра числа \(42\) равна 2.

Остаётся \(0\), в котором \(3^0=1\) умещается ноль раз. Поэтому последняя цифра троичной записи \(42\) равна 0, а вся запись: 1120.

Быстрый перевод

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

Например, восьмеричных цифр столько же, сколько и троек двоичных. Отсюда следует (поймите, почему!), что число можно перевести из восьмеричной в двоичную, просто заменив каждую цифру на тройку двоичных с тем же значением.

Можно осуществить и быстрый перевод между системами, основание ни одной из которых не является степенью основания другой. Достаточно лишь, чтобы эти основания были степенями одного и того же числа.

Например, переведём 12321 из четверичной системы счисления в восьмеричную:

  • каждая четверичная цифра соответствует паре двоичных: 0 — паре 00, 1 — паре 01, 2 — паре 10, 3 — паре 11
  • значит, \(12321_{4} = 0110111001_{2}\)
  • теперь нужно сгруппировать цифры по три (начиная с самой младшей!): 0 110 111 001
  • осталось, наконец, записать соответствующие восьмеричные цифры (отбросив ведущий ноль): 671