11,9K подписчиков

Машина MIX Д. Кнута и разрядность ЭВМ, с разных точек зрения. § 1

242 прочитали

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

Это во многом статья-рассуждение, а не просто подробное изложение фактов. Попробую объяснить все как можно более простым языком.

Все началось с интересной дискуссии, без малейшей иронии, в комментариях к статье

Точнее, с монографии Дональда Кнута, но очень быстро дискуссия распространилась и на программирование (ООП), и на общие вопросы архитектуры ЭВМ. Эта дискуссия интересна еще и тем, что отражает взгляд на одно и тоже, но с немного разных точек зрения. С разных семантических уровней.

Абстрактная машина MIX Дональда Кнута

Давайте начнем с очень краткого и поверхностного знакомства с виновницей появления данной статьи - абстрактной машиной MIX . Эту машину Кнут придумал специально для своей монографии и очень активно использовал ее в многочисленных примерах программ. Она описана в разделе 3 главы 1 первого тома "Искусства программирования для ЭВМ". Вот как он сам писал об этом ("настоящее время" это 60-е годы прошлого века)

Фрагмент книги Д. Кнута "Искусство программирования для ЭВМ", том 1
Фрагмент книги Д. Кнута "Искусство программирования для ЭВМ", том 1

Это фото страницы 159 из изданной в 1976 году издательством "Мир" книги, которая является переводом книги изданной в 1968 году издательством Addison-Wesley.

Самое для нас интересное, что Кнут не определял четко технические подробности своей абстрактной машины. Более того, он даже не стал уточнять, в какой системе счисления эта машина работает. Вот его слова

Фрагмент книги Д. Кнута "Искусство программирования для ЭВМ", том 1
Фрагмент книги Д. Кнута "Искусство программирования для ЭВМ", том 1

Если стремление Кнута абстрагироваться от привязки к реальным машинам было понятно, то здесь у нас уже возникают вопросы. Да, он объяснил, почему система счисления (аппаратная!) неважна. Но действительно ли так можно было поступать? Здесь нам нужно учитывать, что в те времена зачастую считалось, что программисты являются математиками. У нас даже должность часто называлась "математик-программист" (или "программист-математик"). Но так было не только у нас.

И Кнут не случайно в своей монографии так много внимания уделил математике. Его монография во многом математична. Причем даже без учета того, что он много внимания уделяет оценке эффективности алгоритмов. Вот как сам Кнут, который относил себя к "чистым математикам", говорил об этом

Фрагмент книги Д. Кнута "Искусство программирования для ЭВМ", том 1
Фрагмент книги Д. Кнута "Искусство программирования для ЭВМ", том 1

С точки зрения математики, чистой математики, система счисления действительно не столь важна. До повсеместного распространения современной десятичной позиционной системы счисления математики вполне успешно использовали и римскую систему счисления, и 60-ричную систему счисления. Результат, числовое значение, различался, но сами операции, собственно математика, оставались теми же.

Кнут стремился показать в своей монографии связь программирования, со всеми его тонкостями, и классической математики

Фрагмент книги Д. Кнута "Искусство программирования для ЭВМ", том 1
Фрагмент книги Д. Кнута "Искусство программирования для ЭВМ", том 1

Итак, "чистый математик" Кнут в своей монографии рассказывает об использовании ЭВМ для решения совершенно практических задач. Сегодня мы такие задачи называем прикладными. Решение прикладных задач, во всяком случае, на алгоритмическом уровне, действительно не должно зависеть от используемой машины. Да, мы не сможем просто взять программу, написанную для конкретной машины и операционной системы (ОС), и перенести ее на другую машину или другую ОС. Но мы можем алгоритм решения прикладной задачи изложить на любом (именно так, на любом!) языке программирования. А компилятор преобразует исходный текст этой программы в исполняемый код (не обязательно двоичный!).

Почему же тогда Кнут в своей монографии использует именно "машинный язык", а не один из языков высокого уровня (ЯВУ)? Я не буду приводить фрагменты из книги, так как объяснения Кнута довольно объемны, кратко перескажу своими словами. Кнут признает, что использование ЯВУ гораздо легче, но "программист находится под большим влиянием языка". А это опять дает привязку, которой он так стремится избегать.

