Сегодня мы разберёмся с тем, как работает кодирование информации. За простым набором нулей и единиц скрывается целый мир: от того, как устроена память компьютера, до того, почему текст на экране иногда превращается в непонятный набор символов. Мы шаг за шагом посмотрим, как данные записываются и считываются с жёсткого диска, как работает головка чтения-записи и что вообще означает намагниченность в контексте хранения информации.
Мы рассмотрим, как протекают физические процессы на уровне железа. Причем это не про сленговое название комплектующих компьютера, а про реальный металл, который установлен внутри ваших жёстких дисков. Узнаем, как именно движение элементарных частиц превращается в основу цифровой сигнал из нулей и единиц в компьютере. Знание таких основ – это настоящий фундамент, так называемая база, всей информатики.
Мы обсудим, как из этих нулей и единиц собираются числа, буквы и даже сложные мультимедийные файлы. Поговорим о кодировках текста: почему компьютер «понимает» символы только в виде чисел, чем отличается ASCII от Unicode и UTF-8, и почему иногда вместо привычного текста вы видите странные квадратики или нечитаемые значки, если кодировка «сбилась».
Наконец, мы разберём более теоретические вещи: что такое однозначное декодирование, зачем нужно равномерное кодирование и при чём здесь условие Фано. Эти понятия встречаются в заданиях по информатике, но на самом деле объясняют базовые правила того, как информация превращается в удобный и надёжный для хранения и передачи вид.
Навигация по странице
Информация в железе
Память компьютера, независимо от того, жёсткий диск это или электронные микросхемы памяти вроде SSD или оперативной памяти, хранит данные только в цифровом виде. То есть вся информация – текст, изображения, музыка или видео – представлена последовательностью сигналов двух уровней: высокого и низкого. Эти сигналы легко интерпретируются как нули и единицы, а дальше уже строятся более сложные структуры: байты, файлы, базы данных.
Рассмотрим устройство жёсткого диска (HDD). Он состоит из нескольких ключевых компонентов:
- Корпус, который защищает внутренние элементы от пыли и повреждений;
- Магнитные диски (пластины), на которых и хранится информация;
- Головки чтения/записи, которые «пишут» и «читают» данные;
- Двигатель, который раскручивает пластины с большой скоростью.
Наиболее интересны для нас сами магнитные диски, ведь именно на них физически хранится информация. Пластины сделаны из специальных сплавов с магнитными свойствами – чаще всего это ферромагнитные материалы (диоксид хрома), которые легко намагничиваются и сохраняют направление намагниченности.
На поверхности диска информация хранится в виде последовательности битов, где каждый бит представлен направлением вектора намагниченности микроскопического участка пластины, например:
- Вектор намагниченности вверх → высокий уровень → логическая единица (1)
- Вектор намагниченности вниз → низкий уровень → логический ноль (0)
Когда нужно записать данные, головка создаёт сильное локальное магнитное поле, которое ориентирует маленький участок ферромагнитного материала в нужном направлении. Если данные нужно изменить, то на этом же участке вектор намагниченности может быть переориентирован в другую сторону.
Чтение данных происходит обратным образом: головка не создаёт поле, а фиксирует изменения магнитного потока, возникающие из-за ориентации вектора намагниченности. Сенсор внутри головки реагирует на направление магнитного поля и преобразует его в электрический сигнал высокого или низкого уровня – то есть в 1 или 0.
Таким образом, жёсткий диск превращает физическое свойство материала – намагниченность – в цифровую информацию. Буквально крошечные участки сплава на пластине хранят всю библиотеку компьютера, а головка «воспринимает» их как простые нули и единицы.
После того как мы поняли, как отдельные участки пластины намагничены и представляют собой биты, логично задаться вопросом: а как эти миллионы битов организованы, чтобы компьютер мог быстро их находить и считывать? Для этого в жёстком диске используется иерархическая структура хранения информации.
Поверхность каждой пластины разбита на концентрические окружности, которые называют дорожками. Вдоль каждой дорожки расположены последовательности битов. Разные дорожки отделены друг от друга небольшими зазорами, чтобы головка не считывала соседнюю дорожку по ошибке.
Дорожки, в свою очередь, делятся на более мелкие участки – сектора. Один сектор обычно содержит фиксированное количество байт (часто 512 или 4096 байт) и является минимальной единицей данных, которую дисковая система может адресовать и считывать за один раз.
Когда нужно прочитать какой-либо файл, контроллер диска вычисляет, какие дорожки и сектора содержат нужные данные, и перемещает головку к соответствующему сектору.
Стоит отметить, что в жёстком диске несколько магнитных пластин, расположенных друг над другом. Каждая пластина (1) – это отдельная поверхность для хранения данных, и каждая имеет свои дорожки и сектора.
Использование нескольких пластин увеличивает объём памяти: чем больше пластин, тем больше битов можно записать в одном устройстве. Головки чтения/записи (2) находятся над каждой пластиной, и когда диск работает, они перемещаются синхронно, чтобы одновременно обращаться к одинаковым областям на всех пластинах.
Все дорожки на разных пластинах, находящихся друг над другом, образуют цилиндры. Если представить это в 3D, то цилиндр – это вертикальный «столбик» из дорожек на каждой пластине, находящихся под головкой одновременно. Такая организация позволяет очень быстро перемещать головку только в радиальном направлении, а данные со всех пластин в цилиндре считывать практически одновременно.
Благодаря такой структуре контроллер диска может быстро находить запрашиваемые данные. Каждый сектор, каждая дорожка и каждый цилиндр имеют адреса, по которым головка понимает, где именно на пластине хранится нужная информация.
Когда данные считываются, магнитная головка фиксирует направление вектора намагниченности каждого бита в секторе, преобразует его в электрический сигнал, а затем этот сигнал превращается в привычные нам байты, из которых состоят файлы.
Таким образом, дорожки, сектора и цилиндры – это физический каркас, на котором строится логическая организация данных. Без этой системы нули и единицы просто лежали бы хаотично, и найти нужную информацию было бы невозможно.
Цифровые сигналы
После того как мы разобрались с устройством жёсткого диска, логично перейти к электронным накопителям и понять, как информация хранится и считывается там. В жёстких дисках это были направления намагниченности, а в SSD и других электронных компонентах – напряжение.
В твердотельных накопителях (SSD) и в микросхемах оперативной памяти каждая ячейка памяти представляет собой транзистор, который может удерживать электрический заряд. Для компьютера важно не точное количество электронов в ячейке, а то, превысило ли напряжение определённый порог:
- Если напряжение выше порога – это высокий уровень, или логическая единица (1).
- Если напряжение ниже порога – это низкий уровень, или логический ноль (0).
То есть физически в ячейках хранятся аналоговые величины – реальные электрические сигналы. Компьютер же видит только два состояния: высокий или низкий сигнал. Процесс интерпретации этих сигналов как 0 или 1 называется дискретизацией аналогового сигнала.
Именно поэтому вся информация в компьютере, независимо от носителя, хранится в двоичной системе счисления. Любой текст, изображение, звук или видео сначала переводятся в последовательность нулей и единиц.
Главное преимущество цифрового подхода в том, что он устойчив к шуму и небольшим искажениям. Даже если напряжение немного колеблется, пока оно остаётся выше или ниже порога, компьютер корректно интерпретирует бит. Благодаря этому устройства могут надёжно хранить и быстро обрабатывать огромные объёмы информации.
Таким образом, если жёсткий диск использует физические направления намагниченности для кодирования 0 и 1, то SSD и микросхемы памяти используют аналоговое напряжение, которое переводится в цифровые сигналы.
Декодирование
Если компьютеру удобно хранить данные в виде нулей и единиц, то как же человеку тогда понимать эту же информацию? Для этого применяется обратная операция – декодирование.
Декодирование – это процесс, обратный кодированию. Он заключается в преобразовании закодированной информации обратно в исходный вид.
Проще говоря, компьютер читает последовательности нулей и единиц и переводит их в знакомые нам символы, текст, изображения или звук. Благодаря декодированию мы можем видеть на экране слова, слушать музыку и работать с файлами, даже если на самом деле всё это хранится в виде двоичных данных.
Например, возьмём слово «Привет». Когда мы вводим его в компьютер, оно сначала преобразуется в последовательность нулей и единиц. В популярной кодировке UTF-8 это будет так:
11010000 10011111 11010001 10000000 11010000 10111000 11010000 10110010 11010000 10110101 11010001 10000010
Каждый блок из 8 нулей и единиц – это байт, а комбинации байтов кодируют конкретные символы. При выводе на экран компьютер декодирует эти байты обратно в привычный текст «Привет».
Важно понимать, что декодирование возможно только при знании исходной кодировки, в которой данные были сохранены. Если кодировка нарушена или не совпадает, на экране появляются непонятные символы. Это потому, что компьютер неверно интерпретирует байты и не знает, как их правильно преобразовать обратно в символы.
Однозначное декодирование
Но вернёмся к нашему закодированному слову «Привет». Как же компьютер понимает, что набору символов «11010000 10011111» соответствует именно буква «П», а не любое другое значение?
Это работает за счет того, что у нас выполняется принцип однозначного декодирования.
Однозначное декодирование – это свойство кода, которое позволяет восстановить исходные данные без малейшей ошибки и двусмысленности. Иными словами, каждому коду соответствует только один символ или сообщение, и наоборот: каждая последовательность символов всегда однозначно превращается в набор битов.
Простой пример: пусть у нас есть кодировка, где букве «А» соответствует 0, букве «Б» – 10, букве «В» – 11. Если мы прочитаем последовательность 0110, мы точно знаем, что она расшифровывается как «АБ», а не как «ВА» или какой-то другой набор.
Это и есть однозначное декодирование: компьютер никогда не путает, что за символ закодирован конкретной последовательностью битов.
Теперь рассмотрим неоднозначный код: пусть букве «А» соответствует 0, букве «Б» – 01, букве «В» – 1. Попробуйте теперь расшифровать последовательность 011!
Это может быть любой из двух вариантов:
- АВВ
- БВ
То есть здесь невозможно однозначно понять, какое сообщение было закодировано. Любая попытка декодирования приводит к двусмысленности, и компьютер не сможет корректно восстановить исходное сообщение.
К однозначной дешифровке мы вернёмся немного позже. А теперь обратите внимание, что слово «Привет» в кодировке UTF-8 закодировано так, что каждой букве соответствует одинаковое количество бит. А в нашем примере почему-то букве «А» соответствует 1 бит, а букве «Б» – уже 2 бита.
Давайте разбираться.
Равномерное кодирование
Слово «Привет» в UTF-8 закодировано так, что каждой букве соответствует одинаковое количество бит – 2 блока по 8 бит, то есть по 2 байта на символ. Такой способ кодирования называют равномерным.
Равномерное кодирование – это метод, при котором все символы или сообщения кодируются одинаковым количеством битов. Другими словами, каждый символ имеет фиксированную длину кода.
Равномерное кодирование легко реализовать и удобно использовать. Оно эффективно работает при передаче данных по каналам связи с фиксированной пропускной способностью.
Однако в нём есть и недостатки: для редко встречающихся символов память используется неэффективно: например, буква «А», которую мы используем довольно часто будет занимать столько же памяти, что и буква «Ъ», который может встретиться от силы один раз за весь текст.
Согласитесь, было бы эффективнее наиболее часто встречающемуся символу задать маленькую размерность, например в 1 бит, а символу, который встречается реже всего – наоборот, самую большую.
В таком случае наше сообщение будет занимать куда меньше памяти, чем при равномерном кодировании. И такой принцип кодирования называется неравномерным.
Неравномерное кодирование – это метод кодирования, при котором символы или сообщения могут иметь различную длину кода в зависимости от их частоты появления. Более частые символы имеют более короткие коды, а менее частые – более длинные.
Представим, что у нас есть алфавит из 3 букв: A, B и C. Если мы используем неравномерное кодирование, то можем присвоить каждой букве разное количество бит в зависимости от её частоты появления:
- A – 1 бит (наиболее частый символ)
- B – 2 бита
- C – 3 бита
В таком случае слово «ACABAB» будет занимать в памяти 10 бит. (1 + 3 + 1 + 2 + 1 + 2). Это самый эффективный вариант кодирования символов для данного сообщения. А что, если бы мы выбрали другой?
Например, присвоим буквам следующее количество бит:
- A – 3 бит
- B – 2 бита
- C – 1 бита
Тогда все то же сообщение «ACABAB» занимало бы уже 14 бит (3 + 1 + 3 + 2 + 3 + 2). А при равномерном кодировании – все 18 бит так, как каждый символ занимал бы по 3 бита. Так что крайне важно правильно и целесообразно выбирать код для каждой буквы сообщения!
А какой код нам выбрать для каждой буквы? Мы уже ранее говорили, что у нас должно быть однозначное декодирование, но в чём оно заключается?
Как мы уже ранее выяснили, однозначное декодирование гарантирует, что каждая последовательность битов соответствует ровно одному символу.
Но при неравномерном кодировании символы имеют разную длину, и здесь легко допустить ошибку: часть кода одного символа может совпасть с началом кода другого, как это было в примере про буквы «А», «Б» и «В».
Чтобы избежать двусмысленности и невозможности корректного восстановления сообщения применяется условие Фано.
Условие Фано
Условие Фано гласит, что никакое кодовое слово не может быть началом другого кодового слова. Если соблюдать это правило, компьютер всегда сможет однозначно определить, где заканчивается один символ и начинается следующий.
Представьте, что у нас два кодовых слова для букв «А» и «Б». Если код буквы «А» – 0, а код буквы «Б» – 01, мы получаем нарушение условия Фано, потому что код «А» (0) является началом кода «Б» (01). В результате при получении кода 01 его невозможно будет однозначно декодировать.
Существует и обратное условие Фано, которое говорит, что никакое кодовое слово не должно заканчиваться на другой код. Это особенно важно для некоторых схем передачи и хранения данных, где проверка конца слова критична.
Соблюдение этих правил позволяет строить коды так, чтобы каждый символ имел единственный путь декодирования даже в длинных потоках битов и при сложных сообщениях.
Из этих принципов выводятся два важных понятия: префиксный код и постфиксный код. Префиксный код гарантирует, что ни одно кодовое слово не начинается с другого, а постфиксный код – что ни одно кодовое слово не заканчивается на другое.
Таким образом, если мы хотим применять неравномерное кодирование, экономить память и одновременно сохранять возможность корректного декодирования, условие Фано становится обязательным инструментом.
Именно благодаря этому принципу кодирование остаётся безопасным и эффективным, а компьютеры могут безошибочно преобразовывать последовательности битов обратно в исходные символы.
А грамотно распределять кодовые слова по буквам и применять условие Фано мы научимся далее, при разборе алгоритма решения 4 задания ЕГЭ по информатике.
Но для распределения кодовых слов нам необходимо научиться правильно строить двоичные деревья, чему и посвящена следующая статья.