Я опубликовала в интернет-журнале статью на тему двоичного представления информации компьютерами и, среди прочих, неоднократно получала вопрос: «Почему в архитектуре x86 используются байты, состоящие именно из 8 бит, а не иного их количества?»
Я считаю, что на любой подобный вопрос можно дать два основных ответа и некую их комбинацию:
- Так сложилось исторически, и другой размер (например, 4, 6 или 16 бит) тоже вполне сработает.
- Восемь бит по какой-то причине является лучшим вариантом, и даже если бы история сложилась иначе, мы бы всё равно использовали именно 8-битные байты.
- Некая комбинация этих двух версий.
Я не большой специалист по компьютерной истории (мне куда больше нравится использовать компьютеры, чем читать про них), но меня всегда интересовало, есть ли какая-то весомая причина, по которой мир компьютеров сегодня выглядит именно так, или это, по большому счёту, просто историческая случайность. Так что в этой статье речь пойдёт об истории компьютеров.
Приведу пример исторической случайности: в DNS есть поле class
, которое может содержать одно из пяти значений – internet
, chaos
, hesiod
, none
и any
). Для меня это явный пример исторической случайности – не могу представить себе, чтобы мы, воссоздавая это поле сегодня, определили его таким же образом, не беспокоясь об обратной совместимости. Не уверена, что мы бы вообще стали использовать поле класса.
В этой статье не приводятся однозначные объяснения, но я задала вопрос на Mastodon, и собрала из полученных ответов несколько возможных причин 8-битного размера байта. Думаю, что ответ представляет некое сочетание этих причин.
▍ В чём отличие между байтом и словом?
Начну с того, что в этой статье будут активно обсуждаться байты и слова. В чём же отличие между ними? Вот моё понимание этого вопроса:
- Размер байта представляет минимальную единицу данных, которую можно адресовать. Например, в программе на моей машине
0x20aa87c68
может быть адресом одного байта, а значит0x20aa87c69
будет адресом следующего байта. - Размер слова является кратным размеру байта. Для меня это оставалось непонятным долгие годы, причём в Wikipedia этому даётся весьма туманное определение («слово – это естественная единица данных, используемая в конкретной архитектуре процессора»). Изначально я думала, что размер слова равен размеру регистра (64 бита на x86-64). Но, согласно разделу 4.1 («Fundamental Data Types») мануала по архитектурам Intel, в системах x86 слово имеет размер 16 бит при том, что размер регистров 64 бита. Это сбивает с толку. Какой всё-таки размер слова в системах x86 – 16 или 64 бита? Может ли это зависеть от контекста?
Ну а теперь поговорим о возможных причинах использования именно 8-битных байтов.
▍ Причина 1: чтобы любой символ английского алфавита вписывался в 1 байт
Статья на Wikipedia гласит, что 8-битный байт впервые начал использоваться в IBM System/360 в 1964 году.
Вот видео интервью с Фредом Бруксом (руководителем проекта), в котором обсуждается причина этого. Вот часть его содержания:
… 6-битные байты по факту лучше подходят для научного вычисления, а 8-битные – для коммерческого. При этом каждый вариант можно приспособить для работы в роли другого. Поэтому всё свелось к принятию ответственного решения, и я склонился к варианту с 8 битами, который предложил Джерри.
[….]
Моим самым важным техническим решением за всю карьеру в IBM был переход на использование 8-битных байтов в модели 360. Это решение также подкреплялось моей верой в то, что обработка знаков станет более значимой, чем обработка десятичных цифр.
Идея о том, что 8-битный байт больше подходит для обработки текста, вполне логична: 2^6 равно 64, значит 6 бит оказалось бы недостаточно для букв нижнего/верхнего регистра и символов.
Для перехода на использование 8-битного байта в System/360 также была реализована кодировка 8-битных символов EBCDIC.
Похоже, что следующим значительным шагом в истории 8-битного байта стал процессор Intel 8008, который создавался для использования в терминале Datapoint 2200. Терминалам необходима возможность представлять буквы, а также управляющие коды, поэтому в них есть смысл использовать 8-битные байты. В руководстве к Datapoint 2200 из музея компьютерной истории на странице 7 сказано, что эта модель поддерживала кодировки ASCII (7 бит) и EBCDIC (8 бит).
▍ Почему 6-битный байт лучше подходит для научных вычислений?
Меня заинтересовал комментарий о том, что 6-битный байт оказался бы более подходящим для научных вычислений. Вот цитата из интервью с Джином Амдалем:
Я хотел сделать его 24-х и 48-битным, а не 32-х и 64-х, поскольку тогда бы я получил более рациональную систему с плавающей запятой. Дело в том, что в системе с плавающей запятой при 32-битном слове вы оказывались ограничены всего 8 битами для знака возведения в степень, а чтобы это было практично в плане охватываемого численного диапазона, приходилось выполнять корректировку по 4 бита, а не по одному. В результате часть информации терялась быстрее, чем в случае двоичного сдвига.
Мне это рассуждение совсем непонятно – почему при использовании 32-битного слова возведение числа в степень должно быть 8-битным? Почему нельзя использовать 9 или 10 бит? Но это всё, что мне удалось найти в результате недолгого поиска.
▍ Почему в мейнфреймах использовалось 36 бит?
Это также связано с 6-битным байтом: во многих мейнфреймах использовались 36-битные слова. Почему? Кто-то указал на прекрасное объяснение в статье Wikipedia, посвящённой 36-битному вычислению:
До появления компьютеров эталоном в точных научных и инженерных вычислениях был 10-циферный электромеханический калькулятор… В этих калькуляторах для каждой цифры присутствовал ряд клавиш, и операторы обучались использовать для ввода чисел все десять пальцев, поэтому, хоть в некоторых специализированных калькуляторах и было больше рядов, десять являлось практичным ограничением.
В связи с этим в первых двоичных компьютерах, нацеленных на тот же рынок, использовались 36-битные слова. Этой длины было достаточно для представления положительных и отрицательных целых чисел с точностью до десяти десятичных цифр (35 бит оказалось бы минимумом).
Получается, что поводом для использования 36 бит стал тот факт, что log_2(20000000000)
равен 34.2.
Я предполагаю, что причина тому лежит где-то в 50-х годах – тогда компьютеры были невероятной роскошью. Поэтому, если вам требовалось, чтобы устройство поддерживало десять цифр, его нужно было спроектировать с поддержкой ровно достаточного для этого числа бит и не более.
Сегодня компьютеры стали быстрее и дешевле, поэтому, если вам по какой-то причине нужно представить десять цифр, то вы можете просто использовать 64 бита – потеря некоторого пространства памяти вряд ли станет проблемой.
Кто-то другой писал, что некоторые из этих машин с 36-битными словами позволяли выбирать размер байта – в зависимости от контекста можно было использовать 5, 6, 7 или 8-битные байты.
▍ Причина 2: для эффективной работы с десятичными значениями в двоичной кодировке
В 60-е годы существовала популярная кодировка целых чисел под названием BCD (binary-coded decimal), которая кодировала каждую цифру в 4 бита. Например, если бы вам понадобилось закодировать 1234, то в BCD это бы выглядело так:
0001 0010 0011 0100
Поэтому в целях удобства работы с закодированным в двоичную форму десятичным значением размер байта должен был быть кратным 4 битам – например, 8 бит.
▍ Почему BCD была популярна?
Такое представление целых чисел мне показалось реально странным – почему бы не использовать двоичную форму, которая позволяет намного более эффективно хранить целые числа? Ведь эффективность в первых компьютерах была крайне важна.
Лично я склоняюсь к тому, что причина заключалась в специфике дисплеев первых компьютеров, на которых содержимое байта отображалось непосредственно в состояние лампочек – вкл/выкл.
Вот картинка IBM 650 с лампочками на дисплее (CC BY-SA 3.0):
Поэтому, если мы хотим, чтобы человеку было относительно удобно прочитывать десятичное число из его двоичного представления, то такой вариант будет намного более разумным. Я думаю, что сегодня кодировка BCD уже неактуальна, потому что у нас есть мониторы, и наши компьютеры умеют автоматически конвертировать числа из двоичной формы в десятичную, отображая итоговый результат.
Мне также было интересно, не из BCD ли родился термин «nibble» (полубайт), означающий 4 бита – в контексте BCD вы много обращаетесь к полубайтам (поскольку каждая цифра занимает 4 бита), поэтому есть смысл использовать слово для «4 бит», которые люди и прозвали «nibble». Сегодня для меня этот термин уже выглядит архаичным – если я его когда-то и использовала, то только смеха ради (оно такое забавное). Причём эта теория подтверждается статьёй в Wikipedia:
Термин «полубайт» использовался для описания количества памяти, используемой в мейнфреймах IBM для хранения цифры числа в упакованном десятичном формате (BCD) .
В качестве ещё одной причины использования BCD кто-то назвал финансовые вычисления. Сегодня, если вам нужно сохранить какое-то количество долларов, то вы обычно просто используете целочисленное значение в центах и делите это значение на 100, если хотите получить его долларовую часть. Это несложно, деление выполняется быстро. Но в 70-х деление на 100 целого числа, представленного в двоичном формате, явно выполнялось очень медленно, поэтому был смысл перестроить систему представления целых чисел во избежание деления на 100.
Ладно, хватит о BCD.
▍ Причина 3: 8 – это степень 2
Многие люди указали на важность того, чтобы размер байта был равен степени 2. Я не могу выяснить, правда это или нет, и меня не удовлетворило объяснение, что «компьютеры используют двоичную систему счисления, поэтому степень двойки подойдёт лучше всего». Это утверждение выглядит весьма правдоподобным, но мне хотелось разобраться глубже. За всю историю определённо было множество машин, в которых использовались байты с размером не кратным 2. Вот несколько примеров, взятых из темы о ретрокомпьютерах со Stack Exchange:
- в мейнфреймах Cyber 180 использовались 6-битные байты;
- в серии Univac 1100 / 2200 использовались 36-битные слова;
- PDP-8 был 12-битным компьютером.
А вот пара пока не понятных мне причин, названных в качестве объяснения, почему оптимальный размер байта должен быть кратен 2:
- каждому биту в слове требуется линия шины, а количество линий должно быть кратно 2 (почему?);
- значительная часть логики электросхем предрасположена к техникам «разделяй и властвуй» (мне нужен пример для понимания этого утверждения).
А вот причины, которые мне показались более обоснованными:
- Это упрощает проектирование делителей частоты, способных измерять «отправку 8 бит по такому-то каналу» и работающих на основе деления пополам – можно установить 3 таких делителя последовательно. Грэхем Сазерленд рассказал мне об этом и создал классный симулятор делителей частоты, демонстрирующий их устройство. На том же сайте (Falstad) есть и много других примеров схем, и он отлично подходит для создания различных симуляторов.
- Если у вас есть инструкция, обнуляющая конкретный бит в байте, то при размере байта 8 (2^3) вы можете использовать всего три бита этой инструкции для указания, какой это бит. В системах x86 такой возможности нет, зато она есть у инструкций тестирования битов в Z80.
- Кто-то также сказал, что в некоторых процессорах используются сумматоры с опережением переноса, которые работают с группами по 4 бита. Недолгий поиск в Google показал, что существует большое разнообразие схем сумматоров.
- Битовые карты: память вашего компьютера организована по страницам (обычно размером 2^n). При этом компьютеру необходимо отслеживать каждую страницу на предмет того, свободна она или нет. Для этого в операционных системах используются битовые карты, в которых каждый бит соответствует странице и равен 0 или 1 в зависимости от того, свободна ли она. Если бы в компьютере использовался 9-битный байт, то для нахождения нужной страницы в битовой карте пришлось бы делить на 9. Деление на 9 медленнее деления на 8, потому что деление на степени 2 всегда является самым быстрым.
Возможно, я исказила некоторые из приведённых объяснений, так как в этой области знаний я не особо сильна.
▍ Причина 4: небольшой размер байта – это хорошо
Вы можете поинтересоваться: «Если 8-битные байты оказались лучше 4-битных, почему бы не продолжить увеличивать их размер? Можно же использовать 16-битные!»
Вот пара причин для сохранения небольшого размера байта:
- Это приведёт к пустой трате пространства – байт является минимальной адресуемой единицей, и если компьютер хранит много текста в кодировке ASCII (которой требуется всего 7 бит), то выделение для каждого символа не 8, а 12 или 16 бит приведёт к значительным потерям памяти.
- Если размер байта увеличивается, то и система процессора должна усложняться. К примеру, вам требуется по одной линии шины на бит. Так что, думаю, чем проще, тем лучше.
Моё понимание архитектуры процессоров очень шаткое, поэтому углубляться в эту тему я не стану. Хотя причина «пустой траты пространства» выглядит для меня весьма убедительной.
▍ Причина 5: совместимость
Процессор Intel 8008 (1972 год) был предшественником модели 8080 (1974 год), которая предшествовала 8086 (1976 год) – первому процессору семейства x86. Похоже, что 8080 и 8086 были очень популярны, и именно с них пошли все современные компьютеры x86.
Думаю, здесь уместен принцип «не чини того, что не сломано» – мне кажется, что 8-битные байты отлично работали, поэтому в Intel не увидели необходимости менять их размер. Сохранение 8-битного байта позволяет повторно использовать более обширную часть набора инструкций.
К тому же, в 80-х начали появляться сетевые протоколы вроде TCP, в которых использовались 8-битные байты (обычно называемые «октеты»), и если вы соберётесь реализовать сетевые протоколы, то наверняка решите использовать в них 8-битный байт.
Вот и всё!
На мой взгляд, основные причины, по которым байт состоит из 8 бит, следующие:
- Многие из первых компьютерных компаний базировались в США, где самым распространённым языком является английский.
- Разработчики хотели, чтобы компьютеры хорошо справлялись с обработкой текста.
- Небольшие размеры байтов, как правило, более эффективны.
- Минимальный размер, в который впишутся любые английские символы и знаки пунктуации, составляет 7 бит.
- Число 8 лучше 7, потому что является степенью 2.
- Когда у вас уже есть популярные 8-битные компьютеры, которые отлично работают, вы предпочтёте сохранить такую архитектуру для совместимости.
Кто-то также отметил, что на 65-й странице этой книги 1962 года, объясняющей причины, по которым в IBM решили использовать 8-битный байт, по сути, говорится то же самое:
- Полный охват в 256 символов был сочтён достаточным для подавляющего большинства возможных применений.
- В рамках этого охвата один символ представляется одним байтом, чтобы длина любой отдельной записи не зависела от совпадения символов в этой записи.
- 8-битные байты обеспечивают разумную экономию пространства хранилища.
- При работе с числами десятичную цифру можно представить всего 4 битами, и два таких 4-битных байта можно упаковать в один 8-битный. И хотя подобное упаковывание численных данных не представляет особой значимости, это распространённая практика, позволяющая увеличить скорость и эффективность хранилища. Строго говоря, 4-битные байты относятся к другому коду, но простота 4- и 8-битной схемы в сравнении, например, с комбинацией 4 и 6 бит ведёт к более простому устройству машины и логики адресации.
- Размеры байтов в 4 и 8 бит, являясь степенью 2, позволяют разработчику компьютеров задействовать мощные возможности двоичной адресации и индексации вплоть до уровня бит (см. главы 4 и 5).
В целом у меня сложилось ощущение, что 8-битный байт является естественным выбором, если вы проектируете двоичный компьютер в англоязычной стране.
Автор: Дмитрий Брайт