Кроме того, сам Кнут говорит о рассматриваемых в монографии задачах, как о "программах обеспечения". Он рассматривает не законченные прикладные программы, а алгоритмы решения гораздо более узких, но при этом обобщенных, задач. Сегодня мы называем это библиотечными функциями, которые потом используются прикладными программистами в своих программах.

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

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

Фрагмент книги Д. Кнута "Искусство программирования для ЭВМ", том 1
Фрагмент книги Д. Кнута "Искусство программирования для ЭВМ", том 1

Но давайте наконец взглянем на собственно абстрактную машину MIX в том виде, как ее придумал сам Кнут

Абстрактная машина MIX в представлении Кнута
Абстрактная машина MIX в представлении Кнута

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

"Регистр А" это тот самый аккумулятор, а "регистр Х" это расширение аккумулятора. Но сам Кнут, в полном соответствии с терминологией тех лет, называет аккумулятор "сумматором", а его расширение "расширением сумматора". "Регистры Ix" это индексные регистры, которые мы сегодня рассматривать не будем. Не будем рассматривать и "регистр j", который используется для задания адреса перехода.

А вот дальше начинаются весьма специфические особенности, которые делают MIX еще более интересной! Информация в памяти MIX хранится в слов, которые состоят из 5 байт плюс знак. Казалось бы, все как в современных машинах. Да, если бы не одна маленькая, но чрезвычайно важная особенность!

Фрагмент книги Д. Кнута "Искусство программирования для ЭВМ", том 1
Фрагмент книги Д. Кнута "Искусство программирования для ЭВМ", том 1

Дональд Кнут заявляет, что разрядность байта совершенно не важна! Если вы думаете, что это "вольность переводчиков", то ошибаетесь. Вот фрагмент из оригинального издания книги, разумеется, на английском языке

Фрагмент оригинала книги Д. Кнута "Искусство программирования для ЭВМ", том 1
Фрагмент оригинала книги Д. Кнута "Искусство программирования для ЭВМ", том 1

Как видите, слова Кнута были переведены точно. При этом Кнут почти не использовал термин "бит". Он вообще ничего не говорит о разрядности! Говорится лишь диапазоне значений, которые может принимать байт:

  • Два смежных байта позволяют хранить числа от 0 до 4095 (знак в MIX хранится отдельно). Кстати, поэтому индексные регистры всего двухбайтные. В машине MIX только 4000 ячеек памяти, как и показано на иллюстрации.
  • Три смежных байта позволяют хранить число от 0 до 262143.
  • Четыре смежных байта позволяют хранить число от 0 до 16777215.
  • Пять смежных байт позволяют хранить число от 0 до 1073741823.

Разряды (биты) упоминаются лишь в отношении MIX, как двоичной машины. Но для десятичной MIX это десятичные разряды (цифры).

И это подтверждает, что Кнут рассматривает ЭВМ именно с точки зрения математика, с точки зрения прикладного программиста, даже скорее с точки зрения алгоритмов. Не смотря на выбор ассемблера MIX для своих примеров. И к этому мы еще вернемся. Это напрямую касается вопроса разрядности.

Биты и байты. Почему байт не всегда 8 бит

В той дискуссии, с которой и началась статья, мне было заявлено, что Кнут не использовал термин "байт", так как его тогда просто не существовало. И что байт это всегда, и исключительно, 8 бит. Как видно из фрагментов книги, это не соответствует истине. Кнут говорил именно о байтах, но довольно странных, если говорить с массовой сегодняшней интерпретации (семантике) этого термина. А значит, нам нужно разобраться.

Начнем с термина "БИТ", который нам встречается в классической работе Клода Шеннона "Математическая теория связи". Шеннон абстрагировался от семантики сообщений и сосредоточился на технической стороне вопроса. Поэтому задача была сведена к пересылке сообщения, которое выбирается из некоторого множества возможных сообщений. А сама система связи должна быть построена для передачи любого сообщения из множества возможных.

