Шаг 25.
Язык программирования C#. Начала
Базовые типы и операторы. Побитовые операторы и двоичные коды

    На этом шаге мы рассмотрим представление чисел в различных системах счисления.

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

    Итак, с некоторой натяжкой можно полагать, что в памяти компьютера числа представлены в виде двоичного кода, в котором есть нули и единицы. Идея записи числа с помощью нулей и единиц принципиально мало чем отличается от способа записи числа посредством цифр от 0 до 9. Допустим, параметры а0, а1,... аn - это некоторый набор цифр (то есть каждый такой параметр - это какая-то из цифр 0, 1 и так далее до 9). Мы можем записать с их помощью число аnаn-1...а2а1а0. Данная запись означает буквально следующее: аnаn-1...а2а1а0 = а0* 100+ а1* 101+ а2 * 102 + ... + аn-1 * 10n-1 + аn * 10n. Например, число 123 = 3*100+ 2*101+ 1*102. А теперь воспользуемся теми же принципами, но вместо десяти цифр (от 0 до 9) будем использовать всего две: 0 и 1. То есть теперь параметры а0, а1,... аn могут принимать одно из двух значений (0 или 1). Если число записано в виде последовательности аnаn-1...а2а1а0, то это будет означать аnаn-1...а2а1а0 = а0 * 20 + а1 * 21 + а2 * 22+ ... + аn-1 * 2n-1 + аn * 2n. Например, если имеется двоичный код 1011011, то он соответствует десятичному числу 1011011 = 1*20+ 1*21+ 0*22+ 1*23+ 1*24+ 0*25+ 1*26 = 1 + 2 + 8 + 16 + 64 = 91. Чтобы выполнить обратное преобразование (десятичное число записать двоичным кодом), достаточно число записать в виде суммы слагаемых, являющихся степенями двойки. Например, определим двоичный код для числа 29. Имеем следующее: 29 = 16 + 8 + 4 + 1 = 24 + 23 + 22 + 20 = 1*20+ 1*22+ 1*23+ 1*24 = 11101.


В приведенных формулах код из нулей и единиц - это двоичное представление числа. Все прочие числа записаны в десятичной системе.
Операции, которые выполняются с десятичными числами, можно выполнять и в двоичном представлении. Например, можно складывать числа в столбик. Для этого достаточно учесть простые правила сложения двоичных чисел:
 0 + 0 = 0,
 1 + 0 = 1,
 0 + 1 = 1,
 1 + 1 = 10. 
Например, десятичное число 13 имеет двоичный код 1101, а число 9 имеет двоичный код 1001. Складываем эти двоичные коды:
   1101 
 + 1001 
 ------
  10110

    Двоичный код 10110 соответствует десятичному числу 22. Так и должно быть, поскольку 13 + 9 = 22.

    Все описанное выше касалось положительных чисел. Есть еще один важный вопрос. Связан он с тем, как в памяти компьютера кодируются отрицательные числа. Проблема в том, что для записи отрицательного числа на бумаге достаточно перед таким числом поставить знак "минус". Но компьютер не умеет "писать минус". Он понимает только двоичные коды. Чтобы понять принципы кодирования отрицательных чисел, проведем небольшой мысленный эксперимент.

    Допустим, имеется некоторое положительное число A, для которого известен бинарный код. Попробуем выяснить, какой бинарный код должен быть у противоположного по знаку числа -A. Мы будем исходить из того, что код числа -A должен быть таким, чтобы выполнялось условие A + (-A) = 0.

    Выполним побитовую инверсию: в бинарном представлении числа A все нули заменим на единицы, а единицы заменим на нули. То, что получилось, обозначим как ~A. Сложим значения A и ~A. Операцию будем выполнять на уровне бинарного кода. Учтем также, что в компьютере для записи числа выделяется определенное количество битов. Обозначим это количество битов как n. Несложно догадаться, что при вычислении суммы A + (~A) мы будем складывать два битовых кода, каждый длиной в n битов. И при складывании битов, находящихся на одинаковых позициях, один бит будет единичный, а другой нулевой. Поэтому в результате вычисления суммы A + (~A) получим бинарный код, который состоит из n битов, и каждый бит равен единице. К тому, что получилось, прибавим единицу - то есть вычислим сумму A + (~A) + 1. Но если к коду из n единиц добавить единицу, то получим бинарный код, в котором самый левый бит единичный, а после него следует n нулей. И вот здесь нужно вспомнить, что речь идет о компьютере, который запоминает только n битов. Поэтому старший единичный бит теряется (для него в памяти просто нет места), и остается код из n нулей. А это код числа 0. Таким образом, компьютер вычисляет указанную сумму как A + (~A) + 1 = 0. Следовательно, код отрицательного числа -A должен совпадать с кодом выражения ~А + 1. Отсюда мы получаем правило записи двоичного кода отрицательного числа.

    Аналогичным образом выполняется и обратное преобразование, когда по коду отрицательного числа необходимо определить это число в десятичной системе счисления.

    Все эти операции для нас имеют скорее теоретический интерес. Но есть важное практическое последствие. Если взять код положительного числа, то старший бит в таком числе будет нулевым. А вот в коде отрицательного числа старший бит единичный. Таким образом, самый старший бит в бинарном коде числа определяет, положительное это число или отрицательное: у положительных чисел старший бит нулевой, у отрицательных чисел - единичный. Поэтому старший бит обычно называют знаковым битом (он определяет знак числа)


В прикладном плане, кроме двоичной, достаточно популярными являются восьмеричная и шестнадцатеричная системы счисления. В восьмеричной системе число записывается с помощью цифр от 0 до 7 включительно. Если в восьмеричной системе число записано в виде последовательности аnаn-1...а2а1а0 (параметры а0, а1,... аn - это цифры от 0 до 7), то в десятичной системе счисления это число определяется так: аnаn-1...а2а1а0 = а0* 80+ а1* 81+ а2* 82+ ... + аn-1* 8n-1+ аn* 8n.

    В шестнадцатеричной системе счисления число кодируется с помощью шестнадцати символов: это цифры от 0 до 9 и буквы от А до F, которые обозначают десятичные числа от 10 до 15. Для шестнадцатеричной системы справедлива такая формула перевода в десятичную систему: аnаn-1...а2а1а0 = а0*160+ а1*161+ а2*162+ ... +аn-1*16n-1n*16n. В данном случае параметры а0, а1,... аn - это цифры от 0 до 9 и буквы от А до F (вместо букв при вычислении суммы подставляются числа от 10 до 15).


    На следующем шаге мы закончим изучение этого вопроса.




Предыдущий шаг Содержание Следующий шаг