Блог Хеллера's Journal
 
[Most Recent Entries] [Calendar View]

Monday, October 7th, 2013

    Time Event
    10:46a
    Позиционные системы счисления

    В последнее время стало совсем мало времени у меня. Надеюсь, скоро что-нибудь опять существенное напишу, но пока не успеваю. Этот короткий текст — продолжение главы учебника о натуральных числах, довольно долго пылившийся в черновиках. Здесь совсем всё просто и банально, но опять же избежать этого рассказа я никак не могу. Как всегда я призываю всех читать не веб, а pdf.

    После того как мы определили понятие натурального числа, встаёт вопрос о том, как натуральные числа записывать. Пока мы ввели только символы 0, 1, 2, 3 и 4 для нескольких чисел. Мы могли бы продолжить процесс и дальше (пока продолжим этот ряд последовательно символами 5, 6, 7, 8, 9, A), однако довольно быстро возникает проблема: множество \mathbb{N} бесконечное, и соответственно символов нам потребуется бесконечно много, что, видимо, невозможно. Нам нужен способ, который позволит записывать любое натуральные число используя конечное число символов.

    Пусть у нас есть некоторое число n, которое надо записать. Выберем некоторое произвольное b > 0, которое будем называть основанием нашей системы счисления и поделим одно на другое с остатком:

    (1) n = q_0b + r_0

    Здесь r_0 < b и q_0 < n. Поделим теперь на b с остатком значение q_0: q_0 = q_1b + r_1 и подставим это выражение в (1):

    (2) n = (q_1b + r_1)b + r_0 = q_1b^2 + r_1b + r_0

    Аналогично можно представить q_1 = q_2b + r_2 подставив его в (2), затем q_2, q_3 и так далее. Легко увидеть, что последовательность \{q_i\} с каждым следующим элементом убывает, и, стало быть, в какой-то момент найдётся такое k, что q_k = 0. На этом процесс прекратится и мы получим такое выражение для n:

    n = r_kb^k + r_{k-1}b^{k-1} +\ldots + r_1b + r_0

    В этом выражении важно то, что каждое из значений r_i оказывается меньше чем b, и при этом набора \{r_i\} вполне достаточно для того, чтобы однозначно идентифицировать любое число. В этом и заключается основная идея позиционных систем счисления. Число b определяет количество символов, необходимых для представления числа в системе с основанием b.

    В компьютерах применяется так называемая двоичная система счисления, в которой b=2 и используются лишь два символа для записи чисел: 0 и 1. Это обуслевлено тем, что на физическом уровне в вычислительных системах довольно просто отличить два принцпиально различных состояния друг от друга: есть напряжение в проводе/нет напряжения, луч отражается от диска под большим углом/под маленьким, сектор на диске намагничен/ненамагничен. И так далее. Возможно, конечно, и более детальное различение физичеких систем, например мы могли бы различать не просто наличие напряжения, но и его величину: слабое оно или сильное в дополнение к тому, если ли оно вообще. В этом случае b было бы равно трём, и иногда это действительно используется, но технически это часто осуществляется сложнее, поэтому почти всегда используется b=2.

    Рассмотрим пример. Как представить число A в двоичной системе? (Напомню, что за A мы обозначили число, следующее за числом 9). Проделывая процедуру с делением, описанную в начале параграфа, мы приходим к записи

    A = 1\cdot 2^3 + 0\cdot 2^2 + 1\cdot 2 + 0

    Здесь r_3 = 1, r_2 = 0, r_1 = 1, r_0 = 0. Можно кратко записать это как упорядоченный набор: (1, 0, 1, 0), или же даже еще короче, опустив скобки и запятые: 1010. Это и есть двоичное представления числа A. Чтобы не путать системы счисления, удобно так же обозначать основание рядом с числом. В нашем случае получится 1010_2. Впрочем, иногда нам будет удобно пользоваться и записью (1, 0, 1, 0)_2, так что следует иметь её ввиду, по крайней мере в течение ближайших нескольких параграфов. Количество символов, необходимых для представления числа, мы будем называть разрядностью, а выражение r_ib^i i-ым разрядом. Иногда нам будет удобно считать, что число имеет больше разрядов чем необходимо, тогда старшие разряды будут иметь значение 0. Таким образом число 1010_2 можно было бы эквивалентно записать как 00001010_2. Потенциально мы можем считать, что слева в записи числа стоит бесконечное число нулей — это соображение часто упрощает рассуждения и мы будем пользоваться им ниже.

    В повседневной жизни чаще всего применяется десятичная система счисления, в которой b=A и помимо 0 и 1 используются так же символы 2, 3, 4, 5, 6, 7, 8, 9. Рассмотрим, для примера, как представить число 10011001_2 в десятичной системе счисления. Повторяя еще раз процедуру деления с остатком, получаем:
    10011001_2 = 1\cdot A^2 + 5\cdot A + 3 = 153_A

    Рассматривая этот пример, у вас могут возникнуть сомнения по поводу того, как я это вычислил. Ответ тут очень простой: я использовал инженерный калькулятор, который умеет работать с разными системами счисления. Впрочем, даже без калькулятора можно было бы удостовериться в верности данного выражения. Самый простой способ поделить a на b с остатком заключается в многократном вычитании b из a до тех пор, пока результат не окажется меньше b. Этот способ легко понять, но он крайне неэффективен: для его реализации вам потребуется уже не калькулятор, а полноценный компьютер. Тем не менее вычислить это возможно. Пока мы остановимся на этом способе и на самом факте того, что это можно как-то вычислить, а в следующем параграфе я продемонстрирую более эффективный способ деления с остатком, который позволит провести все вычисления используя лишь ручку и клочек бумажки.

    Вездее далее, если не будет оговорено обратное, мы будем использовать десятичную систему счисления, при этом обозначать её мы не будем никак специально, то есть вместо 123_{10} мы будем ограничиваться записью 123.

    В качестве последнего примера рассмотрим шестнадцатеричную систему счисления (b=16), часто используемую программистами. В ней помимо символов десятичной системы применяются так же символы A, B, C, D, E, F. Рассмотрим пример того, как можно понять десятичное значение числа в шестнадцатеричной записи:
    ABF_{16} = A\cdot 16^2 + B\cdot 16 + F = 10\cdot 256 + 11 \cdot + 15 = 2751

    Причина, по которой программисты любят шестнадцатеричную систему счисления, заключается в том, что она очень легко переводится в двоичную систему счисления и обратно. По сути для этого надо знать лишь представление в двоичной системе 16-ти цифр. Для примера выше мы уже видели, что A_{16} = 1010_2, так же легко увидеть, что B_{16} = 1011_2 и F_{16} = 1111_2. Чтобы получить отсюда двоичную запись, достаточно объединить двоичные записи для отдельных шестнадцатеричных цифр: ABF_{16} = 1010\:1011\:1111_2

    Возможность такого представления основывается на следующей несложной общей теореме (сложнее понять формулировку, чем доказать), доказательство которой мы оставим в качестве упражнения читателю (впрочем, я бы пока рекомендовал отложить это упражнение и вернуться к нему после прочтения следующего параграфа):

    Теорема. Записи в системах счисления с основаниями b и c = b^k связаны следующим образом:

    (d_{kn},\dots, d_0)_b

    = ((d_{kn}, \ldots, d_{(k-1)n + 1})_b, \dots, (d_{2k}, \dots, d_{k+1})_b , (d_k, \dots, d_0)_b)_c

    В компьютерной памяти чаще всего двоичные значения 0 и 1 (их называют битами) объединены в группы по восемь бит (число восемь берется из соображений, близких к только что упомянутой теореме). Такая группа бит называется байтом. Во многих системах один байт представляет собой один печатный символ. Если же рассматривать байт как число, что его значения могут варьироваться от 0 до 255 (всего 256 различных значений), и таким образом каждому символу можно сопоставить некоторое числовое значение. Всего у нас может быть максимум 256 символов.

    Если рассматривать не один, а сразу последовательность байт, то их можно считать числом, записанном в 256-ричной системе счисления. Это часто применяется в компьютерах для записи больших чисел. Если рассматривать два байта, то их максимальным значением может быть 65535. Если считать за символ не один байт, а два байта, то это значит, что наша система сможет поддерживать 65535 символов, что хватит даже китайцам с несколькими их диалектам, Египтянам, латинянам и евреям. Если нам и этого мало, то можно рассматривать четырехбайные значения. В этом случае мы сможем записать число 4294967295, то есть четыре байта позволяют записывать девятизначные числа и некоторые десятизначные. С точки зрения символов мы сможем уместить сюда не только все распространенные в мире языки, но и все вымершие языки, смайлики, музыкальные обозначения, матемаетические знаки, несколько вариантов древней клинописи и так далее. Если нам и этого не хватит, то можно взять 8-байтные целые, которые позволят работать с 19-значными числами.

    Если мы будет рассматривать текст как последовательность символов, то мы так же эту последовательность можем интерпретировать как некоторое большое число. Например, для кодирования английского текста чаще всего применяется стандарт ASCII, устанавливающий какой букве соответствует какое число. Букве F в нём соответствует число 70, а букве o — 111 (ASCII использует только 1 байт для кодирования символов). Как число слово Foo в ASCII можно представить следующим образом:

    Foo = 70 \cdot 256^2 + 111 \cdot 256 + 111 = 4587520 + 28416 + 111 = 4616047

    Подобное отношение к тексту позволяет применять к нему математические функции. Например, многие криптосистемы представляют собой всего лишь некоторые арифметические действия над числами и даже не догадываются о том, что пользователь рассматривает данные как текст. Самым ярким примером является криптосистема RSA, на которой сейчас построена значительная доля всей криптографии, используемой на практике, и которую мы рассмотрим в четвертой главе. Используя действия над числами можно так же сжимать данные, чтобы они занимали меньше места. Этот подход называется арифметическим кодированием и мы так же рассмотрим его в четвертой главе. В четвертом параграфе этой главы мы будем рассматривать математические формулы как обычный текст, который в свою очередь мы будем рассматривать как обычное число. Довольно неожиданным образом это позволит сделать нам фундаментальные выводы относительно всей математики в целом.

    << Previous Day 2013/10/07
    [Calendar]
    Next Day >>

Блог Хеллера   About LJ.Rossia.org