Для конечного множества сообщения, размер множества (количество возможных сообщений) или любая монотонная функция от этого размера может рассматриваться как мера информации, создаваемая выбором одного сообщения из этого множества. Если все сообщения равновероятны.Шеннон выбрал логарифмическую функцию, прислушавшись к Хартли. Остается открытым вопрос основания логарифма.

Здесь нам нужно вспомнить, что в те времена техника связи использовала электромеханические реле, контакты которых могли принимать только два состояния, разомкнутое и замкнутое. Поэтому выбор основания 2 для логарифма был вполне обоснованным. Сам Шеннон писал, что выбор основания логарифма является выбором единицы измерения информации. Вот так и появился термин "БИТ", как сокращение от "двоичных единиц". Причем этот термин был предложен не Шенноном, а Тьюки. Шеннон просто использовал этот термин.

Электромеханическое реле может хранить один бит информации. Равно как и электронный триггер, как вариация реле. Шеннон говорил, что возможно использовать и другие основания логарифма, в частности, десять. При этом одна десятичная единица информации (отдельный термин не предлагался) соответствует примерно 3⅓ бит. В качестве примера Шеннон приводил барабан арифмометра.

ЭВМ были не только двоичными, но и десятичными, и двоично-десятичными. Сегодня десятичные машины можно считать ушедшими в историю. Но многие современные ЭВМ умеют работать с двоично-десятичным представлением чисел. Я писал об этом в статье

Бит хорошо подходил для учета информации в канале связи, но для ЭВМ оказался слишком мелкой сущностью. Информация в ЭВМ хранилась и обрабатывалась в виде совокупности бит. И для двоичных, и для десятичных, машин определялись основные форматы данных: целые числа, числа с плавающей запятой (точкой), алфавитно-цифровые символы. Количество бит в каждом типе данных могло быть разным. Десятичные числа могли храниться в виде отдельных цифр, каждая из которых занимала 4 бита. Сегодня мы называем такой формат BCD. А совокупность 4 бит получила собственное название. Мы называем этот тетрадой, англоязычный термин nibble.

С алфавитно-цифровыми символами немного интереснее. В первых ЭВМ не требовалось представление большого количества печатных символов. В те годы набор символов вполне позволял закодировать любой символ в совокупности из 6 бит. Вот эта совокупность 6 бит, которая соответствовала одному печатаемому символу и получила название "БАЙТ". Этот термин появился где то в недрах IBM, примерно в 1956 году, применительно к машине IBM Stretch (IBM 7030).

Когда Кнут писал свой первый том, он уже знал об этом термине, причем именно как о совокупности 6 бит. Именно поэтому он указывает, что один байт может хранить число, минимум 64. При этом уже тогда шло обсуждение, что 6 бит для одного печатного символа недостаточно, что нужно использовать 7 бит. Отсюда и верхняя граница хранимого в байте числа "минимум 100", так это укладывается в 7 бит.

Кнут не хотел привязки к реально существующим ЭВМ и ЯВУ, поэтому он не мог в своей монографии опираться на такой новый, и нестабильный (6 или 7 бит, а может и больше) термин. И он сделал свой байт вариативным. Естественно, программы просто не имели права опираться на количество бит в байте, это исключало бы универсальность алгоритмов, их независимость от машины. А ведь Кнут стремился именно к этому.

Уже позже, в середине 70-х годов прошлого века, стандартом стал считаться байт состоящий из 8 бит. Именно таким большинство из нас сегодня и воспринимают байт. Что это даже сегодня не всегда так, мы еще рассмотрим позже.

При этом байт долгое время оставался не просто совокупностью 8 бит, но и оставался "кодированным представлением символа текста". Поскольку термин родился в IBM, она и стала его использовать и распространять. А с массовым выпуском IBM 360 (у нас ЕС ЭВМ), термин байт получил свою самую известную длину - 8 бит.

Распространение 8-битных микропроцессоров, де-факто, оторвало от термина "БАЙТ" семантическую нагрузку "печатный символ". Теперь байт стал просто совокупностью 8 бит, минимальной порцией обрабатываемой информации. Во всяком случае, в большинстве универсальных ЭВМ.

И при переиздании первого тома, в 1997 году, об этом было сказано в сноске на одной из страниц с описанием MIX

Фрагмент оригинала книги Д. Кнута "Искусство программирования для ЭВМ", том 1, издание 1997 года
Фрагмент оригинала книги Д. Кнута "Искусство программирования для ЭВМ", том 1, издание 1997 года

Математика не оперирует разрядностью чисел, но суровый реальный мир вносит свои коррективы

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

Математика рассматривает числа разных типов, причем основание системы счисления значения не имеет. Числа могут быть целыми, дробными, рациональными, иррациональными, комплексными, и т.д. Количество цифр в числе тоже не имеет значения. Для абстрагирования от конкретных чисел в математике вводится понятие переменной. Переменная тоже может иметь разный тип.

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

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

Давайте подумаем над тем, что в обычной жизни мы используем десятичную систему счисления. А значит, каждая цифра числа является десятичным разрядом. И слова учителя математики в школе "считать до трех знаков после запятой" как раз и уточняют разрядность! Да, не в явном виде, так как речь идет не о количестве десятичных разрядов в числе в целом, а лишь о количестве десятичных разрядов после запятой.

По сути, это уточнение не о разрядности, а лишь о точности выполнения вычислений и записи чисел. И это наглядно показывает математический подход - числа могут иметь ограниченную точность, что сказывается на точности вычислений, но иных ограничений нет.

В ЭВМ же ограничений гораздо больше. Да, каждый разряд (бит) здесь тоже является одной цифрой числа, только теперь система счисления двоичная. Десятичные ЭВМ пока не будем принимать во внимание. Но у нас есть и ограничение на общее количество цифр в числе. Мы ограничены не только в точности, но и в диапазоне возможных значений чисел.

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

Влияние ограничений машины на математику

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

Но сейчас нам нужно немного отойти от излишней детализации:

  • Диапазон представимых в ЭВМ чисел ограничен. Если результат выполнения операции выходит за границы представимого диапазона, то возникает "переполнение". При этом результат будет неверным.
  • Точность представления чисел в ЭВМ конечна. Обычно это касается лишь чисел с плавающей и фиксированной запятой, если говорить о машинных форматах. То есть, конечной будет точность и рациональных чисел, и иррациональных, и комплексных, и любых, которые в машине представлены как числа с плавающей или фиксированной запятой.
  • При выполнении операций над числами в ЭВМ возможна "потеря точности". Это можно считать следствием из предыдущего пункта, но все немного хитрее. Пусть в операции присутствуют два числа, причем оба представлены точно. Но если порядок этих чисел существенно различается, то точность представления мантиссы может быть не важна. Просто при выполнении операции будет выполнено приведение порядков, что сведет число с меньшим порядком фактически к нулю.
  • В большинстве ЭВМ непредставимо понятие "бесконечность". Как со знаком, так и без знака.
  • В некоторых ЭВМ можно столкнуться с артефактом "двух нулей". То есть, иногда 0 может иметь знак, будут существовать и +0, и -0.

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

Мы можем выделить среди всех форматов представления данных, чисел, в ЭВМ "естественные", которые представлены на аппаратном уровне и уровне машинных команд. Такие числа обрабатываются машинными командами напрямую, максимально быстро и эффективно.

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

Но дело в том, что математик не работает с машиной напрямую. Математик работает, по сути, с виртуальной машиной, которая создается компилятором языка высокого уровня (ЯВУ). Это и собственно процесс компиляции, и то, что мы называем "средой времени выполнения". Эта дополнительная прослойка, дополнительный семантический уровень, позволяют математику (математику-программисту) сосредоточиться на своих математических задачах, решать их без жесткой привязки к конкретной машине.

Проблема в том, что Кнут в своей монографии, в первых ее томах, сознательно исключил этот семантический уровень и свел математику с машиной напрямую, пусть эта машина и абстрактная. Монография так и осталась незаконченной... Возможно, Кнут и ввел бы уровень ЯВУ, который почти всегда (сегодня, по крайней мере) находится между математикой и машиной. Но нам это уже не суждено узнать. Все закончилось на четвертом томе, который вышел в виде нескольких книг.

Язык высокого уровня между математиком-программистом и машиной

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

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

Предположим, что в нашем ЯВУ необходима работа с комплексными числами, которые на уровне собственно машины не поддерживаются. Мы уже знаем, что комплексное (complex) число можно представить парой вещественных (real или float) чисел. Если наш компилятор это просто "переводчик", мы будем вынуждены или опуститься почти на машинный уровень, или воспользоваться предоставляемыми языком возможностями, что бы реализовать в программе работу с комплексными числами.

При использовании возможностей языка мы можем, например, представить комплексное число как массив вещественных чисел. Первый элемент будет соответствовать действительной части, второй мнимой. Или в виде структуры, что более наглядно. Все операции с таким представлением будут выполняться через вызов функций, тоже написанных программистом, которым такие "числа" будут передаваться как параметры. Именно так были реализованы комплексные числа в языке С, где тип complex отсутствовал.

Если же язык не поддерживает ни массивы, ни структуры (да, такое тоже может быть), то нам придется на уровне машины, скорее всего ассемблера, выделять память для хранения комплексного числа. И на уровне машины описывать функции работы с этими областями памяти. Так же поступают, когда нужна максимально быстрая работа с нестандартными типами данных.

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

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

Но можно еще больше повысить уровень языка и дать компилятору еще больше свободы. И мы можем придти к объектно-ориентированному программированию (ООП), где возможно создавать свои типы данных и описывать применимые к ним операции. В С++ это будут классы.

Но если присмотреться, то мы изменили лишь внешний облик, а не саму суть работы с комплексными числами. Ведь класс complex остается структурой данных, к которой добавлены методы-функции. Это по прежнему просто отдельная библиотека, даже если она входит в состав компилятора или стандарта языка.

Тем не менее, для математика-программиста, которого мы теперь чаще называем прикладным программистом, использование комплексных чисел будет гораздо проще при всех этих методах их реализации. Он просто воспользуется готовой библиотекой. Библиотека и поддержка компилятора сделали работу математика более математичной и менее привязанной к машине.

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

Компилятор скрывает от математика-программиста очень многое аспекты конкретной машины. Стандарт ЯВУ просто будет предусматривать некоторый набор типов чисел, с точки зрения математики, а не их "естественности" для машины. Компилятор будет отвечать не только за преобразование текста программы в машинный код, но и за реализацию работы со всем предусмотренными стандартом типами чисел (данных).

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

К сожалению, как я уже говорил, Кнут исключил из своей монографии этот семантический слой. Но, и это уже куда интереснее, ВСЮ его монографию можно считать именно таким семантическим слоем! Ведь вся монография как раз и посвящена реализации математических понятий из машинного уровня.

Прикладным программистам не важна разрядность машины

Спорное утверждение? Но это действительно так. И Кнут был прав, когда говорил, что программа не должна зависеть от размера байта. Прикладной программист сегодня не столько математик, сколько должен быть и специалистом (пусть и совсем немного) в конкретной прикладной области. И разрабатываемые им программы, на ЯВУ, должны быть как можно больше независимы от конкретики машины. И от ОС, в идеале.

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

Но что делать, если компилятор не может скрыть все, если прикладную программу, например, нужно перенести с 32-разрядной машины на 16-разрядную? Ведь диапазон представимых чисел будет гораздо уже. Да, это так. Но мы ведь только что видели, что дополнительный семантический уровень, своеобразную виртуальную машину, создать не так и сложно. И расширить этот семантический уровень, при необходимости, не так сложно.

Большая часть программы будет независима от разрядности чисел. Нам лишь нужно переопределить представление данных. Конечно, в подавляющем большинстве случаев компилятор не даст переопределить стандартные типы данных, но мы ведь можем создать свои. И это коснется лишь определения переменных и констант. Это не всегда легко и просто, но почти всегда возможно. Особенно, для современных ЯВУ и ООП.

Давайте рассмотрим простой пример. Пусть наша программа, прикладная, должна работать на 16 и 32 разрядным машинах. Мы можем учесть это еще при разработке программы. Будем использовать не стандартные типы данных, например, int и float, а "самодельные" my_int и my_float. Для языка С++ их реализация, скорее всего, будет в виде классов. Это просто элемент ООП. Для 32 разрядной машины мы просто определим, что my_int это int. А для 16 разрядной машины my_int будет состоять из двух int, но эта тонкость будет скрыта на уровне класса и методов/операторов.

Здесь надо сделать небольшое отступление. Дело в том, что реализация таких my_ классов не обязательно должна выполняться прикладными программистами. Да, это им вполне под силу! Но скорее всего реализация будет подготовлена системными программистами или "продвинутыми" прикладными программистами. И обычный прикладной программист просто воспользуется этим. Точно так же, как раньше пользовались комплексными числами, что мы уже рассматривали.

При компиляции такой прикладной программы мы просто будем выбирать одну из реализаций my_ типов. Все остальное сделает компилятор. И действительно возможно сделать так, что прикладная программа будет полностью независима от разрядности машины!

Стандарт языка программирования, компилятор, готовые библиотеки (не обязательно стандартные), действительно могут сделать ЭВМ удобной для математика или прикладного программиста. Причем почти любую ЭВМ. Мы можем абстрагироваться на прикладном уровне от особенностей машины.

Почему же так делается не всегда? Почему пользователь может столкнуться с ситуацией, когда программа не работает на его машине, но работает на другой? Причин может быть много:

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

Разработка машино-независимой программы, как и системо-независимой, все таки сложнее. Не для прикладного программиста, а из-за необходимости разработки того самого дополнительного семантического уровня абстракции.

Пользователю ЭВМ большинство технических аспектов не нужны

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

Тем не менее, обычный человек работает не столько с ОС или машиной, сколько с прикладными программами. И в привычной терминологии, которая будет разной, например, для фермера, бухгалтера, мастера верстки книг.

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

Когда важны детали

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

Далеко не всегда! Во первых, нам могут вообще не потребоваться вещественные числа. Ни в виде плавающей запятой, ни в виде фиксированной запятой. Мы можем просто выполнять вычисления в целых числах, в копейках или десятых долях копейки. То есть, если мы считаем в десятых долях, то целое число 1000 будет соответствовать 100.0 копеек, или 1.000 рублю. И мы точно также, легко и непринужденно, можем описать этот новый тип данных и операции для него. ООП здесь очень помогает.

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

То есть мы можем написать бухгалтерскую или финансовую программу хоть для 8 разрядной машины, хоть для 128 разрядной. Вся специфика машины может быть вынесена в дополнительный семантический слой, о котором мы уже много говорили.

Мне приходилось, как системному программисту, реализовывать именно такой дополнительный семантический слой для финансовой системы предприятия. Это было в молодости, фактически как подработка. Я просто написал библиотеку, которая позволяла абстрагироваться от разрядности машины. Этой библиотекой и пользовались прикладные программисты, которые хорошо знали все тонкости финансов. На предприятии были разные машины, разной разрядности.

Задача прикладная, но учитывать особенности машины приходится

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

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

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

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

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

Заключение

Пожалуй, пора прервать этот "мутный поток сознания". Да, весьма сумбурно. Но в рамках одной статьи невозможно отразить все аспекты, с разных сторон. Более того, мы только начали разбираться с разрядностью ЭВМ и ее влиянием на различные аспекты ее использования.

В следующей статье (или статьях) мы рассмотрим более глубокие, более низкоуровневые, вопросы, которые связаны с системным программированием, ОС, HAL, и даже аппаратным уровнем и архитектурой разных узлов машины.

И да, я понимаю, что для большинства обычных читателей совершенно неважно все, о чем написано в статье. Для чего тогда все это написано? Ну кому то ведь может быть интересно, что "у куколки внутри" :)

До новых встреч!