Инструменты пользователя

Инструменты сайта


igor:programmirovanie_shkolnikam

Это старая версия документа!


Содержание

Все мои статьи: Статьи Игоря Романова

Наброски книги "Программирование для школьников"

Disclaimer: я вас предупреждал, что это не книга - это наброски.
Материал для детей изрядного возраста (начиная примерно с 8 класса).

Где применяются компьютеры

Да везде.
* В быту: сейчас почти любой бытовой прибор может быть автоматизирован. Нас уже давно не удивляют автоматические стиральные и посудомоечные машины, но теперь можно обнаружить встроенный микроконтроллер хоть в чайнике. Набирают популярность системы «умный дом». Сюда же добавим электронные счетчики электроэнергии, хотя они есть не у всех (а у кого-то уже и воду считает микропроцессор!)
* В сфере досуга и развлечений: компьютерные игры, а также всевозможные самодействующие игрушки, модели, макеты; цифровая фотография, аудио- и видеозапись, цифровое рисование; устройства типа сигвеев, гироскутеров, моноколес, если конечно не считать их транспортными средствами. Сюда же добавим и собственно интернет.
* В различных учреждениях: системы контроля доступа людей в здания и помещения; видеонаблюдение, пожарная сигнализация; лифты.
* В бизнесе, торговле и экономике: системы складского учета и управления; подготовка, хранение, передача и анализ различных документов, в т. ч. отчетных (электронная бухгалтерия); анализ, прогнозирование и моделирование экономических процессов; финансовые операции «онлайн»; безналичные расчетно-платежные системы; компьютеризированные кассовые аппараты, банкоматы и платежные терминалы; системы электронной подписи и близкие к ним (системы «банк-клиент»).
* В науке и инженерной деятельности.
* В медицине сейчас используется огромное разнообразие специализированных компьютеров и компьютеризированных приборов, как собственно лечебных, так и исследовательско-диагностических.
* В промышленности: для обеспечения оптимальных и безопасных режимов работы различного оборудования; станки с числовым программным управлением (ЧПУ) и промышленные роботы; системы управления производством (АСУ).
* В книгоиздательском и книгопечатном деле.
* В связи: любой современный телефонный аппарат или радиостанция, телевизор или радиоприемник представляет собой не что иное как специализированный компьютер. К этому добавим аппаратуру телефонных станций, дата-центров, станции распределения телевизионных сигналов (как земные, так и спутниковые), системы управления движением почтовых посылок.
* На транспорте: обеспечение нужных режимов работы двигателей и иных механизмов транспортных средств; навигация; обеспечение безопасности движения транспортных средств по дорогам; автоматизация погрузочно-разгрузочных работ, составление и распространение расписаний, маршрутизация грузопотоков, продажа билетов, в том числе через интернет с оплатой банковскими картами.
* В военном деле: сбор, передача и отображение информации о расположении сил противника и своих; анализ, моделирование и планирование боевых операций; наведение артиллерийских орудий и других видов оружия; постановка радиопомех противнику и преодоление его помех («радиоэлектронная борьба»); системы опознания «свой-чужой» для кораблей и самолетов; тренажеры для обучения личного состава.
* В государственных делах: обеспечение дипломатической и другой важной переписки (шифровальные машины и шифрсистемы); экспертно-криминалистические приборы и программы.
Чтобы все это проиллюстрировать, давайте прикинем: сколько компьютеров у каждого из вас?
Сколько у вас, я не знаю, поэтому расскажу, что у меня.
* Собственно компьютер.
* Роутер: это специализированный компьютер с двумя сетевыми картами, решающий одну несложную задачу: маршрутизацию (шлюзование) данных между моей внутриквартирной локальной сетью и сетью интернет-провайдера.
* Телевизор: это тоже специализированный компьютер со встроенным экраном, а его функции включают регулирование яркости, громкости и т. п. и выбор канала по командам с пульта ДУ, а также воспроизведение фильмов, фотографий и музыки с флэшки. Это довольно старый телевизор, более новые гораздо «умнее».
* Телевизионная приставка наземного цифрового телевидения (DVB-T2), которая кстати тоже воспроизводит кино.
* Сотовый телефон: в нем имеется процессор с функциями управления режимами связи, но этот процессор «умеет» делать много такого, что к сотовой связи вроде бы не имеет отношения, например запись и воспроизведение звука, будильник, калькулятор и много чего еще.
* Банковская карта. Да, не удивляйтесь: в ней вмонтирован крошечный процессор с памятью и файловой системой, хранящей информацию о карте и ее владельце.
* RFID-ключ («ключ-таблетка»): после банковской карты, надеюсь, упоминание этого ключа в этом списке вас не удивит. Ну а если упоминать ключ, значит не забыть и замок, который этим ключом открывается.
* Стиральная машина.
* Мультиварка.
* В автомобиле лично у меня три микропроцессора: один - в системе обеспечения работы двигателя (инжектор и зажигание), второй в радиоприемнике и третий - в антибуксовочной системе (АБС). В вашем автомобиле, если он дизельный, инжектора и зажигания может и не быть, зато у вас возможно есть навигашка, а это даже не один, а целый комплекс микропроцессоров, один из которых занимается только вычислением координат, а другой отображает на экране карту и выдает голосовые подсказки типа «через 100 метров поверните направо». Вообще в современном автомобиле микропроцессор можно найти чуть ли не в каждом стеклоподъемнике.
* Фотоаппарат.
* Электронная книжка («читалка»).
Как видим, немало (а всего 20 лет назад я ни о чем таком и не мечтал!)
Теперь обратим внимание на то, чего лично у меня нет, но может быть у вас:
* Кондиционер. Если он имеет пульт ДУ, то можно не сомневаться, что сигналы пульта принимает и анализирует маленький процессор.
* Всевозможные цифровые часы, хоть наручные, хоть настенные: если они не очень старые, то без микропроцессора там точно не обойтись.
* Возможно, у кого-то в вашей семье имеется автоматический измеритель артериального давления (тонометр) или анализатор сахара в крови…
* Квадракоптер: такие «игрушки», появившиеся лет 10 назад, без микропроцессоров совершенно немыслимы.
* Игровая приставка.

Какие были компьютеры раньше и какие бывают сейчас

Когда появился первый компьютер?
На этот вопрос нет однозначного ответа. Во-первых, чем глубже интересуешься техникой, тем больше ощущаешь, что мы плохо знаем даже историю 30-40-летней давности, не говоря уж про более давние времена. Во-вторых, «первый компьютер» не возник на пустом месте - он вырос из каких-то более старых устройств. Что из них можно считать компьютером, а что нет?

До середины ХХ века

Начнем с того, что всевозможные вычислительные устройства типа счетов с нанизанными на проволоку костяшками были известны с глубокой древности, но компьютерами они не могут называться даже с очень большой натяжкой.
Леонардо да Винчи около 1500 года предложил счетную машинку с колесами. В последующие века было создано множество моделей машин, которые содержали колеса с нанесенными на них цифрами и по сути были потомками машинки Леонардо да Винчи. В XVII веке немец В. Шиккард, француз Б. Паскаль, голландец Г. Лейбниц предложили свои образцы механических калькуляторов, способных выполнять арифметические действия с многоразрядными числами, но перспектив промышленного применения эти машины не имели.
Сейчас я хочу подвести читателя к мысли, которая кажется очевидной для экономически грамотного человека, но ни в каких книгах и статьях по вычислительной технике мне не встречалась. Мысль такая: вычислительная техника не живет в каком-то своем, отдельном, замкнутом мирке - она существует в мире, населенном людьми. А людям свойственно совершать поступки, руководствуясь не хочуками-нехочуками, а коммерческим интересом. В истории человечества новая техника появлялась много раз, и каждый раз она появлялась там и тогда, где и когда совпадали два условия: у людей накапливался для этой техники значительный объем работы, и за эту работу они были готовы платить. Так в XIX веке пароходы и железные дороги появились потому, что лошади больше не справлялись с возросшим объемом торговых грузоперевозок. А в XX веке автомобили и самолеты появились потому, что уже пароходы и железные дороги не справлялись… Но мы сейчас говорим о XVII веке, когда люди ездили на лошадях, дрались на шпагах, мололи хлеб на водяных мельницах, а по морю ходили под парусами, и 90% населения голубого шарика были совершенно неграмотны. И замысловатые машинки с множеством прецизионных металлических деталей смотрелись как курьезы и могли заинтересовать только таких же чудаков, как их создатели.
Только в 1820-м году Т. де Кальмар во Франции наладил промышленный выпуск машин, получивших название арифмометров. Позже арифмометры стали строиться и в других странах. В нешей стране новейшая модель «Феликс» производилась миллионными тиражами и продавалась года примерно до 1980-го. Ближайший родственник арифмометров - механический кассовый аппарат, изобретенный в 1875 г. В нашей стране такие аппараты использовались примерно до 90-х годов ХХ века, пока не были заменены электронными. Среди арифмометров были немногочисленные «умные» образцы, но большинство было попроще: они могли выполнять только сложение и вычитание и использовались преимущественно в бухгалтерии.
В XVII веке была изобретена логарифмическая линейка - прибор, позволявший выполнять поначалу только умножение и деление, а чуть позже «научившийся» и многим другим действиям. У меня хранится логарифмическая линейка, на которой еще отец считал студенческие курсовики, и я ею даже изредка пользуюсь. Это обычная прямая линейка, а у отца была еще круглая, похожая на карманные часы - довольно редкий экземпляр даже для своего времени, но она у нас не сохранилась.
Логарифмическая линейка подкупает простотой устройства, карманной переносимостью и мгновенной готовностью к действию. Это прибор универсальный, но на этом же принципе позже были созданы специализированные приборы типа авиационной штурманской линейки (такие приборы времен Великой Отечественной войны можно увидеть в музее «Золотые ворота» во Владимире).
В 1846 г. петербургский учитель музыки Куммер изобрел счислитель, названный впоследствии по фамилии автора. Счислитель Куммера представлял собой плоскую коробку величиной со школьный пенал, внутри которой имелись подвижные планки с нанесенными на них цифрами. В какой-то мере счислитель Куммера был родственником арифмометров, отличаясь от них тем, что вместо колес в нем были прямые планки. Такие приборы выпускались до второй половины XX века.
Арифмометр, как и счетные линейки, как и более современная машина - электронный калькулятор (изобретенный в 1971 г.), может производить одиночные арифметические действия по команде человека. Чтобы устройство могло претендовать на название «компьютер», оно должно обладать способностью автоматически выполнять последовательность действий (арифметических или иных), обеспечивающую решение некоторой задачи: одной (специализированный компьютер) или многих (универсальный компьютер).
В 80-е годы XIX века американец Г. Холлерит (в старых книгах может встретиться написание фамилии Голлерит) изобрел табулятор. По большому счету это шкаф с множеством счетчиков (первоначально 40, у следующих образцов могло быть по-разному), каждый из которых может увеличивать свое значение на единицу при замыкании электрической цепи. Носителем информации для табулятора служили картонные перфокарты наподобие тех, которые раньше использовались в жаккардовых ткацких станках. Перфокарта была разделена на позиции (числом таким же, как число счетчиков в табуляторе), и в каждой позиции можно было пробить отверстие. Когда перфокарта вводилась в табулятор, каждый из его счетчиков либо сохранял прежнее значение, либо плюсовал единицу, если соответствующее отверстие пробито.
Для чего была нужна такая машина? Табулятор был впервые применен в 1890-м году для обработки результатов переписи населения США. Сведения о каждом жителе страны записывались на перфокарту путем пробивки отверстий в нужных позициях перфокарты. Например для сведений об образовании могли отвести 4 позиции: «неграмотный», «начальное», «среднее» или «высшее». По завершении переписи все перфокарты были пропущены через табулятор, и каждый из счетчиков показал количество перфокарт, в которых имелось отверстие в соответствующей позиции, т. е. можно было увидеть прямо в цифрах, сколько в стране людей неграмотных, сколько с начальным образованием и т. д. В последующие десятилетия табулятор был усовершенствован, «научился» новым действиям. Подобные устройства выпускались до середины XX века, а в 1986 году на студенческой практике мне довелось видеть немецкий трофейный табулятор постройки, кажется, 1937 года.
Именно табуляторы были первой продукцией знаменитой американской фирмы IBM. Это были громоздкие, тяжелые (почти в тонну весом) агрегаты из нескольких тысяч деталей. При работе они издавали шум, напоминающий пулеметную стрельбу.
Табулятор представляет собой просто набор счетчиков, хотя и собранных в общем корпусе, но действующих по отдельности и выполняющих одну простейшую операцию: увеличение на 1. Компьютером такая машина считаться не может.
Вам, вероятно, знакомо слово тотализатор? В представлении советского/российского человека, читавшего романы английского писателя Дика Френсиса, это слово прочно ассоциируется с преступными играми на ипподроме. С играми, ради которых людей порой убивают… Но давайте разберемся, что представляет собой тотализатор с чисто технической точки зрения. А представляет он не что иное как гибрид табулятора и арифмометра, или несколько арифмометров в одном: каждый из них, кроме одного, суммирует вводимые в него числа, а один счетчик - последний - суммирует все, что введено в прибор. То есть мы для множества чисел (ставок разных игроков на разных лошадей) подсчитываем постатейные подытоги (ставку на каждую лошадь) и общий итог. Когда все ставки приняты, владелец тотализатора сопоставляет полученные итоги и вычисляет процент выигрыша, приходящийся на каждую ставку. Машина подобного типа существовала и вне ипподрома, называлась она счетно-аналитической машиной и использовалась в бухгалтерии для решения задачи аналитического учета. В СССР первые такие машины (импортные) появились в 1925 г., а десятью годами позже в Москве был открыт Первый государственный завод счетно-аналитических машин, на котором выпускались аппараты конструкции В. Н. Рязанкина, способные не только складывать, но и вычитать.
Табуляторы и арифмометры представляют собой цифровые устройства: каждая величина («переменная»), используемая при вычислении, имеет конечный ряд допустимых значений и не может принимать значения в промежутках между соседними значениями из ряда. В отличие от них логарифмическая линейка - устройство аналоговое: хотя на ней и нанесены деления, каждая переменная может принимать непрерывное множество значений от нуля до максимума.
В 20-е-50-е годы XIX века над созданием счетных машин работал английский математик Ч. Бэббидж. Он поставил амбициозную задачу построить «аналитическую машину» (не путать с машинами Холлерита и Рязанкина), которая могла бы выполнять арифметические действия по программе. Он только еще приступил к изготовлению деталей для машины, а его помощница (и вероятно единственная единомышленница) Ада Лавлейс уже написала для этой машины первую программу…
Машина Бэббиджа явно опережала свое время. В эпоху, когда еще в помине не было никакой электротехники, механическая вычислительная машина должна была стать сложнейшим техническим изделием из всех, какие только могло вообразить человечество! На порядок сложнее любых пароходов и железных дорог! Построить такое чудо своими силами нечего было и думать. Время от времени Бэббиджу удавалось выбить какое-то финансирование из бюджета, но его вечно не хватало. Да и не очень-то охотно ему давали, зная его непостоянный характер. Он занимался разными науками, начинал и бросал, и опять начинал и опять бросал… Прожил долгую, полную событий жизнь и так и не увидел своего детища в работе. Непохоже, чтобы его это сильно угнетало. Он предвидел, что его наработки пригодятся лет через 50. В действительности же его научное наследие оказалось по-настоящему востребовано только на рубеже 30-х-40-х годов XX века: в 1938-1941 годах немец К. Цузе построил машины Z1, Z2 и Z3, используя теоретические наработки Бэббиджа и Буля (о котором чуть ниже), но на новой конструктивно-технологической базе с использованием электромагнитных реле. Если уж ставить вопрос о первом компьютере, то машины Цузе как раз и претендуют на это звание. Несколькими годами позже в США построен компьютер «Марк I», при проектировании которого также использовано наследие Бэббиджа.
Еще один персонаж, которого мы не должны забыть, - английский математик Джордж Буль. Никаких вычислительных устройств он не строил - он был чистым теоретиком. В 1847-1848 годах он опубликовал несколько научных трудов по логике, на основании которых сформировалось учение, названное в его честь: булева алгебра. В свое время булева алгебра осталась недооцененной, но через 100 лет, когда потребовались теоретические основы создания современных компьютеров, о ней вспомнили, а уж как вспомнили, так больше не забывали: современный компьютерный мир без нее немыслим, об ее пересмотре даже вопрос не ставится.
На первых русских линкорах, проектировавшихся около 1910-го года, впервые в нашей истории был внедрен принцип центрального управления стрельбой орудий главного калибра. Вообще-то приборы управления стрельбой были предложены петербургским часовым мастером Н. Гейслером еще в 90-е годы XIX века, но эти приборы только передавали данные от командира к орудиям и не содержали каких-либо счетно-решающих элементов. По итогам русско-японской войны стало ясно, что система требует усовершенствования. В Англии были закуплены счетно-решающие приборы конструкции А. Поллена, но что эти приборы собой представляли? Информация крайне скудная. Можно не сомневаться, что устройством ввода данных в этот прибор служил оптический дальномер, установленный на корабле в соответствующей надстройке. Также мне удалось узнать, что устройством вывода служили циферблаты со стрелками, расположенные в орудийных башнях. Задача наводчика сводилась к тому, чтобы повернуть орудия до совмещения со стрелками выходных данных прибора. Это ввод и вывод, а что внутри прибора? Можно только догадываться.
Представим себе валик, закрепленный в подшипниках с возможностью поворота вокруг своей оси. Если валик не трогать, то он сохраняет угол поворота, т. е. представляет собой запоминающую ячейку, имитирующую некоторую величину, участвующую в расчетах. Эту величину можно сразу же отоображать визуально, если снабдить валик стрелкой и шкалой. Если валик поворачивать с некоторой скоростью, то его угловое положение будет представлять интеграл скорости, и получаем простейший вычислительный элемент - интегратор. Представим, что на валик насажено колесико, но не круглое, а имеющее какую-то криволинейную форму, и к краю колесика прижимается рычаг. Угловое положение этого рычага однозначно связано с угловым положением вала, но связане не непосредственно, а по какой-то зависимости (возможно сложной), определяемой формой колесика - и получаем вычислительный элемент - функциональный преобразователь. Два валика, соединенные системой рычагов, представляют сумматор…
Несколькими годами раньше российский инженер Алексей Крылов изобрел дифференциальный интегратор - механическую вычислительную машину, также основанную на валиках, колесиках и рычажках и решающую дифференциальные уравнения (применялась при проектировании кораблей).
Примерно в то же самое время был построен эскадренный миноносец «Новик» - быстрейший корабль своего времени. Его главным оружием были не пушки, а торпеды, и для стрельбы ими петербургский филиал компании «Эриксон» (во времена СССР - объединение «Красная Заря») построил прибор центрального управления (ПУТС). Информации по этому прибору еще меньше. В англоязычных странах и соответственно в переводных с английского книгах эти приборы могут называться директорами торпедной стрельбы.
В 30-е-40-е годы двадцатого века строились эскадренные миноносцы проекта 7 и 7У - внуки «Новика». На них уже было три прибора управления стрельбой: для орудий главного калибра, для зенитных орудий и для торпед. На смену устаревшим ненадежным ПУТС Эриксона пришли оригинальные отечественные приборы, созданные заводом «Электроприбор» N212, а на кораблях более поздней постройки - лидерах - ставились ПУТС итальянской фирмы «Галилео». Закупка приборов передового технического уровня за рубежом, с одной стороны, не дает отечественным ученым и инженерам расслабляться, а с другой стороны, обогащает их ценным опытом. Так что в целом это нормальная практика, только ею не следует злоупотреблять. И уж совершенно недопустимо навязывать инженерам бездумное «передирание» иностранных образцов вместо создания своих, более совершенных.
Прибор управления артиллерийским зенитным огнем (ПУАЗО) можно увидеть как в Артиллерийском музее, так и в Военно-морском, но эти экспонаты дают представление только о внешнем виде прибора. А что там внутри? Развинчивать музейный экспонат нам, конечно, не позволят. Однако давайте сделаем небольшое умственное упражнение: прикинем, какой прибор сложнее - для стрельбы по кораблям или по самолетам?
Бой «корабль против корабля» идет в плоскости. Для нашего корабля нам нужны двумерные координаты X1 и Y1, скорость V1 и курс K1, для противника - аналогичный набор параметров X2, Y2, V2, K2. Если же мы ведем бой «корабль против самолета», то нам никуда не деться от использования всех тех же самых переменных, но нам потребуется еще одна координата - высота самолета, которую к тому же нужно как-то вычислить. Кроме того, поскольку скорость самолета гораздо больше скорости корабля, наш прибор должен обладать достаточным быстродействием, иначе его показания не будут успевать за реальной обстановкой. Очевидно, что ПУАЗО будет сложнее, чем прибор для стрельбы по кораблям.
Могут ли эти приборы считаться компьютерами?
Американский моряк-подводник Дж. Инрайт в своей книге «Синано: потопление японского секретного суперавианосца» рассказывает об имевшемся на его лодке приборе управления торпедной стрельбой, и этот прибор он недвусмысленно называет компьютером. Но ведь Инрайт - моряк, а не специалист по вычислительной технике. Можем ли мы согласиться с его трактовкой? На этот вопрос мы опять-таки не сможем ответить, пока не определимся, что считать компьютером, а что нет.
Чтобы прибор мог считаться компьютером, он должен обладать, как минимум, одной из двух способностей: (а) выполнять не одну какую-то математическую операцию, как например арифмометр, а расчеты с множеством действий, когда результат какого-то действия используется в последующих действиях, т. е. реализовать алгоритм (об алгоритмах поговорим чуть позже) и (б) решать задачу многократно для изменяющихся исходных данных. Прибор, о котором пишет Инрайт, обоим этим требованиям удовлетворяет…
Еще один аргумент «ЗА»: состояние устройств вывода описанных выше приборов неоднозначно зависит от входных данных на текущий момент: оно зависит также и от того, что было на входе раньше. Иными словами, эти приборы обладают памятью. Однако есть и агумент «ПРОТИВ»: алгоритм, реализованный в этих приборах, целиком определяется их конструкцией и не может быть изменен, т. е. такие приборы не программируются.
Я пишу о морских вычислительных приборах, поскольку с ними хоть как-то знаком. Свои вычислительные средства были и в авиации: штурманские приборы, бомбовые и стрелково-пушечные прицелы… Так получилось, что до середины XX века военная вычислительная техника развивалась бурно, а гражданская заметно от нее отставала. Сейчас мы подходим к такой ситуации, что от приборов, которым всего-то лет 50 или чуть больше, не осталось никаких следов. Ни одного сохранившегося экземпляра, ни чертежей, ни эксплуатационной документации… Археологам легче найти золотое украшение двухтысячелетней давности, чем железку, которой пользовались наши отцы! Авторы даже самых толковых книг по истории военных самолетов, кораблей, танков не любят писать о приборах: они сами недостаточно хорошо ориентируются в этих вопросах и того же ожидают от своих читателей.
В 1936 году В. С. Лукьянов, основываясь на опыте уже упоминавшегося нами Крылова, создал гидравлический интегратор - специализированное устройство, решающее задачу интегрирования. Интегрирование (лат. накопление, объединение) - в простейшем случае нахождение интеграла от некоторой функции (чаще всего меняющейся от времени) - эта задача изучается в старших классах школы, но этим же термином называются и более сложные (университетского уровня) задачи - решение дифференциальных уравнений. В качестве рабочей субстанции использовалась вода. Она двигалась по стеклянным трубкам, наполняла сосуды, так что весь процесс решения задачи можно было наблюдать зрительно. В течение без малого двух десятилетий Лукьянов работал над усовершенствованием своих интеграторов, каждая следующая модель была сложнее предыдущей и соответственно могла решать более сложные задачи. Использовались эти устройства чуть ли не до 1980-х годов.
Иногда считают, что Лукьянов был единственным автором вычислительных устройств, использующих воду, но это не так: в 1949 году У. Филлипс в Новой Зеландии в гаражных условиях, из подручных материалов, вплоть до обломков старых самолетов, построил водяной компьютер MONIAC. Это было едва ли не первое вычислительное устройство, построенное как учебно-демонстрационное пособие специально для моделирования экономических процессов. MONIAC неплохо себя проявил, после чего было построено несколько серийных образцов, один из которых работоспособен до сих пор. Он находится в Кембриджском университете и ежегодно демонстрируется студентам.
Вы, вероятно, слышали про немецкую шифровальную машину «Энигма»? Может быть, видели один из фильмов с таким названием? Кстати, похожие машины были и у нас, но, благодаря отсутствию установленных фактов «взлома» шифра противником, наши машины остались практически неизвестны широкой публике, а история раскрытия англичанами и американцами шифра «Энигмы» сделала этой машине большой посмертный пиар.
Можно ли считать «Энигму» компьютером? По-моему, нет. В лучшем случае она тянет на специализированный гаждет. Зато машина «Бомба», которую англичане построили для раскрытия шифра «Энигмы», к компьютерам приближается вплотную. Когда же вместо «Энигмы» немцы построили более хитрую машину «Лоренц», англичане ответили им своим «Колоссусом» (1943 г.). В создании «Бомбы» участвовал математик Алан Тьюринг. «Бомба» была специализированным устройством, но, работая над ней, Тьюринг уже задумывался о том, что делать дальше, и выдвинул принципы построения универсальных машин: (1) машина должна иметь множество одинаковых запоминающих ячеек, (2) любая математическая операция может быть выполнена с данными из любых ячеек, (3) чтобы указать машине, какие операции нужно выполнять и над какими данными, пишется программа, которая не «ввинчивается» в машину намертво, а помещается опять-таки в запоминающие ячейки, где она может быть быстро и легко заменена без ущерба для «железа». Как мы теперь видим, Тьюринг был не первый, кто додумался до этих принципов (за исключением того, что в машинах Цузе программа не хранилась в запоминающих ячейках, а читалась с перфоленты). Тьюринг был первым, кто заявил эти принципы вслух, и первым, кого услышали, в итоге получилось так, что он считается основоположников современной архитектуры компьютеров. В рамках принципов, выдвинутых Тьюрингом, были построены машины: в Англии - EDSAC (1949 г.), в США - ENIAC (1944 г.) и EDVAC (1949 г.), которые уже без всякой натяжки могут считаться настоящими компьютерами. Это история 40-х годов двадцатого века.
Первобытная эпоха в компьютерном мире продолжалась до середины XX века и характеризовалась следующим:
* Половина объема вычислений, производимых во всем мире с применением технических средств, приходилась на механические и электромеханические вычислительные устройства, выполняющие только одиночные операции под непрерывным управлением человека, а другая половина - на специализированные приборы, значительная часть которых работала по аналоговому принципу и программировалась только конструктивно, т. е. программа встраивалась в прибор намертво и ее невозможно было сменить без коренной переделки аппаратуры.
* Не существовало ни общей теории построения вычислительных машин, ни каких-либо единых стандартов их конструирования: каждый автор создавал свое детище с нуля, был вынужден вычерчивать отдельно каждую деталь. Все это сильно замедляло работу. Движущей силой прогресса были одиночные гении-изобретатели, многие из которых остались непонятыми и непризнанными. Что же касается программирования, то его по сути не было, если не считать той самой первой программы, которую составила Ада Лавлейс.
Появление программируемых цифровых компьютеров ознаменовало собой первую смену исторических эпох (не путать с поколениями ЭВМ).

50-е-60-е годы ХХ века

В годы Второй мировой войны и после нее наметился коренной пересмотр взглядов человечества на вычислительную технику. Развивалось кораблестроение, авиация, ракетная техника, энергетика (в т. ч. атомная). На повестке дня стояло освоение космоса. Стало ясно, что современные технические изделия невозможно создавать, полагаясь только на интуицию мастеров - нужны подробные и точные расчеты. Произошло именно то, о чем мы говорили в предыдущей главе: людям нужно было очень много считать, и это невозможно было делать бесплатно. Кто имел хороший компьютер, тот имел наше все, а кто компьютера не имел, был обречен оставаться лузером - не важно, просто человек, или завод, или целое государство.
В нашей стране из-за потерь, причиненных войной, работы по созданию новой техники замедлились, но чуть позже, в 50-е годы, наши инженеры вступили в «компьютерную гонку» и достигли в ней впечатляющих результатов. Нам не нужно было догонять Америку - Америка догоняла нас. Я не буду перечислять все выдающиеся советские ЭВМ. Попробуйте погуглить «Урал», «Минск», «Раздан», «Наири»… В 1958 г. была создана ЭВМ М-100, которая стала «Новиком» среди компьютеров - одной из быстрейших в мире для своего времени, и навсегда осталась таковой среди ламповых ЭВМ. В этой машине, а отнюдь не в американском «Пентиуме» 1990-х годов, впервые были воплощены такие технические решения, как конвейерное выполнение операций и кэш-память («сверхоперативная память» по терминологии того времени). В 1960-е годы было создано семейство быстродействующих электронно-счетных машин - БЭСМ. Новейшая машина этого семейства - БЭСМ-6 - в первые годы своего существования (1968-1970) также была быстрейшей в мире. БЭСМ-6 не создавалась для рекордных гонок - это была обычная серийная машина, было изготовлено свыше 300 штук. А вот другой пример: МИР - Машина Инженерных Расчетов. Это была простенькая машинка, на рекорды она на первый взгляд не претендовала, зато на ней был реализован интересный командный язык Алмир (АЛгоритмический язык для МИР), позволявший производить сложные математические и физические расчеты с минимумом трудозатрат на программирование. В этой машине были воплощены новые для того времени технические решения (некоторые из них были впоследствии забыты), позволявшие решать сложные численно-расчетные задачи практически с такой же скоростью, как на гораздо более мощных машинах. По сути, эта машина и язык Алмир стали бабушкой и дедушкой нынешнего «Матлаба». Эта машина занимала всего несколько квадратных метров в помещении, обслуживалась одним человеком и была, таким образом, едва ли не первым персональным компьютером. Это было в 60-е годы двадцатого века.
К сожалению, такое счастливое положение дел плохо уживалось с социалистической плановой экономикой. Тогдашние руководители нашего государства, будучи людьми с довольно посредственным уровнем образования, косо смотрели на любую сложную технику, в том числе на вычислительную технику и программирование. В один прекрасный день нашлась умная голова, которая придумала использовать новейшие ЭВМ для прогнозирования экономического развития страны. И какие бы ни использовали методики прогнозирования, результаты получались неутешительные. Мы-то теперь видим, что безрадостные прогнозы сбылись, мы теперь даже можем понять глубинные причины этого… Но тогдашнее правительство и ЦК КПСС во главе с Политбюро ничего такого видеть-слышать не желали, и в итоге было принято преступное (на мой взгляд) решение о прекращении собственных разработок вычислительной техники и об использовании вместо них американских образцов. Это решение не было осуществлено полностью: страна нуждалась в собственных компьютерах военного назначения. А вот «на гражданке» место оригинальных русских машин заняли СМ-4 (американская PDP), болгарский ИЗОТ (американский VAX), ЕС ЭВМ (американские IBM). Новейшим представителем последнего семейства была ЕС-1060 - мне довелось иметь с ней дело во время обучения в институте. Эта машина занимала зал размером с 3 хороших трехкомнатных квартиры и потребляла электроэнергию, как троллейбус. По этим параметрам ЕС-1060 была близка к БЭСМ-6, но значительно уступала последней по боевым возможностям. К тому же эта машина была почти постоянно неисправна и работала буквально несколько часов в год. Другие «цельнотянутые из США» машины были ничуть не лучше. Но самое плохое было то, что к этим машинам было крайне скудное программное обеспечение, а то, что имелось, было низкого качества.
Мы говорим в основном про цифровую вычислительную технику, однако давайте вспомним и аналоговую. В середине XX века она отказалась от валиков, колесиков и рычажков, перешла полностью на электрический, а затем на электронный принцип действия. В 50-е годы аналоговые и цифровые машины, варажаясь языком конного спорта, «шли ноздря в ноздрю»: цифровые машины хотя и обещали более быстрое решение сложных задач, но сами были громоздки и дороги. Даже самая «простая» цифровая машина тех времен занимала порядочных размеров комнату (скорее зал) и потребляла очень много энергии. В нашей стране было построено семейство аналоговых машин МН («модель нелинейная»): некоторые представители этого семейства были в настольном исполнении, размером как большой радиоприемник, и цена была такова, что позволяла выпускать эти машины в огромных количествах. Но ничто не могло помочь преодолеть главный недостаток аналоговых ЭВМ - их «умственную ограниченность». Аналоговая машина непригодна для решения народнохозяйственных задач, т. к. там нужно хранить множество показателей, причем хранить с абсолютной точностью. Операция сложения на аналоговой машине как-то получается, умножение ей уже дается с большим трудом, зато такая машина великолепно справляется с операциями дифференцирования и интегрирования. Поэтому аналоговые ЭВМ долго применялись для решения задач моделирования непрерывных процессов, таких как обтекание воздухом самолетного крыла или полет ракеты в околоземном пространстве. Решение таких задач на цифровых ЭМВ было поначалу сложно и дорого, главным образом из-за необходимости привлекать к работе программистов. Однако позже в области цифровых ЭВМ и их программирования имел место большой прогресс, и аналоговая техника стала терять рынок. К 1960-м годам доля аналоговых ЭВМ в общем объеме переработки информации стала уже ничтожно мала. Аналоговые машины еще строились, но во все меньших и меньших количествах. Строят их и сейчас, уже в единичных количествах, в основном в качестве лабораторных стендов для учебных заведений.
Эпоха древней компьютерной цивилизации характеризуется тем, что программируемые цифровые вычислительные машины стали выпускаться на заводах серийно и начали вытеснять технику прежней эпохи, как электромеханическую, так и электронную аналоговую. Введенный мною термин «цивилизация» наверняка вызовет возражения у читателей, особенно у тех, кто интересуется «настоящей» историей. Я настаиваю на этом термине, потому что в рассматриваемую эпоху в СССР, США и Англии, а чуть позже и в других странах, сформировалась компьютерно-программная промышленность, движущей силой развития которой были уже не энтузиасты-одиночки, работавшие в гаражно-коленочных условиях, а инженерные коллективы, вооруженные научными теориями и имеющие серьезную финансовую поддержку.
Для большинства ученых, инженеров и студентов вычислительная техника была все еще совершенно недоступна и неизвестна. Для тех счастливчиков, у кого на работе или в учебном заведении имелись какие-то ЭВМ, основным режимом работы был пакетный: задачи, решаемые в интересах множества пользователей, объединялись в пакет, который решался последовательно от начала к концу. Чтобы обеспечить работу ЭВМ без простоев, нужно было к моменту запуска иметь все надлежащие данные в готовности. Подготовку данных целесообразно было производить параллельно с подготовкой самой машины, т. е. на отдельном устройстве. Занимались этим специальные работники - операторы подготовки данных - на специальных рабочих местах, оснащенных устройствами подготовки данных. Основным носителем данных для ввода в ЭВМ была перфокарта. УПД на перфокартах (не путать с перфоратором - устройством вывода данных из ЭВМ на перфокарты) представляло собой электромеханический прибор с клавиатурой наподобие пишущей машинки. При нажатии клавиши на перфокарте пробивались определенные отверстия. При этом оператор не видел результатов нажатия. Во избежание ошибок по завершении пробивки каждой перфокарты (обычно она содержала одну строку исходного текста программы) оператор должен был ввести строку еще раз, при этом пробивка не производилась, а производилась только сверка нажатых клавиш с данными, пробитыми на перфокарте. Если обнаруживалось несовпадение, то перфокарта исправлению не подлежала и браковалась, и весь процесс приходилось повторять заново (и не факт что с успешным результатом). По окончании подготовки всех данных колоду перфокарт из лотка УПД переносили на считыватель, подключенный непосредственно к ЭВМ. Когда машина была готова, ее запускали. Результаты расчетов выводились на принтер и выкладывались в ящик, где пользователь мог их взять. С момента подачи заявки на вычисления до получения ответа могло пройти несколько дней.
Технология подготовки данных на перфокартах была весьма затратна, и в 60-е годы XX века для замены перфокарт были предложены более прогрессивные носители данных: магнитные ленты (МЛ) и магнитные диски (МД). Соответственно были созданы устройства подготовки данных на магнитных лентах (УПДМЛ) и на магнитных дисках (УПДМД). Оператор, работавший на этих устройствах, видел каждый введенный знак на экране непосредственно после ввода и мог исправлять ошибки по мере их обнаружения, что позволило сократить трудоемкость работы и уменьшить нервную нагрузку на работников.
По таким экономическим показателям, как объем, вес и стоимость носителя в пересчете на 1 байт информации, МД и МЛ были предпочтительны, тем более что они были многоразовые (в отличие от перфокарты, которая могла записываться только один раз). Было бы логично ожидать, что МЛ и МД быстро и полностью вытеснят перфокарты, но этого не произошло. С одной стороны, переоборудование ВЦ на новые носители требовало существенных капитальных затрат. С другой стороны, перфокарты представляли определенное удобство: внесение изменений в программу производилось путем изъятия, замены или вставки отдельных перфокарт, без переписывания всей программы. Аналогичная операция на МД или МЛ была сопряжена с определенными трудностями: на первоначальный текст приходилось писать патчи (англ. patch - лоскуток, заплатка, т. е. небольшой кусок текста, который нужно было наложить на определенное место изначального текста). Патчи записывались на МД или МЛ отдельно от основного текста, а операция их наложения была источником дополнительных ошибок. Технология наложения патчей применяется и сейчас, но только там, где это действительно необходимо.
Электронные цифровые вычислительные машины первого поколения (1950-х годов) строились на электронных лампах. Они (и лампы, и машины) были громоздки и нежны и потребляли очень много электроэнергии. Устанавливались они в специально оборудованных зданиях или помещениях - вычислительных центрах (ВЦ). Около 1960-го года на смену лампам пришли более компактные, надежные и энергоэкономичные транзисторы - так появились ЭВМ второго поколения. Наметилось разделение двух направлений в развитии вычислительной техники: с одной стороны, никто не отменял «больших» ЭВМ с новыми техническими возможностями, казавшимися немыслимыми всего несколько лет назад. С другой стороны, стало возможным строительство боле простых малых ЭВМ, более компактных и дешевых, которые можно было бы строить в больших количествах. Новая элементная база позволила сделать компьютер более прочным и «жизнестойким», и примерно к 70-м годам XX века наука и промышленность подошли к созданию компьютера, который можно было бы установить на корабль или самолет. В 1980-е годы многие навигационные задачи на флоте и в авиации решались с помощью компактных и надежных бортовых компьютеров. В обиход вошел термин «авионика» - электроника для авиации. Дальнейшее разделение направлений развития привело к созданию микро-ЭВМ, которые, при некоторой ограниченности интеллектуальных возможностей, могли бы работать прямо в заводских цехах, взаимодействуя с установленным там оборудованием. Так в 1960-е годы появились промышленные роботы и станки с числовым программным управлением (ЧПУ) - предки нынешних микроконтроллеров. Они стали предвестниками очередной смены исторических эпох.
Еще одна черта древней эпохи: тогдашние ЭВМ были вычислительными машинами в полном буквальном смысле, т. е. решали задачи, связанные со сложными математическими и физическими расчетами, и по всем инженерным решениям были «заточены» под эти задачи. Однако в 1960-е годы люди начали задумываться об использовании ЭВМ для решения задач в области экономики и управления производством, а еще чуть позже - и для других задач, в которых вычисления играли второстепенную роль.
Мы рассмотрели компьютеростроение древней эпохи, теперь коснемся программного искусства. Применительно к этой эпохе слово искусство мне представляется абсолютно оправданным, потому что программистов было мало, налаженной системы обучения не существовало, а для непрограммиста разработка программ представлялась чем-то совершенно запредельным.
В программировании немало вопросов, которые трудно понять и еще труднее объяснять. Но кажется я нащупал подход, который приближает нас к пониманию. Вообразим, что программа - живое существо, которое обитает в некоторой внешней среде. Чтобы организм мог жить, он, очевидно, должен быть приспособлен к той среде, в которой живет, но невозможно представить такой организм, который мог бы жить в любых условиях и мог бы приспособиться к любому их изменению.
Прикладная программа создается для решения какой-то жизненной, практической задачи. Применительно к эпохе, которую мы сейчас рассматриваем, - научной или инженерной, потому что других почти не было. Прикладная программа 1950-х годов предназначалась для конкретного компьютера и обитала в нем подобно раку-отшельнику в своей раковине: все, что надо, она вынуждена была делать своими вот этими клешнями, не надеясь на чью-либо помощь. Такой образ жизни не способствует быстрому умственному развитию: попросту говоря, прикладной программист был вынужден тратить много сил на всевозможные вспомогательные действия, прежде всего на ввод и вывод данных. Программы для микроконтроллеров - скетчи - и сейчас живут так. Но настоящие проблемы начинаются, когда старая «раковина» разваливается и «раку» приходится переселяться в новую. Это процесс непростой и небыстрый, и вообще не факт что с шансами на успех: при переносе программы со старого компьютера на новый что-то в программе наверняка потребуется переделать. Только что, в 40-е-50-е годы XX века, мы наблюдали переход от первобытности к цивилизации в компьютеростроении, а чуть позже, в 50-е-60-е годы, аналогичный процесс имел место в программировании. Люди пришли к пониманию, что вместо создания программ, с трудом приспосабливающихся к изменениям условий внешней среды, гораздо эффективнее будет создать для них искусственную среду обитания - «цивилизованную», более комфортную, чем «дикая природа». Такой средой стали операционные системы (ОС). Операционная система является принадлежностью конкретного компьютера и сама не решает никаких прикладных задач. ОС древнекомпьютерной эпохи может рассматриваться как подставка-подкладка под прикладную программу, которая позволяет нашей зверюшке жить, ни в чем не нуждаясь: если требуется какое-то типовое вспомогательное действие, то прикладному программисту не нужно программировать его самому - он программирует лишь системный вызов, все остальное операционная система сделает как надо. Теперь, если мы создаем новый, более совершенный компьютер на замену старому, нам нет необходимости переделывать все имеющееся программное обеспечение: достаточно сделать новую операционную систему, в которой наши прикладные программы будут жить с комфортом, не подозревая о том, что компьютер уже другой.

70-е-80-е годы ХХ века

С появлением транзисторов стремление проектировщиков ЭВМ создать небольшое, недорогое и энергоэкономичное изделие не только не остановилось - наоборот, оно еще усилилось. В 1960-е годы была изобретена интегральная микросхема - устройство размером с транзистор (порядка 1 см), содержащее несколько десятков транзисторов и представляющее собой целый блок, реализующий некоторую операцию по обработке данных. В наше время уже никого не удивляют микросхемы с миллионами транзисторов. Так появились ЭВМ третьего поколения, к которому относятся и вся наша нынешняя вычислительная техника. Однако новое поколение само по себе не означало смены исторических эпох: прогресс в деле миниатюризации элементов ЭВМ был и раньше, и позже. Смену исторических эпох я увязываю не с микросхемами, а с внедрением в повседневную практику диалогового режима общения пользователей с ЭВМ: теперь пользователь мог не готовить все программы и данные заранее перед запуском машины, а вводить все в уже работающую машину и через короткое время (порядка секунд) получать от нее ответ. Операция подготовки данных стала не нужна.
В 70-е годы XX века появились видеотерминалы, обеспечивавшие работу пользователя с ЭВМ в диалоговом режиме. Терминал (абонентский пункт) - оборудованное рабочее место пользователя, установленное, как правило, за пределами машинного зала, но соединенное с компьютером проводами типа телефонных или телеграфных. В принципе, абонентские пункты, которые можно было установить на значительном расстоянии от ЭВМ, были и раньше: в качестве терминалов использовали телетайпы и электрические пишущие машинки. Однако повсеместное внедрение терминалов сдерживалось двумя факторами. Во-первых, для работы ЭВМ с терминалами были нужны многопользовательские операционные системы разделения времени (ОСРВ) или системы виртуальных машин (СВМ): они имелись далеко не везде, да и качество «крякнутых» американских программ, и квалификация тогдашних сисадминов оставляли желать лучшего. Во-вторых, чтобы пользователи могли плодотворно работать в диалоговом режиме, необходима многочасовая непрерывная работа самой ЭВМ, что тоже удавалось не всегда. Так, например, в Ленинградском Электротехническом институте (ЛЭТИ) в 80-е годы XX века имелся вычислительный центр, оснащенный ЭВМ ЕС-1060, и к нему было подключено несколько терминальных классов, но они не могли по существу эксплуатироваться именно из-за постоянной неготовности ЭВМ. В результате практически до 1988 года студенческие курсовые проекты по программированию приходилось выполнять в пакетном режиме с использованием перфокарт.
Принцип обслуживания множества пользователей (абонентов) одной машиной в диалоговом режиме жив и сегодня и носит название мейнфрейм (англ. mainframe). Этим же словом называется и сама машина. Близкое по смыслу слово - сервер - компьютер (или программа), смысл существования которого сводится к выполнению команд, поступающих с других компьютеров. Различие между этими понятиями довольно тонкое. Принцип мейнфрейма привлекателен прежде всего экономически: он позволяет сосредоточить финансы и людские силы на одном компьютере и тем самым придать последнему максимально богатые технические возможности, которые становятся доступны каждому из абонентов. Абонент подключается к мейнфрейму на коммерческих условиях и решает свои задачи, независимо от того чем занимаются другие абоненты. Мейнфрейм работает по принципу разделения времени. Для него не существует понятия перегрузки: сколько бы ни было пользователей, все они обязательно будут обслужены. Но раньше других получит свои результаты тот, кто пишет быстро работающие программы. А тот, кто пишет программы тяп-ляп, вынужден будет сидеть какое-то время перед пустым экраном, и это очень мудро. Сервер, как правило, обеспечивает централизованное хранение данных или выполнение каких-то операций с целью обеспечить совместную работу множества пользователей. Механизма разделения времени на сервере может не быть, но тогда, если вдруг один или несколько пользователей зададут серверу бОльший объем работы, чем он может выполнить, то сервер может «упасть», т. е. вообще перестать реагировать на запросы пользователей.
Рабочее место, соединенное с мейнфреймом или сервером, называется клиентом. В современном компьютерном мире под этим словом чаще подразумевается не машина, а программа, образ действия которой состоит в том, чтобы не решать сложную задачу своими силами, а послать соответствующую команду на другой компьютер, и полученный от него ответ предъявить пользователю. Интернет-браузер, например, представляет собой не что иное как WEB-клиент. Вам может встретиться выражение тонкий клиент - это устройство (или опять-таки программа), полностью зависимое от мейнфрейма, не способное работать автономно. Видеотерминалы 70-х годов, как и телетайпы и пишущие машинки более ранней эпохи, - типичные тонкие клиенты.
Рабочая станция, в отличие от клиента и сервера, - компьютер, выполняющий работу по команде пользователя, сидящего непосредственно за этим самым компьютером. Очевидно, что все наши настольные компьютеры и ноутбуки представляют собой рабочие станции.
В предыдущей главе мы рассмотрели ЭВМ БЭСМ-6 как серийную машину, одну из быстрейших в мире в конце 1960-х годов. К сожалению, эта машина оказалась «лебединой песней» советского компьютерпрома. В 1970-е годы расстановка сил в мировой компьютерной гонке начала меняться: американец Сеймур Крей затеял амбициозный проект по созданию суперкомпьютера, который был назван по фамилии создателя. В течение нескольких десятилетий Крей построил несколько машин, каждая следующая была мощнее и совершеннее предыдущих. Надо, однако, оговориться, что машины Крея представляли собой «формулу 1» среди компьютеров и не претендовали на серийное производство. Насколько я понимаю, большого секрета из этих разработок никто не делал. Во всяком случае, сам факт существования этого проекта был известен в СССР. Но что могла наша страна противопоставить Крею? Все дело упиралось в идеологическую дилемму: либо мы продолжаем дальше чисто заводское, «конвейерное» производство рядовых ЭВМ, либо ищем в своей стране гения-индивидуала, который будет двигать дело вперед, используя свой ум и свои личные деловые качества. Примерно как в свое время И. В. Курчатов в атомной энергетике. Наше государство, как мы теперь знаем, пошло по первому пути.
Однако было бы неправомерно говорить, что после БЭСМ-6 в нашей стране совсем не велись разработки машин сверхвысокой производительности. Были созданы многопроцессорные вычислительные комплексы «Эльбрус» и ПС-2000 - дедушки нынешних многоядерных «Пентиумов».
Для чего нужны суперкомпьютеры? Уж точно не для студенческих курсовиков, и уж точно не для игр и офисных дел. Создание таких машин финансируется различными конторами (государственными, а в США и частными) для решения задач в их интересах. Военным супермашины нужны для расчета траекторий ракет и для «взлома» вражеских шифров, ученым-географам для прогнозирования погоды и поиска нефти и газа, ученым-биологам для анализа белков, инженерам - для расчета прочности сложных сооружений… На самом деле таких задач довольно много, я здесь упомянул лишь те, которые больше «бросаются в глаза». И давайте отметим, что суперкомпьютер, в отличие от серийных машин 1970-х годов, - машина чисто вычислительная, притом часто «заточенная» под какие-то специфические задачи.
Компьютерное средневековье наступило около 1970 года, хотя значительная часть человечества жила в древности, а то и в первобытности, чуть ли не до 1990-го года. Характерные черты этого исторического периода:
* ЭВМ появились во многих научно-исследовательских и учебных заведениях и на технологически развитых заводах, где они все чаще использовались для решения не свойственных им прежде задач, прежде всего в области экономики.
* Диалоговый режим работы пользователей без многочасового ожидания, без перфокарт, а порой и без печати данных на бумагу, стал преобладающим.
* Компьютер постепенно перестает быть чисто вычислительной машиной в том строгом смысле, как это понималось в древнюю эпоху: доля численных расчетов в общем объеме работы мирового компьютерного парка сокращается, а увеличивается объем работы с непривычной информацией, прежде всего символьной: хранение и обработка текстов, таблиц, баз данных; поиск, выборка, упорядочение… Все эти операции типичны для народно-хозяйственных задач (бухгалтерских и планово-экономических), а также для инженерных, таких как например патентные исследования.
* Мы должны отметить, с одной стороны, дальнейший рост компьютерной промышленности, выполняющей государственные заказы (в том числе военные) и, с другой стороны, подключение к общему делу частных фирм, в т. ч. мелких, производящих компьютеры и особенно программы за свой счет и поставляющих их на открытый рынок. Примером такой компании является ныне всемирно известный «Микрософт», который начинался в 1975 г. с двух работников: Б. Гейтса и П. Аллена. Разумеется, в СССР таких частных фирм быть не могло, и это предопределило последующее отставание нашей страны от США.
* Появляются достаточно надежные компьютеры, которые могут работать хоть сутками напролет без ухода и присмотра, причем в жестких условиях внешней среды. Такие компьютеры могут иметь ограниченные вычислительные возможности и при этом проворачивать значительные объемы работы, а минимизация обслуживающего персонала позволяет еще более повысить экономический эффект от их применения.
На подводной лодке С-189, которая стоит сейчас в качестве музея в Санкт-Петербурге, можно увидеть специализированную цифровую машину «Клейстер-Н», датируемую концом 1970-х годов. По сути это калькулятор, предназначенный в основном для штурманских вычислений. По внешнему виду эта машина заметно отличается от следующего поколения калькуляторов, выпускавшихся в 1980-е годы: она довольно большая, размером почти как нынешний настольный системный блок, и очень тяжелая. Похожие устройства выпускались и для гражданского использования. Чуть позже, к середине 1980-х годов, появилось следующее поколение программируемых калькуляторов, о которых чуть ниже.
В 70-е годы в нашей стране построена серия ракетных крейсеров проекта 1164 (в интернете чаще всего можно встретить «Москву» - бывшую «Славу»). На этих кораблях был установлен централизованный вычислительный комплекс, который у моряков получил название БИУС - боевая информационно-управляющая система. БИУС могла решать несколько десятков типовых задач: как по управлению кораблем, так и по наведению оружия. Круг задач, которые должны были решаться на этой машине, был четко оговорен к началу ее проектирования, поэтому создатели БИУС «заточили» свое изделие под эти задачи, трезво сознавая, что попытка приспособить машину для решения «неродных» задач может оказаться неудачной. Компьютер, проектируемый по такому принципу, называется специализированным. Для древней эпохи такие компьютеры были совершенно нехарактерны, а средневековье отмечено их появлением и развитием. С тех давних времен и до наших дней бортовые компьютеры на кораблях и самолетах - всегда специализированные, хотя в наше время они на 3/4 и более собираются из деталей от универсальных компьютеров.
На берегу, на гражданской службе более типична несколько другая ситуация: круг задач, которые предстоит решать на компьютере, не определен как исчерпывающий список. Разработчик такого компьютера вынужден «пройти между Сциллой и Харибдой»: сосредоточить максимум усилий на нужных задачах и в то же время обеспечить приспосабливаемость машины к решению новых задач, которые могут появиться в будущем. Такой компьютер называется проблемно-ориентированным. Малые ЭВМ серии СМ, которые строились в нашей стране в 70-е годы, как и их американские прототипы, относятся к проблемно-ориентированным: они могут решать много разных задач, однако есть такие задачи, которые им не под силу.
В 1978 г. фирма Intel в США выпустила микропроцессор 8086, который поначалу был встречен специалистами прохладно, потому что казался чересчур переусложненным. Но на его основе фирма IBM построила персональный компьютер PC/XT, который, что называется, «получил хороший рынок». Выпуск таких процессоров и таких компьютеров давно прекращен, но современные настольные компьютеры и ноутбуки являются потомками PC/XT и Intel 8086 в четвертом или пятом поколении.
Компьютеры IBM PC (и PC/XT - следующее поколение после PC) не были чем-то революционным. Да, у них была необычно большая для персональных машин емкость памяти, и был цветной монитор, но машины с такими особенностями были и раньше - просто до поры-до времени они были дороговаты. Но общую тенденцию к удешевлению техники никто не отменял, значит такой компьютер по такой цене рано или поздно должен был появиться. Он и появился - один из многих. Убойной фишкой был не сам компьютер, а его программное обеспечение. Основой его была операционная система MS DOS, которая представляла собой великолепный компромисс между функциональностью и сложностью. К тому же она была снабжена подробной и доходчивой документацией, и это не считая «художественных» книг, по которым можно было изучить ее принципы действия. Никогда в истории - ни до того, ни после - не было операционной системы, которая была бы так хорошо приспособлена для программирования. Прикладные программы для DOS разрабатывались множеством фирм в мире, но и любой грамотный пользователь мог подобрать подходящую для себя среду разработки и создавать программы по своим потребностям. Век DOS оказался недолог (начало разработки в 1981 г., массовое распространение - около 1988 г., начало заката - 1996 г., а последние компьютеры с DOS эксплуатировались примерно до 2002 г.) Ее боевые возможности не успевали за бурным развитием железа, но DOS успела дать мощный толчок развитию мирового программистского искусства и оказала огромное влияние на путь развития этого искусства на десятилетия вперед.
В 1980-е годы в США уже имелись персональные компьютеры, по своим вычислительным возможностям близкие к нашим СМ и ЕС (а порой и превосходящие их), и продавались они по цене легкового автомобиля, т. е. были доступны представителям среднего класса. В других странах подобная техника не производилась, на поставки такой техники из США в СССР было наложено эмбарго, а советские разработки в этой области в то время уже существенно отставали от американских. Отставание в области «железа» могло бы быть не такой большой проблемой, если бы его компенсировать опережающим развитием программирования, но этого не произошло. Профессия программиста плохо вписывалась в социалистические принципы ведения хозяйства. Эти принципы требовали привлекать к работе большое количество людей с равной, и притом очень маленькой, зарплатой. Однако серьезное программирование - дело в значительной степени индивидуальное, мастерство на грани искусства. И давайте смотреть правде в глаза: любой высококлассный программист - человек со своими тараканами в голове… В капиталистических странах, при частнособственнической организации народного хозяйства эти тараканы никому не мешают, а в СССР программист всегда был белой вороной среди других специалистов. СССР уже много лет как прекратил существование, но советский менталитет в области компьютеров и программирования отнюдь не изжит, и последствия этого мы будем ощущать на своих шкурах еще долго.
Компьютерное средневековье не началось в один день, и заканчивалось оно тоже постепенно. Если в США и других индустриально развитых странах предвестниками новой эпохи были «персоналки», то в СССР - программируемые калькуляторы - потомки «Клейстера-Н» и его сухопутных братьев, значительно уменьшившиеся в размерах и стоимости. Это довольно интересные для своего времени приборы: хотя и называют их калькуляторами, по сути это - простенькие персональные компьютеры, в умелых руках они могли проявить впечатляющие способности. И, в отличие от настоящих персоналок, цена такой машинки была раз в 100 меньше цены автомобиля: такая «игрушка» была по карману даже студенту, живущему на одну стипендию. Студентам технических специальностей при разработке курсовых проектов приходилось производить много сложных расчетов - больше, чем представителю какого-либо другого слоя общества! И программируемый калькулятор был в этом деле большим подспорьем (я бы сказал: бОльшим подспорьем, чем нынешние компьютеры для нынешней молодежи!). В отличие от больших машин, калькуляторы МК-52, МК-54, МК-62, МК-90 не были «слизнуты» с американских аналогов, а представляли собой полностью оригинальный отечественный продукт.
Программируемые калькуляторы не следует рассматривать как суррогатные персональные компьютеры: это два совершенно разных класса приборов. Калькулятор предназначен только для сложных численных расчетов, стало быть его покупатель - человек, систематически занимающийся такими расчетами. Персональный компьютер, помимо чисто вычислительных, владеет операциями по обработке других типов данных (прежде всего символьных) и чаще всего используется для решения задач с несложными расчетами (бухгалтерия) или вообще не связанных с расчетами (подготовка текстовых документов), а в наше время 90% всех компьютеров, продаваемых и покупаемых в мире, используется чисто для развлечений.
И кстати о развлечениях. Еще одно явление, характерное для позднего средневековья и предвещавшее очередную смену эпох, - это компьютерные игры. До 1970-го года ЭВМ использовались исключительно для дела, играть на компьютере было совершенно немыслимо. Однако общая тенденция к удешевлению компьютеров привела к тому, что сначала появились игровые программы, которые могли эксплуатироваться на различных компьютерах, а чуть позже - и специальные игровые компьютеры (игровые приставки, игровые консоли), ни для каких деловых задач не предназначенные. Первые игровые приставки не имели характерной для компьютеров архитектуры с процессором и памятью, но такие устройства не обеспечивали быстрой смены игры, поэтому их проектировщики пришли к мысли, что игровая приставка должна стать похожа на компьютер. От настоящего компьютера приставки отличались тем, что не имели монитора, а использовали в качестве устройства отображения информации обычный телевизор. А в качестве носителя программы - картриджи, не похожие ни на какие устройства для настоящих компьютеров, и магнитофонные кассеты, вставлявшиеся в обычный магнитофон. К 1980-му году в мире выпускалось уже несколько моделей игровых компьютеров, цена которых была в несколько раз меньше цены делового персонального компьютера. В нашей стране такая техника стала более-менее обычной только в последнем десятилетии XX века.
В эпоху, когда не было нынешних сетевых технологий, приобрести программы (как деловые, так и игровые) было непросто. Их приходилось покупать на картриджах или вводить вручную из кодовых таблиц, публиковавшихся в журналах. Существовал и такой экзотический способ: специальные радиостанции время от времени передавали программы в эфир, чтобы их можно было записать на магнитофонные кассеты. В 1970-е годы появились гибкие мегнитные диски - дискеты. Первые дискеты имели диаметр 8 дюймов (203 мм) и помещались в конверт из специальной плотной бумаги. В конверте имелось отверстие для вала, приводящего дискету во вращение, и прорезь для магнитных головок, выполнявших чтение и запись данных. Дискеты 80-х годов имели почти такое же устройство, но меньший размер: 51/4 дюйма (133 мм), а еще более поздние - 3.5 дюйма. Эти дискеты уже имели твердый пластмассовый корпус, а прорезь для головок имела сдвижную металлическую крышку для защиты от пыли. Сейчас дискеты - уже антиквариат. Их основной недостаток: малейшие посторонние частицы, попадая на рабочую поверхность дискеты, приводили к невозможности прочитать записанные данные.
Дискеты сразу же получили широкое распространение на персональных деловых компьютерах, а на игровых они применялись редко.
Лишь около 1990 года вошли в обиход ныне хорошо нам знакомые CD-диски, которые первоначально предназначались только для записи музыки, но чуть позже их приспособили и для записи компьютерных файлов, в т. ч. программ.
Программирование в средние века постепенно перестало быть искусством, стало больше похоже на обычную инженерную деятельность. Это обусловлено, во первых, появлением множества языков программирования, так что каждый, кто хотел стать программистом, мог выбрать язык на свой вкус и кошелек. С другой стороны, в США и Англии была создана система профессионального обучения программистов. В СССР такую систему тоже пытались создать, но идеологическая зашоренность мешала, так что качество подготовки программистов оставляло желать лучшего.
Выше мы говорили о новых, нетипичных для древней эпохи прикладных задачах, а сейчас остановимся на операционных системах. В этой области имел место очень большой прогресс, который, однако, имел изнаночную сторону: операционные системы стали слишком сложны, их разработка стала чрезвычайно трудоемкой, а изучение их студентами-программистами и переучивание действующих программистов на новые ОС отнимало неоправданно много сил и времени.
Рассматривая ОС средних веков, мы подходим к теме виртуализации. Само слово виртуализация очень сложно для объяснения. Выше мы уже употребили термин «системы виртуальных машин» - настала пора хоть немного разобраться, что это такое. Сформулируем так: виртуальная машина - это машина, которой нет, но функции ее выполняются. А по сути это программный инструмент в составе операционной системы, который придается в помощь каждой прикладной программе, чтобы обеспечить ей максимально комфортные условия для работы. (Мы, конечно, понимаем, что максимально комфортные условия нужны не столько программе, сколько программисту, который ее создает). В древнюю эпоху, когда программы на компьютере исполнялись одна за другой, такая проблема не стояла. Теперь люди столкнулись с задачей обеспечения «уживаемости» множества прикладных программ на одной реальной машине. Виртуальная машина работает как оболочка или контейнер, изолирующая «свою» прикладную программу от всего внешнего мира, как программного, так и железячного. Системные вызовы прикладной программы воспринимаются виртуальной машиной и при необходимости передаются операционной системе, так что прикладная программа живет в виртуальной машине не как рак-отшельник в раковине, а как морская свинка в клетке, ни в чем не нуждаясь, никому не мешая и ничего не зная о том, что происходит за стенами клетки.
Идея виртуальных машин позволяет решить проблему переносимости программ с компьютера на компьютер на новом уровне. Представим, что у нас имеется игровая программа, созданная когда-то раньше для эксплуатации на игровой приставке, а теперь мы хотим эксплуатировать ее на обычном компьютере. Теперь мы можем категорически отказаться от переделки самой программы: максимум, что нам грозит, - это написать новый «контейнер», эмулирующий (воспроизводящий) игровую приставку («целевую платформу») на компьютере («хост-платформе»). И это придется делать только если не найдем подходящий готовый. Правда, эта задача хорошо решается при условии, что обе «платформы» - и старая, и новая - снабжены хорошей документацией, а это в нашем мире, к сожалению, бывает не всегда. Так появилась идея создать СВМ - операционную систему, в которой прикладная программа обязательно помещается в «контейнер» и живет только в нем. Стало быть, все, что нужно для плодотворной работы прикладному программисту, - это справочник по тем услугам (сервисам), которые предоставляет контейнер, а программисту, пишущему контейнер, - справочники по системным вызовам обеих ОС. Но ведь контейнер обычно проще, чем большая прикладная программа или чем ОС, да и необходимость в его разработке возникает не так часто, поэтому программистов, разрабатывающих контейнеры, может быть немного, и основные людские силы можно сосредоточить на разработке прикладных программ, что мы и хотим.
Такой подход к делу обещает определенное удобство, но мы должны понимать, что любое удобство в этом мире не бесплатно: СВМ требует определенного времени на выполнение своих обязанностей, поэтому множество прикладных программ в СВМ будет выполняться медленнее (иногда значительно медленнее), чем на реальной машине без СВМ. В древние века, когда машин было мало и их быстродействие оставляло желать лучшего, такие идеи не имели шансов на признание. В средние века они оказались востребованы, а в последующие десятилетия стали практически обязательными.
Мы употребляем СВМ как нарицательный технический термин, но это слово (в такой же расшифровке) употреблялось и как собственное имя операционной системы, которая эксплуатировалась на уже знакомых нам машинах ЕС. Как и сами ЕС, и почти все программное обеспечение для них, СВМ не была оригинальной советской разработкой - была скопирована с американской VM.

Последнее десятилетие XX века и начало XXI века

В 1989 году эмбарго на поставку персональных компьютеров в СССР было отменено, и компьютеры IBM PC/AT (следующее поколение после PC/XT) стали знакомы многим в нашей стране. Этот год я считаю годом очередного перелома эпох: закончилось средневековье, наступило новое время. Оно характеризуется массовым внедрением в нашу жизнь персональных компьютеров. Такой компьютер занимал немного места, умеренно потреблял электроэнергию и, главное, мог работать сутки напролет без всякого ремонта и наладки. За сутки на таком компьютере можно было поднять такой объем работы, над которым весь вычислительный центр ЛЭТИ трудился бы год! И таким компьютером можно было оснастить рабочее место практически каждого ученого или инженера. Иными словами, доступ человека к компьютеру перестал быть ресурсом. Правда, покупка такого компьютера для домашнего пользования стала возможна лишь через несколько лет, году примерно в 1993-м.
Уменьшение стоимости компьютеров и расширение их промышленного выпуска в разных странах (а не только в США, как раньше) привело к пересмотру взглядов на компьютерные игры. В один прекрасный момент люди перестали считать крамолой мысль о том, что игровой компьютер может быть технически совершеннее и дороже, чем деловой. Более того: фирмы, традиционно выпускавшие деловые компьютеры (хотя бы та же IBM - International Business Machines - «международные машины для дела»), понемногу стали переориентироваться на игровые (или скажем более обобщенно: развлекательные) машины. Это касается как «железа», так и программного обеспечения. В нынешних магазинах мы чисто делового компьютера просто не найдем. Изучая технические особенности самых дорогих компьютеров, имеющихся на рынке, мы приходим к выводу, что это типично развлекательные компьютеры, что, в общем-то, недвусмысленно написано на их мо… пардон, на лицевых панелях.
Бурный рост производства персональных компьютеров частными фирмами и перенос значительной части этого производства из США в страны юго-восточной Азии привел к постепенному самоустранению американского государства от компьютерных дел. Вслед за США вынуждены были пойти и другие, и постсоветская Россия не могла оставаться исключением. Однако в России так и не были созданы (и даже до настоящего времени) возможности для частного бизнеса, в результате наша компьютерно-программная промышленность, и без того уже изрядно пострадавшая от некомпетентных решений высшего государственного руководства, не выдержала конкуренции с американскими «друзьями» и была окончательно добита.
Очередная смена исторических эпох произошла не одномоментно, а растянулась на период с 1995 по 2005 годы, зато она шла синхронно практически во всех странах мира. Новейшая эпоха в компьютерном мире характеризуется не одним, а множеством факторов:
* Цена компьютеров снизилась до величины значительно меньше стоимости автомобиля. Современный школьник может носить в кармане смартфон, вычислительные возможности которого превосходят весь мировой парк компьютеров 1960-х годов, и собирать собственные компьютерные системы из запчастей, цена которых сравнима уже с ценой не автомобиля, а школьного завтрака. А в Англии уже ставится вопрос о том, чтобы простенькие микроконтроллеры раздавать школьникам бесплатно - лишь бы учились программированию.
* Компьютеры стали переносными: в конце XX века уже никого не удивляли ноутбуки, а в XXI веке появились еще более легкие планшетные компьютеры, способные много часов работать от аккумуляторов без подключения к электросети.
* Появились новые виды компьютерных услуг: интернет (в т. ч. мобильный) и GPS.
* Было изобретено множество специализированных компьютеров и гаджетов, которые в начале 1990-х годов даже не были предметом мечты. Примеры: электронный музыкальный плеер и автомобильный видеорегистратор.
* Компьютер освоил несвойственные ему до недавнего времени профессии: фотографию, видео, звукозапись и черчение.
* Если в предыдущие исторические эпохи развивающаяся компьютерная промышленность только способствовала появлению новых предприятий и целых отраслей промышленности, то теперь компьютер, образно говоря, вышел убивать. В большинстве стран мира прекратил работу телеграф, исчезли сельские и районные телефонные компании, и на очереди - телефонные сети в небольших городах. Под вопросом существование почты. Прекращено производство электрофонов, магнитофонов, видеомагнитофонов, магнитных лент и виниловых пластинок. Практически свернуто производство чертежной бумаги, чертежных принадлежностей и инструментов, светокопировальной бумаги и аппаратуры для светового копирования чертежей, фотокинопленок и реактивов для их проявления. Уходит в прошлое профессия штурмана, как на море, так и в авиации. И это далеко не полный список «унесенных ветром».

Современные компьютеры и подобные им устройства

«Настоящий» компьютер характеризуется тем, что «общается» с человеком, получает от него команды и исходные данные для исполнения этих команд, а результаты выдает опять-таки человеку. Соответственно компьютер имеет устройства для «общения» с человеком - HID - Human Interface Devices - буквально: устройства сопряжения с человеком. Это экран (монитор), клавиатура и различные манипуляторы типа мыши или джойстика.
«Большой компьютер» - выражение, которое встречается в речи специалистов-компьютерщиков, а соответствующий строгий технический термин - компьютер общего назначения - КОН. Слово «большой» не следует воспринимать буквально. Оно не означает размеры, а происходит из пословицы: «большому кораблю - большое плавание». Так называют компьютер, предназначенный для решения широкого круга задач, в том числе сложных. В качестве «больших» используются достаточно сложные и мощные компьютеры, укомплектованные соответствующими процессорами и периферийными устройствами, оперативной памятью большого объема, а также внешней памятью для долговременного хранения множества программ. Соответственно цена такой машины может кусаться более или менее сильно. Именно к классу «больших» относятся наши настольные компьютеры, ноутбуки и планшеты, современные смартфоны, а также серверы, используемые профессионалами на предприятиях и в дата-центрах, и маленькие на вид одноплатные компьютеры типа Raspberry Pi, Orange Pi, Odroid и многие другие.
Микроконтроллер (МК) похож на компьютер, но отличается тем, что соединен напрямую с какими-либо техническими устройствами и управляет ими без участия человека. Устройства ввода применительно к микроконтроллерам называются датчиками, устройства вывода - исполнительными механизмами. Микроконтроллер может вообще не иметь никаких органов управления для взаимодействия с человеком.
Ближайшие родственники микроконтроллеров - промышленные роботы и регуляторы, станки с ЧПУ, а также боевые, корабельные и авиационно-космические счетно-решающие приборы. С точки зрения программиста между ними вообще никакой разницы нет. Различие здесь конструктивное. Такие приборы обычно имеют массивный, прочный корпус (пластмассовый или металлический), защищающий хрупкую «начинку» от влаги, пыли и других нежелательных воздействий, а на входах и выходах - винтовые зажимы для присоединения достаточно толстых проводов и электронную «обвязку», обеспечивающую прямое подключение к соответствующим датчикам и механизмам, защищающую микроконтроллер от превышения допустимого тока и напряжения. Неудивительно, что качественный промышленный контроллер может стоить дороже домашне-офисного КОН, хотя значительно уступает ему по своим «умственным способностям».
Программное обеспечение промышленных контроллеров обычно включает некоторые типовые задачи, среди которых N1 - пропорционально-интегрально-дифференциальное регулирование. Это наука институтского уровня, поэтому мы в этой книге рассматривать эту задачу не будем. В двух словах: принцип пропорционально-интегрально-дифференциального регулирования позволяет быстро и точно управлять трудноуправляемыми в обычных условиях техническими устройствами, такими как корабельная артиллерийская башня или космическая ракета, хотя подобные объекты могут встретиться практически в любой области техники.
Более подробно о программном обеспечении, о различии программ для компьютеров и микроконтроллеров поговорим позже.
Граница между компьютерами и микроконтроллерами не очень четкая: некоторые микроконтроллеры имеют клавиатуры и экраны, а у некоторых компьютеров соответствующие устройства могут быть сильно упрощенными… Некоторые специалисты выделяют в отдельный класс специализированные компьютеры, и если принять такую трактовку, то место этому классу как раз между компьютерами и микроконтроллерами.
Специализированные устройства («гаджеты») содержат в себе компьютер (скорее микроконтроллер) и какие-то периферийные устройства «в одном флаконе» и предназначены для решения каких-то специфических задач. Примеры: телефонные аппараты, радиостанции, аудио- и видеоплееры, электронные книги («читалки»), фотоаппараты, видеокамеры, автоматизированная бытовая техника… Граница между гаджетами и специализированными компьютерами опять-таки размыта. К какой из этих групп отнести, например, морской карт-плоттер?
Программируемые логические контроллеры (ПЛК) - еще один класс приборов, которые вам могут встретиться «вживую» или в книгах и которые мы не должны забыть, говоря о компьютерах и микроконтроллерах. В промышленной автоматике ПЛК работают «плечом к плечу» с компьютерами, но сами они компьютерами не являются, поскольку не обладают памятью: состояние их выходов определяется состоянием входов в данный момент. Соответственно ПЛК не выполняют расчетов по сложным алгоритмам, в которых результат операции используется для последующих операций. К сожалению, здесь имеется путаница в терминологии: часто словом ПЛК называют промышленные регуляторы.
Программируемые логические интегральные схемы (ПЛИС) - еще одна группа устройств, которые тоже иногда неправильно называют ПЛК. ПЛИС похожа ПЛК и в то же время на микроконтроллер, и может считаться чем-то средним между ними, но еще больше она похожа на набор запчастей для самостоятельной сборки микроконтроллера. Только собирать его приходится не болтами и пайкой, а логически. Процесс изготовления микроконтроллера на основе ПЛИС аналогичен программированию: на некотором языке составляется описание устройства, затем это описание компилируется на компьютере и «заливается» в ПЛИС. Чаще всего используется язык Verilog.
Контроллеры на основе ПЛИС дороже обычных микроконтроллеров, для большинства обычных программистов это полнейшая terra incognita, зато ПЛИС могут решать некоторые специфические задачи намного быстрее обычных микроконтроллеров и поэтому имеют свою пусть небольшую, но устойчивую область применения. Одноплатный промышленный контроллер на ПЛИС по внешнему виду трудноотличим от обычного одноплатного МК.
Отдельную группу компьютероподобных устройств представляют калькуляторы. Настоящий калькулятор характеризуется тем, что может выполнять только одиночные действия. Но как быть с программируемыми калькуляторами? Программируемый калькулятор - по сути стопроцентный компьютер, так что давайте просто считать это название досадной неточностью в терминологии.

Информация и ее представление в компьютере

Что такое информация? И что такое данные?
Никогда не изадавайте таких вопросов! Потому что спросили как-то у одного математика, что такое число, - он думал-думал, а потом выпил две бутылки водки и повесился.
Все, что мы можем сказать: информация и данные - это то, с чем работают компьютер и программист. Компьютер - станок для обработки данных. Программист - наладчик этого станка. Как-то примерно так.
Теперь рассмотрим более серьезный вопрос: единицы измерения информации.

Единицы измерения информации

Минимальная единица - бит (англ. bit). 1 бит - это количество информации, которое мы рассчитываем получить в ответ на вопрос, если ответ может быть «да» или «нет». Для полной строгости следовало бы добавить: при условии, что эти «да» и «нет» равновероятны, но в нашей повседневной компьютерной жизни этим обычно пренебрегают. Бит - это элементарная ячейка компьютерной памяти, которая в каждый момент имеет одно из двух возможных значений. Как называть эти значения? - Да как угодно. «Да» или «нет», «истина» или «ложь», 1 или 0.
Как видим, бит - очень маленькая единица. Если ее не хватает, приходится оперировать более крупными.
Первая более крупная единица информации - байт - 8 бит. Это ячейка компьютерной памяти, способная принимать 256 различных значений. Как трактовать эти значения? - Можно по-разному. Вот самые типичные:
* Натуральные числа от 0 до 255;
* Целые числа от -128 до 127;
* Буквы, цифры и разные другие символы, которые встречаются в книгах и деловых документах.
Если с первыми двумя случаями все ясно, то на последнем чуть позже остановимся более подробно.
Что такое слово? - Такой вопрос тоже лучше не задавать. Что такое компьютерное слово? - На этот вопрос ответить можно, хотя и неоднозначно. Машинное слово - это такое количество байт или бит (разрядов), которое данная машина может обработать одной командой: 16, 32 или 64 бита. Если же мы не говорим «машинное», то слово (WORD) - это 2 байта или 16 бит, тогда 32 бита (4 байта) - это двойное слово - double word (DWORD), а 64 бита (8 байт) - четверное слово - four word (FWORD) или quadra word (QWORD). Это современное представление. Если вам в руки попадет книжка 1970-х-1980-х годов про ЭВМ ЕС, то там вы можете увидеть полуслово (16 бит) и слово (32 бита), но это все в прошлом.
Наверно, мы могли бы придумать единицы информации в 10 или 100 байт, но в реальном компьютерном мире такие единицы не имеют употребления.
Ячейка памяти в одно слово может, очевидно, трактоваться как натуральное число в диапазоне от 0 до 65535, или как целое число в диапазоне от -32768 до 32767. Какие числа могут быть представлены двойным или четверным словом, сосчитайте сами.
Сейчас я хочу обратить ваше внимание на то, что ТРАКТОВКА компьютерных данных - вопрос чисто человеческий, сам компьютер ничего никак не трактует - он просто выполняет операции над данными строго по командам, которые мы для него написали. Соответственно забота о том, как правильно написать команды, лежит полностью на программисте. (Точно так же автомобиль сам не знает, куда нужно ехать, - куда рулишь, туда он и едет). И еще: когда мы отводим некоторую ячейку компьютерной памяти для хранения некоторой величины (переменной), мы всегда должны четко представлять размер этой ячейки и столь же четко доводить наше представление до компьютера.
Понятия слова, двойного слова и т. д. ассоциируются с ячейками памяти. Но для решения какой-либо задачи обычно требуется не одна ячейка, а много. Иногда - очень много. Чтобы оценить емкость памяти реального компьютера, нужны кратные единицы: килобайт (Кбайт), мегабайт (Мбайт) и т. д. В отличие от килограмма или километра, килобайт содержит не ровно 1000, а 1024 байта. Сколько в мегабайте - сосчитайте сами.
В 70-е-80-е годы при описании существующих тогда машин емкость памяти часто указывали в машинных словах, что затрудняло сравнение: ведь машинное слово в разных машинах имеет разную длину. Поэтому сейчас емкость любых запоминающих устройств указывают не в машинных словах, а только в байтах.

Представление печатных знаков в компьютере

Есть 10 цифр, 26 общеупотребительных латинских букв (которые бывают заглавные и строчные) и знаки препинания: точка, вопросительный знак и др. - всего порядка сотни знаков, без которых нам не обойтись, независимо от того, в какой стране мы живем. У нас же, россиян, есть еще 33 буквы, которые опять-таки бывают заглавные и строчные. Если сложить все вместе, то одного байта будет достаточно. Однако если мы захотим одной ячейкой памяти представить все буквы всех языков мира, то 256 значений будет недостаточно - значит, нужна ячейка с бОльшим количеством бит. Это будет необходимо и для вычислений, если мы хотим работать с большими числами или представлять их с большой точностью.

Как числа представляются в компьютере и как они записываются в программах

Выше мы рассмотрели байт, слово и двойное слово как запоминающие ячейки, построенные из нескольких элементарных запоминающих ячеек по 1 биту каждая. Размер ячейки в битах в разных книгах может называться длиной, объемом или емкостью - единства терминологии здесь, к сожалению, нет. В зависимости от длины ячейка может принимать то или иное множество состояний, и каждое состояние может трактоваться как число. Если каждый бит изобразить цифрой 0 или 1, то получается, что любое число в компьютере может быть представлено последовательностью двоичных цифр - нулей и единиц. Таким образом мы приходим к пониманию двоичной системы счисления. Эта система для нас непривычна ровно постольку, поскольку мы все с детства привыкли к десятичной системе счисления. Однако десятичная система была не везде и не всегда. В древности в Европе была в ходу двенадцатиричная система. Затем она была вытеснена десятичной системой, которую привезли из Индии арабы. Привезли вместе с привычными нам десятичными цифрами 0123456789, которые часто называют арабскими, хотя на самом деле они индийские. Произошло это очень давно, задолго до начала развития компьютерной техники, так что двенадцатиричная система оказалась совершенно забыта и заброшена, и все, что от нее осталось, - это слово «дюжина». Неудивительно, что для современного человека переход на другую систему счисления - психологический барьер… Но для нас, программистов 21-го века, этот барьер уже не имеет сколько-нибудь существенного значения. Вот для инженеров-электронщиков, проектирующих компьютерное «железо» - да… Я же сейчас нарушу общепринятый в компьютерной литературе подход и втравливать читателя в дебри двоичной арифметики не буду совсем. Лишь немного коснусь двоичной записи чисел. Поскольку каждая цифра в двоичной системе не может быть больше 1, то число 2 записывается как 10, 4 - как 100… У одного моего друга - профессионального компьютерщика - номер на двери квартиры записан как 11010, а вам я предлагаю самостоятельно вычислить, какие номера написаны на соседних квартирах, с учетом того что их хозяева - не профессиональные компьютерщики.
Недостаток двоичной системы в том, что запись чисел получается довольно длинной и поэтому трудно читаемой. Например, такое небольшое число как тысяча записывается вот так: 1111101000, а попробуйте записать миллион или миллиард. Поэтому были предложены системы записи чисел: восьмиричная и шестнадцатиричная. Это не самостоятельные системы счисления, а именно системы записи чисел, за которыми, в конечном счете, стоит двоичная система счисления. Весь ряд бит, изображающий число, делится на группы по 3 или 4 бита, и каждая группа изображается цифрой: восьмиричной или шестнадцатиричной соответственно. В качестве восьмиричных используют арабские (индийские!) цифры от 0 до 7. Соответственно тысяча в восьмиричной системе запишется как 1750. Для представления шестнадцатиричных цифр используют опять-таки индийские цифры 0…9, а недостающие цифры заменяют латинскими буквами A…F, так что тысяча запишется как 3E8.
В программировании приходится использовать разные системы записи чисел. Восьмиричные числа вам могут встретиться в старых книгах про СМ ЭВМ, если такие книги вдруг попадут вам в руки. Сейчас эта система не используется по очевидной причине: восьмиричные числа по внешнему виду не отличаются от десятичных, и это может стать причиной путаницы, а путаница для нас - враг N1! Если нужно записать число в шестнадцатиричной системе, то его либо предваряют символами 0x, либо после числа ставят букву h (заметим, что ни x, ни h не являются шестнадцатиричными цифрами!). Если же ни того ни другого нет, то число считается десятичным.
Какую систему записи чисел следует использовать программисту?
Еще лет 40 назад приходилось использовать ту систему, которая предписывалась эксплуатационной документацией на конкретную машину. Например для СМ ЭВМ - восьмиричную, а для ЕС ЭВМ - шестнадцатиричную. Рассмотрим пример, хотя и не из реальной жизни, но иллюстрирующий применение разных систем счисления и записи чисел. Допустим, имеем некую абстрактную машину, на которой мы хотим запрограммировать системный вызов: вывести на принтер 50 знаков равенства подряд, чтобы обозначить границу страниц в выходном документе. Программист 60-х годов, работающий в шестнадцатиричной системе, записал бы это примерно так:

mov  r0,31  ;номер системного вызова "вывод N знаков на устройство"
mov  r1,6С  ;устройство, в которое пишем: 108 - номер принтера
mov  r2,3D  ;код знака равенства
mov  r3,32  ;количество знаков для вывода - 50
int  21     ;собственно системный вызов

Но это все в прошлом, современные системы программирования допускают использование таких систем записи чисел, которые наиболее удобны для каждой конкретной операции. Есть несколько разумных рекомендаций.
* Все количественные значения - в десятичной системе.
* Если нужно указать печатный знак, то указываем сам этот знак, заключая его в кавычки (одинарные или двойные - уточнить в документации на машину или систему программирования).
* Неколичественные значения, которые мы не выбираем произвольно, а берем из каких-то справочных пособий, пишем строго так, как они записаны в соответствующих источниках. Например номера системных вызовов DOS/Windows/Linux - в шестнадцатиричной системе, однако еще более грамотно будет не писать коды, а присвоить им символические имена.
* В двоичной системе записывать только те значения, в которых важен каждый бит, например данные для записи в управляющие регистры устройств ввода-вывода. С учетом этого всего программа из предыдущего примера может быть записана так:

mov  r0,0x31    ;номер системного вызова "вывод N знаков на устройство"
mov  r1,PRINTER ;устройство, в которое пишем
mov  r2,'='     ;знак, который пишем в устройство
mov  r3,50      ;количество знаков для вывода
int  SYSCALL

Программа стала более наглядной, не правда ли? Сразу оговоримся, что PRINTER и SYSCALL - это символические имена, за которыми стоят, в конечном счете, некоторые значения (в первом варианте программы мы их уже писали). И сразу - правило N1 для программиста на все времена: если мы используем какое-то символическое имя, то необходимо убедиться, что это имя определено, т. е. где-то в программе имеется предложение, присваивающее этому символическому имени значение. Как правило, определять имя следует прежде (выше по тексту), чем его использовать.
Мы рассмотрели представление натуральных чисел. Часто бывают нужны целые числа: положительные и отрицательные. Если мы хотим представлять числа одним байтом, то придется пожертвовать диапазоном представляемых чисел: «старший» бит в байте отведем под знак числа. Нулевое значение этого бита будем трактовать как положительное число, тогда 00000000 остается нулем, а значения с 00000001 по 01111111 будем трактовать как числа с 1 по 127 - точно так же, как натуральные. Отрицательные числа имеют единицу в «старшем» бите: значение 11111111 трактуется как -1, а 10000000 как -128. Такое представление чисел называется дополнительным кодом. Оно несколько трудновато для человека, но очень удобно для машины (и соответственно для людей, проектирующих машину), т. к. операции сложения и вычитания производятся совершенно одинаково как для натуральных чисел, так и для целых в дополнительном коде.
А как быть, если нужны дробные числа?
Вообще-то больше половины (а может быть 3/4 или даже больше) всех компьютеров, программ и программистов дробными числами не пользуются и живут при этом припеваючи (и даже прибыль получаючи!). Тем не менее…
Можно, например, трактовать значения байта как дробные числа в диапазоне от 0 (00000000) до 0.99619375 (11111111). Если же нужны числа с целой и дробной частью, то одним байтом здесь не обойдется. Можно, допустим, представить число как двойное слово: «старшее» слово - целая часть, «младшее» - дробная часть. Такое представление чисел называется представление с фиксированной границей целой и дробной частей или представление с фиксированной точкой (запятой). Точка или запятая? - здесь, к сожалению, единства не будет, поскольку в русской литературе и в русской школе принято целую часть от дробной отделять запятой, а в англо-американской - точкой. Эта ситуация всем уже порядком надоела, поэтому программисты в разговоре между собой говорят просто «фиксированное представление чисел». Такое представление имеет ограниченное применение в области бухгалтерско-экономической (поскольку денежные суммы, как правило, содержат некоторое количество целых рублей, а суммы мельче копейки никто не считает) и в программировании обработки деталей на станках с ЧПУ. В физико-математических расчетах обычно применяется представление чисел с плавающей запятой (точкой). Слово «плавающая» здесь - антоним слова «фиксированая». Под такое число отводится ячейка не менее 32 бит, из которых большая часть (примерно три четверти от общего количества бит) отводятся под мантиссу, а остальные - под порядок. Мантисса трактуется как дробное число со знаком, ее абсолютное значение (модуль) всегда находится в диапазоне от 0.5 до 1, и это значение умножается на 2 в такой степени, каков порядок (он трактуется как целое число со знаком). Получается очень большой диапазон представляемых чисел и очень высокая точность. Например, если расстояния измерять в километрах, то максимальное значение будет 2127 км - это расстояние до звезд, причем даже не самых близких к нам, а минимальное (2-128 км) - гораздо меньше размера атома. Расстояние от Земли до Солнца можно представить с погрешностью около 1 км. Несмотря на это, в мощных процессорах предусмотрена возможность вычислений с числами двойной длины (64 бита и даже 80 бит). В повседневной жизни не каждому программисту это может хотя бы раз понадобиться, но в учебнике высшей математики такие задачи рассматриваются. Процессоры среднего класса (ARM Cortex) обходятся 32-битными числами с плавающей точкой, что соответствует их разрядности.
В математике иногда приходится оперировать иррациональными числами. Для представления такого числа необходим бесконечный ряд цифр, что в компьютерной технике совершенно нереально. Поэтому в обычном программировании приходится довольствоваться приближенным представлением чисел, которое мы только что обсудили.

Как данные размещаются в памяти компьютера

В предыдущей главе мы говорили о числах, теперь будем использовать более правильный термин: переменная. Этим термином в программировании называется любая величина, которая используется при решении задачи - совсем не обязательно число.
Если раньше мы использовали абстрактное выражение «запоминающая ячейка», то настало время кое-что конкретизировать. Оперативное запоминающее устройство, или оперативная память, предназначена для хранения данных, которые в данный момент участвуют в решении задачи на компьютере. Современная оперативная память всегда имеет байтовую структуру: она организована как ряд ячеек размером в 1 байт каждая, и все ячейки пронумерованы последовательно от нуля до максимума. В компьютерной технике и в программировании номера ячеек принято называть адресами. Если вы когда-нибудь будете читать английские книги в оригинале, то там под словом address может пониматься как адрес, так и сама ячейка.
Как мы уже видели в предыдущей главе, каждая переменная может требовать для размещения не один байт, а более. В этом случае для ее хранения отводится участок или область памяти из нескольких последовательно расположенный байт, причем адрес того байта, который ближе к началу, отождествляется с адресом всей переменной. Теперь для того, чтобы присвоить переменной какое-то значение, даем команду «поместить это значение по указанному адресу» («записать в память»), а чтобы использовать это значение в последующих операциях - команду «прочитать из памяти по указанному адресу». Иными словами, роль и место переменной в расчетах ассоциируется с ее адресом.
Современный программист при написании программы никогда не указывает адрес ячейки: такая программа получилась бы очень неудобной для чтения. Поэтому в тексте программы вместо адреса указывается символическое имя переменной, или просто имя. Имя может содержать одну или более латинских букв, причем на последующих местах, кроме букв, можно также использовать цифры и знак подчеркивания. В некоторых системах программирования допускаются еще какие-то символы - а вот этого я вам делать не советую. Можно ли использовать русские буквы? - Не следует, т. к. ваша программа окажется непригодна для нерусских компьютеров. Латинские буквы рекомендуется использовать заглавные. Возможность использования строчных букв следует уточнить по документации к вашей системе программирования, при этом также надо уточнить, будет ли строчная латинская буква считаться совпадающей с соответствующей заглавной или это разные буквы. В книгах по некоторым системам программирования можно увидеть советы типа «одно и то же имя можно написать как RESET, Reset или reset» - вот с этим я категорически согласиться не могу. Скажем так: данный конкретный транслятор прощает такую вольность. Но некрасивые привычки лучше в себе не воспитывать с молодости, чтобы потом не избавляться от них с мучительной болью. А привычка писать одно и то же имя по-разному - однозначно некрасивая, потому что не способствует ни четкости мысли, ни ясности ее изложения! С другой стороны, привычка всегда и везде писать служебные слова языка строчными буквами, а имена переменных заглавными однозначно будет принята любым транслятором и сделает вам хороший имидж в глазах товарищей-программистов.
Итак, мы пришли к пониманию, что с точки зрения человека имя переменной ассоциируется с ее значением, а с точки зрения компьютера имя просто представляет адрес. То есть между именами и адресами имеется взаимно-однозначное соответствие. Как это соответствие устанавливается?
Первая мысль: написать команду типа «имени переменой SHIRINA поставить в соответствие адрес 14878». На самом деле так тоже никто не делает. В современном программировании мы просто указываем компьютеру: «для переменной SHIRINA отвести 4 байта» или даже еще круче: «для переменной SHIRINA отвести место, как для числа с плавающей точкой». Такой информации достаточно для того, чтобы компьютер сам «оформил землеотвод» по некоторому адресу, а программисту этот адрес чаще всего знать вообще без надобности.
Как компьютер решает задачу размещения переменных в памяти?
Есть два подхода: статический и динамический. Вопреки обычаю, начну с более сложного - динамического. При использовании этого подхода в памяти отводится большая область, которая называется «куча» (англ. heap). Когда возникает нужда создать переменную, компьютер выполняет определенные действия, по итогам которых обнаруживаем отведенный под эту переменную участок в куче, адрес этого участка ассоциируется с именем переменной, а участок помечается как занятый, чтобы не использовать его для чего-то другого. Когда переменная отработает свое назначение, ее нельзя ни оставлять в заброшенном состоянии, ни выбрасывать просто так на свалку: ее необходимо надлежащим образом утилизировать. Для этого имеется специальная команда dispose. Если этого не сделать, то отведенный под переменную участок останется помеченным как занятый (или еще хуже: не будет помечен ни как занятый, ни как свободный), и мы не сможем использовать его для других целей. Такое негативное явление, называемое утечкой памяти (англ. memory leak), типично для не очень опытных и не очень добросовестных программистов, каковых в мире большинство. Проектировщики систем программирования пытаются как-то помочь таким программистам, но с переменным успехом, и вообще на мой взгляд это работа из серии «нос вытащишь - хвост увязнет». Короче, давайте на сегодня считать, что динамическое размещение переменных в памяти - фича для продвинутых программистов.
Суть статического подхода в том, что для всех переменных место в памяти отводится заранее и остается занятым в течение всего времени выполнения программы, т. е. переменная, которая больше не нужна, не уничтожается. С точки зрения чистой экономики такой подход представляется не очень эффективным. Однако сейчас не древний век и мы не покупаем ячейки памяти по одной - покупаем целый компьютер, так что объем памяти обычно бывает с запасом. Иногда - с очень большим запасом. В этой ситуации статическое распределение памяти вполне приемлемо, а в микроконтроллерах практически только так и делается.
Вот пример на языке Паскаль:

var
  Cena:integer;
  Stoim:longint;
  Dlina,Shirina,Vysota,Objem,Ves:real;

Рассмотрим подробно, что здесь написано. Служебное слово var (от variable - переменная) означает, что далее следуют описания всех переменных, которые используются в программе. Эти же описания рассматриваются компьютером как указания отвести участки оперативной памяти под переменные, причем без заполнения этих участков какими-либо начальными значениями (в противном случае вместо var следовало бы написать const). Далее следуют имена переменных и указания их типов: integer - обычное целое число (в Паскале - 2 байта), longint - «длинное» целое число (4 байта). Английскому слову real в русскоязычной математике соответствует термин «вещественное число». Ну мы-то знаем, что настоящих вещественных чисел в компьютерной технике не бывает, так что этому слову соответствует переменная с плавающей точкой… а какой длины? Это нам, по большому счету, не очень-то и важно: компилятор языка Паскаль знает это лучше нас.
Обратите внимание, как в этом примере написаны имена переменных: с заглавной буквы, а последующие буквы - строчные. Это давняя паскалевская традиция. Паскаль - язык строгих правил: на каком бы компьютере он ни был реализован, такое написание не вызовет возражений. Тем не менее в других языках эта традиция может не поддерживаться.
На языке Си этот же пример может быть записан так:

int CENA;
longint STOIM;
single DLINA,SHIRINA,VYSOTA,OBJEM,VES;

Похоже, не правда ли?
Си - язык менее строгих правил, чем Паскаль, но реализован на более широком множестве компьютеров. Поэтому какой-то компьютер может не понять тип real: ведь «вещественные» числа в 32 бита (single), 64 (double) и 80 бит (extended) - они же все real, а тип single однозначно говорит о том, что мы хотим 32-разрядные числа с плавающей точкой. Но компьютер попроще, не «переваривающий» длинные числа с плавающей точкой, может не понять, что такое single. В общем, придется уточнять по мануалам. Слова var или const на сях не пишутся, и это скорее плохо, чем хорошо: экономия трех нажатий на клавиши нас не волнует, а наглядность программы страдает.
И вот тот же пример на языке ассемблера.

dataseg
CENA     dw  ?
STOIM    dd  ?
DLINA    dd  ?
SHIRINA  dd  ?
VYSOTA   dd  ?
OBJEM    dd  ?
VES      dd  ?

Слово dataseg соответствует паскалевскому var и говорит о том, что последующие команды (правильнее было бы сказать директивы) относятся к той области памяти, которая предназначена для данных. Далее каждая переменная декларируется в отдельной строке. Ассемблер не хочет задумываться, будем ли мы использовать числа как целые или с плавающей точкой: ему подавай чисто размер ячейки. И мы ему подаем размер: db - один байт, dw - слово, dd - двойное слово, df (или возможно в каких-то ассемблерах dq) - четверное слово. Далее обязательно начальное значение ячейки, но мы ставим знак вопроса, потому что только запрашиваем ячейки, без записи каких-либо начальных значений.
Важное замечание. Декларируя переменные, мы не только «заказываем» компьютеру место для их хранения, но и даем обязательство, что заявленные здесь имена будут использоваться только как имена переменных, а не для каких-либо еще целей. В программировании каждое слово, каждый знак должен использоваться строго для того, для чего он предназначен, иначе не просто нас не поймут - мы сами себя не поймем!

Имущество твердое и мягкое

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

Что нужно знать о конструкции компьютеров

Прежде всего учтем, что компьютер - электронное устройство, изготовлением компьютеров занимается промышленность: радиоэлектронная или приборостроительная. Так было не всегда: первые компьютеры были механическими.
Обычно компьютер или иное подобное устройство собирается из одного или нескольких блоков (модулей), каждый их которых представляет собой печатную плату со смонтированными на ней электронными компонентами.
Печатная плата представляет собой пластинку из электроизоляционного материала, на поверхности которой имеются медные дорожки, заменяющие провода. Название «печатная» отражает тот факт, что дорожки не прокладываются каждая от начала к концу, а печатаются подобно гравюре все сразу (а на сложной плате их могут быть тысячи). Современная радиоэлектронная промышленность без печатных плат немыслима, но простенькую плату можно изготовить и в домашних условиях (в то же время и заводы не брезгуют частными заказами на изготовление плат из отходов основного производства).
На печатной плате размещаются и закрепляются с помощью пайки компоненты компьютера или иного электронного устройства. Их разнообразие не поддается счету, но под номером 1 у нас будут микросхемы, потому что микроконтроллер, процессор, память - все эти элементы, которые мы рассмотрим чуть позже, выполняются в виде микросхем.
Микросхема представляет собой, по большому счету, ту же печатную плату, только уменьшенную во много раз. На кремниевой пластинке (ее называют кристаллом или чипом, от англ. chip - щепка, стружка) «напечатаны» тысячи, а иногда миллионы электронных компонентов и связей между ними, а для связи с внешним миром к кристаллу подпаяны тончайшие медные проволочки. Размеры чипа могут быть порядка 2..6 мм, так что ясно, что устройство получается весьма нежное. Чтобы защитить микросхему от внешних воздействий, ее заключают в корпус из твердой, почти негорючей пластмассы обычно черного цвета, а для электрических соединений микросхему снабжают металлическими выводами такой толщины, чтобы они хотя бы могли выдержать прикосновение человеческих пальцев. Форму и размеры корпуса конструктор выбирает не как попало, а согласно одному из общепризнанных стандартов. Их много, мы сейчас остановимся на трех.
* Корпуса QFP и SOIC - «планарные», или SMD - surface-mounted details - «детали для поверхностного монтажа». Корпус квадратный (QFP - Quad Flat Package, с вариантами: BQFP, TQFP и др.) или продолговатый (SOIC), выводы («ножки») расположены по кромкам корпуса (у QFP по всем 4 сторонам, у SOIC - только по длинным), и загнуты так, что их концы находятся в плоскости основания корпуса. На поверхности печатной платы под них делаются контактные площадки, и выводы к ним припаиваются. Выводы очень мелкие, поэтому пайка таких микросхем - промышленная технология. Для заводов такая технология - находка, но «не пытайтесь повторить это дома»: следует либо купить микросхему аналогичного назначения в другом корпусе (это в большинстве случаев возможно), либо предпочесть плату заводского изготовления.
* Корпус QFN - квадратный, без «ног» - выводами служат контактные площадки, расположенные по краям основания. Такая микросхема не паяется, а вкладывается в держатель (по-простонародному называемый панелькой или кроваткой), который паяется на плату. К такой технологии прибегают, если требуется, чтобы микросхема была быстросменной.
* Корпус CBGA похож на QFN и отличается тем, что контактные площадки размещены по всему основанию корпуса рядами («матрицей»).
* Корпус PDIP имеет продолговатую форму и выводы только по продольным сторонам. Выводы загнуты вниз. В печатной плате под них сверлятся отверстия, контактные площадки делаются на обратной стороне платы, и пайка выполняется тоже с обратной стороны. Для заводов такая технология неудобна, а вот для радиолюбителя - самое то что надо. Если же пайка «намертво» нежелательна, то для таких микросхем имеются и «кроватки».
Для примера: микроконтроллер ATmega8 выпускается в корпусах TQFP32, QFN32 и PDIP28. Цифры в обозначении корпусов - количество выводов.
Теперь, когда мы получили представление о печатных платах и микросхемах, нам нетрудно понять, что такое однокристальный микроконтроллер или одноплатный компьютер.

Общие принципы архитектуры

Основные части, без которых ни одно компьютероподобное устройство не может обойтись, - это процессор и оперативное запоминающее устройство (ОЗУ, оно же оперативная память, по-английски RAM - Random Access Memory - память с произвольным доступом).
Процессор (англ. processor - обработчик) - это «сердце - пламенный мотор» компьютера. Здесь выполняются все операции по преобразованию данных. А хранятся данные в оперативной памяти. Процессор, как правило, имеет лишь несколько запоминающих ячеек - регистров, в которых данные находятся в течение очень короткого времени перед операциями и после них. Мощные современные процессоры часто имеют кэш - запоминающее устройство типа ОЗУ, но меньшей емкости. Кэш занимает промежуточное место между ОЗУ и регистрами процессора. Для программиста он, как принято говорить, «прозрачен», т. е. программист как бы не видит кэша и не догадывается о его существовании, и пишет программу так, как будто никакого кэша нет. Наверно, мне вообще не следовало бы здесь писать о кэше, но вам это слово может встретиться, например, в описании процессора, значит вам надо знать, что это слово значит.
Количество регистров в современных процессорах обычно бывает 16 или 32, а емкость оперативной памяти от 128 байт у ATtiny25 до 16 Гбайт и возможно больше у «больших» компьютеров.
Процессор и ОЗУ соединены между собой шиной. По большому счету, шина - это просто множество проводов. У сложных мощных компьютеров в состав шины входят определенные электронные компоненты - чипсет, и это я вам пишу опять-таки только для того, чтобы это слово не стало для вас неожиданностью, если вы его где-нибудь увидите. И еще пара выражений, которые вы можете услышать от специалистов: северный мост и южный мост - это не что иное как составные части чипсета в компьютерах архитектуры IBM.
Процессор и оперативная память представляют собой ядро компьютера и, как я уже говорил, это обязательные компоненты. Все остальное - периферия, или периферийные устройства. Их разнообразие огромно: мониторы, клавиатуры, принтеры, звуковые, сетевые устройства и другое. На этом мы остановимся чуть позже. Сейчас важно, что (1) ни одно из этих устройств не является обязательным и (2) обычно любое периферийное устройство может быть заменено другим устройством, близким по назначению, без существенного ущерба для работы программ на этом компьютере.
Периферия соединяется с процессором (и иногда с оперативной памятью) с помощью шины. И вот тут мы подошли к первому архитектурному вопросу, который программисту необходимо прояснить, прежде чем приступать собственно к программированию.
Вопрос вот в чем. Шина может быть либо одна - общая для памяти и периферийных устройств, либо их будет две: шина памяти и шина ввода-вывода (как во всех наших настольных компьютерах и ноутбуках). Соответственно по первому варианту программист обращается к периферийным устройствам как к ячейкам памяти, для которых отведена определенная область адресного пространства (обычно не более четверти того, что отведено под оперативную память). Во втором случае для обращения к периферийным устройствам имеются специальные команды «ввод» и «вывод», и адресное пространство периферийных устройств - свое, отдельное от ОЗУ. Иными словами, команды «ВВОД ИЗ УСТРОЙСТВА ПО АДРЕСУ 108» и «ЧТЕНИЕ ПАМЯТИ ПО АДРЕСУ 108» - это совершенно разные команды.
Следующий архитектурный вопрос: распределение памяти. Здесь два варианта: неймановский и гарвардский. При неймановском варианте (он используется в большинстве компьютеров) имеем одно оперативное ЗУ, в котором для программы и для данных отводятся отдельные области в пределах общей емкости (общего адресного пространства). Сколько отвести под программу и сколько под данные - на этот вопрос никакого стандартного ответа нет: это решается по потребностям для каждой задачи. При гарвардском варианте (он типичен для микроконтроллеров, в т. ч. ATtiny и ATmega) программа и данные находятся в отдельных устройствах и, соответственно, при проектировании нашего изделия мы должны выбрать такой микроконтроллер из семейства, чтобы и память программ, и память данных имели достаточный объем. При этом возможна ситуация, когда память данных соответствует потребности тютелька-в тютельку, а память программ имеет большой избыток емкости (или наоборот).

Разрядность и производительность процессора

Разрядность - важнейший архитектурный показатель процессора (и он же определяет разрядность машины в целом). Это «длина машинного слова», или количество бит, которое данный процессор может обрабатывать одной командой. Разрядность может принимать значения из ряда: 8, 16, 32 и 64. Очевидно, что чем больше разрядность, тем больше диапазон и точность представления числовых величин, с которыми наш процессор может работать, и тем больше данных он способен переработать за единицу времени. Заметим, что процессор, разрядность которого больше 8, обязательно имеет команды для обработки 8-битных величин, а 32-разрядный - также и для 16-битных, и т. д.
Я не случайно подчеркиваю, что разрядность - это архитектурный параметр. Сейчас мы остановимся на двух количественных параметрах: это тактовая частота процессора и количество ядер в нем.
Если процессор - сердце компьютера, то тактовая частота - его ритм сердцебиения. Она определяется тактовыми импульсами, которые вырабатываются тактовым генератором. Любое действие в процессоре занимает один или более тактов, поэтому тактовая частота косвенным образом показывает количество операций, которое процессор может выполнять в секунду. Для Ардуино - даже не косвенно, а почти прямо, а для других процессоров может быть по-разному. Например, процессор Cortex M3 производит сложение, вычитание и умножение за 1 такт, а для деления может потребоваться от 2 до 12 тактов. Поиск аналогичной информации в описаниях и руководствах по процессорам разных типов может оказаться весьма хлопотной работой: два процессора, выпущенные одной фирмой в один год и отличающиеся одной буквой в названии, могут иметь существенные отличия по времени выполнения команд. Поэтому программисту следует всегда держать в уме, что деление - самая долгая из арифметических операций.
Каждый процессор, изготавливаемый на заводе и продающийся в магазинах, имеет максимально допустимую тактовую частоту, которая является его паспортным параметром, т. е. указывается в заводской документации. Именно ее и имеют в виду, когда говорят о производительности процессора. Превышать ее, вообще говоря, не следует. Попытка эксплуатировать процессор на более высокой частоте - разгон процессора - дает результат «фифти-фифти», т. е. может удаться, а может и нет - вплоть до полного выхода процессора из строя. Как правило, процессор при превышении тактовой частоты потребляет больше электроэнергии и сильно греется, так что усиленное охлаждение дает некоторый шанс на успех.
Строительство многоядерных процессоров - прием, позволяющий увеличить скорость обработки данных без чрезмерного увеличения тактовой частоты (что сопряжено с определенными трудностями) и без увеличения количества процессоров в компьютере (что резко усложнит систему и уменьшит надежность). Простые процессоры имеют одно ядро. Когда мы говорим «многоядерный процессор», то подразумеваем, что он 32- или 64-разрядный (количество ядер может быть 2, 4, 8, 16 и т. д.)
Производительность процессора - это объем данных, который он может «переварить» за секунду. Производительность можно определить также и для машины в целом, с учетом объема (объемов) запоминающих устройств, но это сложно, поэтому сейчас остановимся только на производительности процессора. Будем ее рассчитывать по формуле:
P=B*C*F
где P - производительность, B - bits - разрядность, C - cores - количество ядер, F - frequency - тактовая частота.
Обратите внимание, что я использую звездочку как знак умножения. В программировании - только так.
Эта формула приблизительна.
Во-первых, если ядер несколько, то не каждый программист сможет распределить объем работы между ними поровну (и уж точно не сможет, если задача такова, что не позволяет такого распределения). Во-вторых, ядра, работая каждое над своей частью задачи, хоть чуть-чуть, но мешают друг другу при обращении к памяти и периферии, из-за чего производительность неизбежно страдает. С другой стороны, проектировщики мощных процессоров (32- и особенно 64-разрядных), помимо чисто количественного наращивания сил, применяют различные технические ухищрения для уменьшения затрат времени на каждую операцию, так что реальная производительность может оказаться намного больше.
Почему я различаю разрядность как архитектурный параметр и два других параметра как количественные?
Потому что можно построить 8-разрядный процессор с очень большой тактовой частотой, но программироваться он будет так же, как и с низкой частотой. И наоборот, можно построить 64-разрядный процессор с низкой частотой или еще проще: эксплуатировать его на низкой частоте, и на программировании это опять-таки никак не скажется. В реальной жизни так никто не делает. Люди давно поняли, что процессор с маленькой разрядностью предназначен для несложных задач, и большая тактовая частота ему не нужна. Если хотим получить более высокую производительность, то наращиваем и частоту, и разрядность, а потом и количество ядер.
Производительность - важный параметр, позволяющий нам понять, какой процессор «мощный», какой «маломощный», или сказать, к примеру, что процессор Intel Atom в тысячу раз мощнее ATmega. У профессоров подобные выражения под запретом, но действующие программисты в разговоре между собой считают слово «мощность» нормальным.

Какие бывают запоминающие устройства

Рассмотрим несколько терминов, некоторые из которых характерихуют техническую реализацию устройств, а другие - их место в компьютере, роль в решении задачи на компьютере или соответствие некоторым требованиям. Некоторых из них мы уже касались, сейчас кое-что систематизируем.
Оперативная память предназначена для хранения данных для решения задачи, которая в данный момент решается на компьютере, а в «большом» компьютере - также и для программы. В качестве оперативной используется электронная память, все особенности устройства которой «заточены» на максимальное быстродействие и на исключение каких-либо ограничений по количеству операций записи. Оперативная память энергозависима, т. е. хранит данные постольку, поскольку не нее подано напряжение питания (и, соответственно, при этом имеет место потребление электроэнергии). В англоязычной документации соответствующий термин: RAM - Random Access Memory.
Слова «Оперативная память» означают, с одной стороны, место этого устройства в компьютере и возлагаемую на это устройство роль в работе компьютера, и с другой стороны эти слова характеризуют промышленное изделие, продаваемое в магазинах (и соответственно такая надпись может наноситься на само изделие).
SRAM - Static Random Access Memory: слово static характеризует особенности внутреннего устройства микросхемы памяти, интересные и понятные только для инженера-электронщика. Мне непонятно, зачем это слово вообще упоминается в документации на микроконтроллеры Atmel, но оно там есть, и оно не должно сбивать вас с толку: в этих микроконтроллерах это обычная оперативка, выполненная на одном чипе с процессором и используемая только для хранения данных.
Долговременная память: этот термин подразумевает пригодность для долговременного (и следовательно энергонезависимого) хранения данных, которые не требуют частой и многократной перезаписи (вплоть до таких данных, которые записываются один раз и в дальнейшем много раз читаются). Близкие по значению термины: ROM - Read-Only Memory - «память только для чтения», по-русски ПЗУ - постоянное запоминающее устройство.
EEPROM - Electrically Erasable and Programmable Read-Only Memory - «память только для чтения, программируемая и стираемая электричеством» - вариант электронной памяти для использования в качестве долговременной. Эта память имеет скорость чтения практически как у оперативной, однако запись в такую память требует значительных затрат времени (не столько на саму запись, сколько на предварительное стирание ранее записанных данных). В микроконтроллерах фирмы Atmel имеется от 128 до 4096 байт такой памяти, которая выполнена на одном чипе с процессором, может быть использована в программах и допускает до 100000 циклов перезаписи. В «больших» компьютерах такая память также имеется, но только для собственных нужд компьютера, а для программиста она недоступна.
Флэш-память (англ. flash memory) - название одного из типов энергонезависимой электронной памяти, занимающей промежуточное положение между оперативной памятью и EEPROM. Флэш-память работает медленнее оперативной, но пишется быстрее, чем EEPROM и допускает обычно до 10000 циклов перезаписи. Обычно выпускается в виде микросхем, которые можно увидеть в роутерах, телевизорах и телевизионных приставках и других подобных устройствах для хранения программ (прошивок) с возможностью перепрограммирования, а в микроконтроллерах Atmel флэш-память выполнена на одном чипе с процессором. Также этот тип памяти используется в быстросменных картах памяти («флэшках»), которые в «больших» компьютерах используются в качестве внешней памяти.
Внешняя память: под этим термином подразумеваются различные устройства, по сути представляющие собой память, но подключаемые к компьютеру как устройства ввода-вывода. Техническая реализация внешней памяти может быть различна, но есть общие черты: очень большой объем, достигаемый ценой невозможности быстрого доступа к каждой конкретной ячейке. Устройство внешней памяти принимает от процессора команды чтения и записи данных блоками: к команде записи прилагается блок данных, которые требуется записать, а в ответ на команду чтения блока устройство сообщает процессору требуемые данные. Чтение и запись происходят значительно медленнее, чем в оперативной памяти, поэтому процессор никогда не обрабатывает данные из внешней памяти непосредственно: он дает команду чтения, помещает данные «оптом» в оперативную память, выполняет всю обработку там, а результаты, если нужно, помещает во внешнюю память. В «больших» компьютерах все программы для решения множества задач, а также и данные для их работы, хранятся именно во внешней памяти, где они организованы в виде файловой системы, и при необходимости копируются в оперативную память, где и ведется вся обработка.
Здесь рассмотрена общепринятая трактовка термина «внешняя память», но применительно к микроконтроллерам Atmel этот термин имеет другое значение: оперативная память в виде отдельной микросхемы, в отличие от той, которая расположена на одном чипе с процессором. Настоящей внешней памяти в таких микроконтроллерах чаще всего не бывает.
«Винчестер» - несменный жесткий магнитный диск - устройство номер 1 для использования в качестве внешней памяти в «больших» компьютерах. В качестве устройства номер 2 здесь будут вышеупомянутые флэш-карты, а под номером 3 - SSD-диски, которые представляют собой не что иное как флэш-микросхемы, подключаемые к компьютеру как винчестеры.
Настоящий винчестер не имеет ограничений по количеству циклов записи, поэтому чаще всего используется в больших компьютерах, а флэш-карты и SSD имеют такие ограничения и поэтому не могут рассматриваться как полноценная замена винчестерам. Их следует использовать как WORM-память (англ. Write Once Read Many - «пишем один раз, читаем много раз»).
Кэш-память - небольшая оперативная память, встроенная в процессор и называемая так только в том случае, если имеется и настоящая оперативная память вне процессора.
Лазерные оптические диски (CD и DVD) и соответствующие дисководы могут рассматриваться и в качестве памяти, и в качестве устройства ввода-вывода.

Какие бывают периферийные устройства

Мы уже рассмотрели устройства ввода-вывода и внешние запоминающие устройства - все они являются периферийными.
Периферийные устройства соединяются с процессором шиной ввода-вывода (или общей шиной). С точки зрения программиста каждое устройство представлено небольшим количеством запоминающих ячеек - регистров, или портов, ввода-вывода. Мы можем читать их них информацию и записывать свою, которая может восприниматься устройством как команды или как данные. Типична ситуация, когда устройство имеет всего два порта ввода-вывода: порт данных и порт управления (команд, настроек). Основная сложность работы программиста с периферийными устройствами состоит в том, что нужно подробно изучить каждое устройство (а их много, и все разные!), чтобы понять, что куда писать и откуда читать.
Разнообразие периферийных устройств для микроконтроллеров, специализированных компьютеров, гаджетов и больших компьютеров не поддается счету, сейчас мы рассмотрим лишь некоторые из них.
Аналого-цифровые и цифро-аналоговые преобразователи широко используются в промышленной автоматике и, соответственно, в микроконтроллерах. Выше я писал про аналоговый компьютер, в котором каждая величина, участвующая в расчетах («переменная»), может принимать непрерывное множество значений в допустимом интервале. Компьютеры, с которыми нам предстоит иметь дело, - цифровые: в них каждая величина имеет конечный ряд допустимых значений, так что каждое значение аналоговой величины может быть представлено ближайшим значением из ряда допустимых. Чтобы включить такой компьютер в некоторое техническое устройство, приходится ставить соответствующие преобразователи. Роль аналоговых величин чаще всего играет электрическое напряжение, иногда - сила электрического тока. Неэлектрические величины типа температуры, давления, освещенности преобразуются в электрическое напряжение с помощью соответствующих датчиков, которые на рынке представлены как самостоятельные изделия. С другой стороны, электрическое напряжение, выдаваемое компьютером через цифро-аналоговый преобразователь, может быть подано на источник света или на электромотор…
Таймер или правильнее: счетчик-таймер считает поступающие на его вход электрические импульсы: досчитав до установленного значения (или до нуля, если нужное значение было заложено в счетчик перед началом операции), счетчик-таймер посылает микроконтроллеру сигнал, в ответ на который можно запрограммировать те или иные действия. Таймер, в строгом понимании этого слова, обеспечивает выполнение некоторого действия через заданное время после наступления определенного события. Таймер-счетчик считает импульсы, которые совсем необязательно соответствуют каким-то единицам времени. И в любом случае ни одно из этих устройств «не знает», какой сейчас день недели или год: эта задача возложена на другое устройство.
Часы истинного времени или, как часто пишут «часы реального времени» (что не совсем верно), хранят в своих запоминающих ячейках часы и минуты местного времени, число, месяц и год, и обычно день недели впридачу, и могут выдавать эти значения по запросу компьютера. Таким образом можно обеспечить временную привязку действий компьютера не к событию, которое может произойти когда угодно, а к заданному дню и часу. Например, в помещении, где содержат скот или домашнюю птицу, для повышения их продуктивности желательно включать и выключать свет в определенное время. Прибор, который можно построить для решения этой задачи, тоже назыается таймером, но в наше время такой прибор целесообразно построить на микроконтроллере и снабдить его часами истинного времени, во избежание нарушения светового режима при перерывах подачи электроэнергии.
Часы истинного времени обязательны для большого компьютера, а для микроконтроллеров они поставляются как отдельные изделия.
Устройства отображения информации используются тогда, когда вырабатываемая компьютером информация предназначена для восприятия человеком. Персональный компьютер без таких устройств немыслим. В этой группе устройств под номером 1 будет экран. Монитор, или если совсем строго то видеомонитор, - это экран, изготавливаемый промышленностью и продающийся в магазинах как самостоятельное изделие, подключаемое к компьютеру через стандартный интерфейс. Принтер, в терминологии нашей молодости алфавитно-цифровое печатающее устройство (АЦПУ), на программистском жаргоне «печаталка» - тоже относится к устройствам отображения.
Устройства ручного ввода - здесь под номером 1, конечно, клавиатура, а под номером 2 - всевозможные манипуляторы, передающие компьютеру определенные сигналы при перемещении устройства человеком: мыши, трекболы, джойстики, игровые рули и педали…
Звуковые устройства, звуковые карты, звуковые процессоры.
Устройства приема и передачи данных обеспечивают обмен данными между двумя и боле компьютерами, находящимися на значительном расстоянии друг от друга. Такие устройства достаточно разнообразны. Если расстояние не очень велико и имеется возможность проложить провод, то используется проводная связь по интерфейсам SPI (Serial Peripheral Interface), TWI (Two-Wired Interface), RS-232 или Ethernet. Последний достаточно сложен и используется в серьезной технике, начиная с 32-разрядных микроконтроллеров ARM Cortex, в более дешевых устройствах он не получил признания. Передача данных по проводам с помощью электрического тока сопряжена с определенными трудностями. Если говорить по-самому-простому, то можно передавать данные быстро, но недалеко, а можно на большое расстояние, но медленно. От этого недостатка свободен волоконно-оптический (оптоволоконный) кабель, по которому данные передаются не током, а светом. Основной объем «грузооборота» компьютерных данных в мире приходится именно на оптоволоконные сети (в понимании большинства людей они ассоциируются с интернетом - это не совсем верно, но в первом грубом приблиении можно принять).
Если прокладка проводов невозможна или нежелательна, приходится использовать радиоволны: на малых дистанциях WiFi и Bluetooth, на средних - приемопередатчики диапазона 433 МГц, на дальних дистанциях - коммерческие сети GPRS, 3G и 4G.
GPIO - General Purpose Input-Output - ввод-вывод общего назначения - это просто провода (часто заканчивающиеся контактными штырями или гнездами), которые напрямую соединены с портами ввода-вывода, так что мы можем просто снимать с них данные в виде логических нулей и единиц либо посылать туда высокое напряжение (логическую единицу) или низкое (логический 0). GPIO никогда не работают сами по себе - к ним подключаются какие-то другие устройства, и этими устройствами мы можем управлять. GPIO всегда имеется на микроконтроллерах, иногда в больших количествах (десятки отдельных линий), а у больших компьютеров GPIO чаще всего нет.
Периферия больших компьютеров (а часто и микроконтроллеров) обычно строится по двухуровневому принципу: каждое «направление» ввода-вывода обслуживается двумя устройствами, одно из которых - оконечное устройство, а другое - адаптер. Например, монитор - оконечное устройство, а видеокарта - адаптер (ее и называют часто видеоадаптером). Такое кажущееся усложнение системы продиктовано тем, что оконечных устройств очень много, выпускаются они множеством разных фирм, и нет смысла «учить» компьютер работать с каждым из них. Эта задача возлагается на проектировщика адаптера, а проектировщику компьютера и программисту приходится иметь дело только с адаптером.
На самом деле в большом компьютере при наличии операционной системы таких уровней бывает даже не два, а больше, но все остальные уровни представлены виртуальными, или логическими, устройствами, за которыми не стоит никакое «железо» - это просто программы в составе операционной системы. Рассмотрим, что происходит, если программист в системе Linux пишет, допустим, на языке Паскаль writeln или на языке C - printf. Данные, которые он хочет вывести, попадают на стандартный вывод - само это выражение красноречиво говорит о том, что это виртуальное устройство. Стандартный вывод передает данные на следующее виртуальное устройство - обычно на консоль, но смысл хитрости в том, что стандартный вывод можно перенаправить, например на принтер или в файл. Причем делается это средствами операционной системы, без вмешательства в программу, «заказывающую» вывод. С консоли данные направляются либо во фреймбуфер, либо на эмулятор терминала, и уж только оттуда - на видеокарту.
Ужасно сложно, да?
Подобные «сложности» в компьютерном мире - обыкновенная повседневность. На самом деле все это было бы сложно для человека, если бы он затеял в одиночку разрабатывать операционную систему. Но реальную операционную систему создает не один человек - там большой коллектив, в котором каждый программист разрабатывает свой участок. По результатам же этой работы имеем существенное упрощение жизни как для программиста, так и для системного администратора, а в конечном счете и для разработчиков операционной системы, если они захотят что-то в своем изделии переделать.

Программная совместимость и архитектурные классы (аппаратные платформы) компьютеров

Два компьютера называются програмно-совместимыми, если программа, написанная для одного из них, может эксплуатироваться и на другом.
В те времена, когда компьютеры только появились, проблема программной совместимости стояла очень остро: каждый новый компьютер строился с теми или иными усовершенствованиями, и каждое усовершенствование могло привести к тому, что все программное обеспечение для нового компьютера придется создавать заново с чистого листа, а это было чрезвычайно трудоемко. Случалось, что разработка программ просто не успевала за разработкой «железа». С появлением языков высокого уровня острота этой проблемы несколько снизилась: теперь можно было старую программу просто перекомпилировать для нового компьютера. Но это возможно постольку, поскольку доступен исходный текст программы, а так бывает не всегда. Таким образом, в наше время создатель каждого нового компьютера должен серьезно задумываться о том, нужно ли обеспечивать программную совместимость и с какими именно из ранее созданных компьютеров.
Часто бывает так, что некоторый новый компьютер А создается не на пустом месте, а как развитие некоторого более старого компьютера В. В таком случае разработчик обеспечивает программную совместимость «снизу вверх»: программа, созданная для компьютера В, может выполняться и на компьютере А, но не гарантируется, что программа для компьютера А, будет выполняться на В. В дальнейшем может появиться новый компьютер С, и т. д. Таким образом развивается семейство компьютеров, пограммно-совместимых «снизу вверх».
От чего же зависит программная совместимость или несовместимость?
Причиной несовместимости может быть любая мелочь. Но для совместимости необходимо, чтобы процессоры имели, как минимум, одну и ту же систему команд (командный язык). Командный язык непосредственно связан с разрядностью процессора.
Существует много архитектурных классов компьютеров: два компьютера из разных классов категорически не будут иметь программной совместимости, а в пределах одного класса по крайней мере есть надежды на совместимость. Часто употребляется термин «аппаратная платформа».
Из множества архитектурных классов рассмотрим три самых перспективных для нас.

AVR

Это «Alf & Vergard RISC» - «компьютер Альфа и Вергарда с сокращенной системой команд». В рамках этого класса фирма Atmel выпускает семейства 8-разрядных однокристалльных микроконтроллеров (ОКМК) ATtiny и ATmega (хотя по большому счету это одно большое семейство). Эти простые машинки - «Жигули» среди компьютеров. Они имеют 32 регистра общего назначения, оперативную память SRAM и долговременную память EEPROM для данных, flash-память для программы (гарвардская архитектура!) и «малый джентльменский набор» периферийных устройств для управления различным оборудованием. Значения емкости запоминающих устройств варьируются в широком диапазоне, за счет чего и получается семейство микроконтроллеров, программно-совместимых с точностью до некоторых нюансов.
Процессоры AVR работают только с целыми числами, в них нет команды деления, а в самых маленьких - даже и умножения. Несмотря на это, выпускаются они в огромных количествах и применяются в самых разных изделиях от игрушек до вполне серьезной промышленной автоматики. На основе этих однокристалльных микроконтроллеров выпускаются одноплатные микроконтроллеры (ОПМК) под торговым названием Arduino. Однако сразу предупреждаю: Arduino - категория не архитектурная, а скорее конструктивная: под этим же названием выпускаются машины ARM Cortex M3 (Arduino Due), а несколько лет назад выпускались и в архитектуре Intel (Arduino Galileo, сейчас их выпуск прекращен).
Кроме Arduino, множество фирм из разных стран выпускает на основе Atmel'овских микроконтроллеров одноплатные микроконтроллеры: SEM - Smart Evolution Module - буквально «хитрый модуль для развития», Seeduino и другие, и можно не сомневаться, что в обозримом будущем появятся еще. В отличие от ардуин, большинство которых (Uno, Nano, Micro, Leonardo, ProMini) использует один и тот же ОКМК ATmega328 (32к+2к памяти), семейство SEM представляет собой гамму микроконтроллеров с широким выбором по емкости памяти: от ATmega48PA (4к+512) до ATmega1248P-AU (128к+16к). Для каждого устройства в скобках указаны величины емкости памяти: flash-памяти + SRAM.
Эти микроконтроллеры очень энергоэкономичны: могут месяцами работать от небольших батареек и при работе практически холодные.
Многие считают AVR идеальной «учебной партой» для начинающих программистов. Такой взгляд имеет место быть, однако есть и аргументы «против». Микроконтроллер, в отличие от «большого» компьютера, не работает сам по себе: к нему подключается какая-то периферия, и для программирования желательно (читаем: необходимо) понимание устройства и работы этой периферии. Если мы делаем какие-то игрушки-самоделки, то нужно разбираться в электротехнике (хотя бы на уровне закона Ома), понимать принцип работы светодиодов, электродвигателей (простых и шаговых)… Не обойтись и без некоторых навыков радиомонтажа. Программист промышленных контроллеров работает обычно не один, а в команде, и может себе позволить этого всего не знать или знать поверхностно, но в промышленности на такие машины часто возлагаются задачи, для решения которых нужен серьезный математический аппарат: дифференциальное и интегральное исчисление, векторная алгебра и аналитическая геометрия… Это наука не школьного, а скорее университетского уровня.
И еще. Микроконтроллеры часто вообще не имеют средств отображения информации (мониторов и т. д.), что может существенно затруднить поиск ошибок в программах (отладку программ). В общем, микроконтроллеры не так просты, какими хотят казаться.
На мой субъективный взгляд, важнейшая привлекательная черта маломощных микроконтроллеров - это их простота, позволяющая нам за сравнительно небольшое время разобраться во всем их устройстве, так сказать, «до дна» (что совершенно немыслимо для более сложных процессоров, например для AMD64). Кроме того, эти машинки не терпят упрощенческого, наплевательского подхода к программированию. Да, мигать светодиодом с помощью такого микроконтроллера можно научиться за полчаса, но более сложная программа, сделанная наспех, без должной подготовки, без тщательного изучения предмета, может просто «не пойти», тогда как более мощные машины это прощают.

ARM Cortex

ARM расшифровывается как Advanced RISC Machine или как Acorn RISC Machine, т. е. тоже подразумевает компьютер с сокращенной системой команд, хотя, как и в предыдущем случае, «сокращенный» - скорее все-таки красивый лозунг, чем реальность.
Под этим обозначением подразумевается не какой-то конкретный компьютер, а свод рекомендаций «о том, как правильно строить компьютеры». Прежде всего оговоримся, что, согласно этим рекомендациям, правильный компьютер - 32-разрядный (хотя сейчас уже может быть и 64-разрядный), а в остальном могут быть варианты.
ARM Cortex M0…M4 - в рамках этого подкласса фирма STMicroelectronic выпускает семейство однокристалльных микроконтроллеров STM32. Это семейство большое, в нем порядка сотни членов (против примерно 30 у Atmel), и они различаются как количественно (емкостью flash-памяти и SRAM), так и «уровнем развития»:
STM32F0 (Cortex M0) - «entry-level», машины для новичков.
STM32F1 (Cortex M3) - «mainstream», машины для самого широкого круга потребителей.
STM32F2 (Cortex M3) и STM32F4 (Cortex M4) - «high-performance», машины с расширенными возможностями.
В архитектуре этих МК очевидны параллели с AVR, прежде всего гарвардская архитектура памяти (только у них нет EEPROM). Но они имеют бОльшую разрядность и тактовую частоту, и бОльшую емкость памяти (с возможностью выбора), соответственно им по плечу более трудные задачи, и такая машина прощает программисту многие грехи, которые не прошли бы на ардуинке.
На основе этих ОКМК выпускаются одноплатные микроконтроллеры: STM32 Discovery Board (буквально «плата для открытий») и NUCLEO. Обе эти серии ОПМК во многом близки и к ардуинам, и к SEM'ам, и к ним можно подключать ту же самую периферию.
ARM Cortex R - микроконтроллеры для систем реального времени - мы их касаться не будем.
ARM Cortex A - подразумевает не микроконтроллеры, а «чистые» процессоры (хотя возможно с оперативкой на кристалле - Storage on Chip - SoC), более мощные, чем STM32, и ориентированные на применение в одноплатных компьютерах общего назначения (ОПКОН). В частности, процессоры фирмы Broadcom (Cortex A53 или A7) используются в компьютерах Raspberry Pi. Orange Pi - это тоже Cortex A7, а фирма Samsung на основе своих же процессоров Exynos 4412 (Cortex A9) выпускает компьютеры Odroid. На такие компьютеры обычно устанавливают операционные системы семейства Linux.
Процессоры ARM используются в планшетах, смартфонах, роутерах, калькуляторах и т. д. Правда, не все они Cortex (соотношение между такими понятиями, как ARM и Cortex - довольно сложный вопрос. Где-то в интернете мне встретилась фраза: Cortex - самый совершенный ARM). Программное обеспечение таких аппаратов часто на 3/4 и больше состоит из запчастей от линуксов, благо такие запчасти доступны и бесплатны.
Архитектура ARM всегда подразумевает полный набор арифметических команд, в том числе для «длинных» (32-разрядных) целых чисел, а Cortex M4 и все Cortex A могут обрабатывать и числа с плавающей точкой.

AMD64

Это класс мощных 64-разрядных процессоров, как одно-, так и многоядерных. Процессор Athlon64 был выпущен фирмой Advanced Micro Devices (AMD) в 2003 году, в качестве его прототипа были использованы 32-разрядные процессоры, выпускавшиеся фирмами AMD и Intel. Athlon64 стал первым серийным 64-разрядным процессором для общегражданского применения.
Эти процессоры - тяжеловозы современного компьютерного мира, они ориентированы на большие компьютеры. Выпускаются в нестандартных корпусах и вставляются в контактный держатель - сокет (англ. socket), размещаемый на материнской плате (motherboard). На материнской плате имеются шины с чипсетом, разъемы (слоты) для оперативной памяти (она здесь сменная) и некоторые периферийные устройства: видеопроцессор, звуковую и сетевую карты, часы реального времени с резервной батарейкой. Такая плата - сложное и громоздкое устройство, изготавливаемое только в заводских условиях.
Процессоры этого типа потребляют много электроэнергии и, соответственно, любят хорошее охлаждение, чаще всего с принудительным обдувом воздухом с помощью вентилятора.
Архитектура этих процессоров представляет собой довольно замысловатое наслоение множества противоречивых технических решений, выработанных разными людьми в течение нескольких десятилетий. Разобраться в ней досконально - трудно даже для человека, систематически в течение многих лет работающего с такими процессорами. Однако неправильно было бы говорить, что начинающему программисту сюда вообще не следует соваться. Во-первых, такой компьютер чаще всего работает сам по себе, так что многие задачи можно решать, не зная никакой другой техники, кроме самого этого компьютера. Во-вторых, на таком компьютере всегда имеется операционная система: она берет на себя множество функций, которые на микроконтроллере пришлось бы осуществлять «своими вот этими руками». Например, если нужно вывести результат работы программы на экран, то программируется системный вызов, а чтобы то же самое вывести в файл, этот системный вызов нужно лишь слегка подправить. За системным вызовом стоит большая процедура, но большинство программистов ничего об этом не знает, и в этом нет ничего стыдного.
Следующий аргумент «ЗА»: на большом компьютере обычно имеется монитор, так что если в программе что-то идет не так (а поначалу ВСЕГДА что-нибудь не так), то можно, например, вывести на экран значение переменной, которая вызывает сомнения, и т. д. Таким образом, поиск неисправностей в программе значительно облегчается по сравнению с микроконтроллерами.
Кроме того, именно на «больших» компьютерах строятся почтовые и WEB-серверы, для которых создается огромное количество программ на специализированных языках (типа PHP, Java и Java-script) - это целый большой пласт в искусстве программирования.

Понятие ресурсов компьютера

Ресурс - это нечто, что все хотят, но на всех не хватает. Каждый человек хочет иметь такой компьютер, который мгновенно решал бы самую сложную задачу. Но такой компьютер будет чудовищно дорог. Компьютер, который мы покупаем за имеющиеся у нас деньги, неизбежно будет иметь ограниченные «умственные способности». Любая причина, которая их ограничивает, и есть ресурс.
На сегодня мы ограничимся рассмотрением двух ресурсов: процессорного времени (или производительности процессора - можно смотреть и так и так) и объема памяти.
Мы получили представление о том, какой компьютер мощный, какой маломощный. Теперь мы можем сказать, что мощный компьютер имеет большие ресурсы, а маломощный - маленькие.

Математическое обеспечение

В предыдущей главе мы коснулись аппаратного обеспечения компьютеров, в повседневной речи - «железа». Соответствующий английский термин - hardware - буквально «твердое имущество». Теперь остановимся на «мягком имуществе» (software). Этим термином называют математическое обеспечение компьютеров.
Если говорить о математическом обеспечении, то обычно прежде всего люди представляют себе программы. Давайте с самого начала договоримся, что собственно программы - это верхушка айсберга. Сам же айсберг на 90% состоит из чистой математики.
Математика - наука об общих количественных закономерностях в окружающем нас мире. Она выросла из того, что люди, по мере своего умственного развития, стали замечать, что очень разные на первый взгляд события могут быть представлены одними и теми же числовыми и логическими описаниями, а значит и разные задачи могут быть решены сходными методами.
Чтобы понять, что такое математическая модель, возьмем для примера две задачи.
ЗАДАЧА 1. У нас имеется три железорудных карьера, каждый из которых может выдавать в день некоторое количество руды (свое), и два металлургических завода, каждый из которых может принимать в день некоторое количество руды. Между карьерами и заводами проложены дороги, расстояния между пунктами известны. Сколько самосвалов нам потребуется для доставки всего имеющегося количества руды с карьеров на заводы?
Как такую задачу вообще решать, сразу и не сообразишь, да? Однако с первого взгляда ясно, что можно решить «в лоб», т. е. пусть вся руда с карьера N1 поступает на завод N1, и т. д. Но насколько удачно будет такое решение? Если бы у нас были совсем маленькие карьеры и один-единственный грузовик, мы могли бы придумать несколько вариантов организации перевозок и выбрали бы из них такой, чтобы наш грузовик хотя бы «накручивал» за день меньше километров. Если же ясно, что одним грузовиком не обойтись (а возможно их потребуются сотни или тысячи), то вариантов будет так много, что перебирать их будем до скончания века, а на заводах и в карьерах нашего решения просто не дождутся… Значит, хотелось бы иметь математический метод, который бы позволил нам получить оптимальное расписание движения грузовиков без перебора всех вариантов.
ЗАДАЧА 2. У нас имеется ракетный крейсер, вооруженный 16 ракетами «Базальт», и подводная лодка с 16 ракетами «Гранит», а нам противостоит вражеский флот в составе 2 авианосцев, 3 крейсеров и 10 эсминцев. Мы знаем, что таким количеством ракет все корабли нам не потопить, но если сосредоточить весь ракетный залп по одному авианосцу, то его мы потопим наверняка. Аналогично можно потопить 2 крейсера или 5 эсминцев. Если это удастся, будем сверлить дырочки под ордена, да? Но как поступит после этого командир вражеского флота? Подсчитает потери, доложит вышестоящему командованию… Сообразит, что больше ракет у нас нет, и с оставшимися силами пойдет дальше бомбить наши города? А у нас там дети…
Очевидно, что эту задачу, как и предыдущую, не следует пытаться решать «в лоб». Может быть, распределить наши ракеты на вражеские корабли так, чтобы, допустим, не топить их, а нанести такие повреждения, после которых противнику уж точно ничего не останется, как убираться восвояси? Но если так, то сколько ракет нацелить на каждый вражеский корабль?
Итак, две казалось бы очень разных задачи из разных отраслей человеческой деятельности. Но вот что интересно: решаются они практически одним и тем же методом. Называется он динамическое планирование или динамическое программирование. Слово программирование здесь не должно вводить нас в заблуждение (просто этот метод был изобретен достаточно давно, когда программирование в «нашем» понимании этого слова еще не было в ходу).
К чему я это все? К тому, что программирование (в «нашем» смысле этого слова) начинать следует не с того, чтобы очертя голову хвататься за клавиатуру, а с изучения математики.
Теория вероятности… «Наука о случайном? Как такое может быть?»
Теория игр… «Что мы, дети что ли, чтобы играть?»
Теория игр - это вам не в бирюльки играть, это абсолютно взрослая наука, изучаемая в институтах! Учебник «Введение в теорию вероятности и ее приложения» состоит из нескольких томов, и весьма толстых (а теория игр - это как раз одно из этих приложений). А используются эти приложения людьми самых разных профессий, от финансистов до военных.

Об алгоритмах и программах

Слово алгоритм восходит к имени математика Аль-Хорезми, однако связь между ними не совсем понятна. Первоначально алгоритмом назывался метод вычисления («извлечения») квадратного корня из заданного числа. В то время, когда жил и работал Аль-Хорезми, для математиков уже не были новостью формулы и расчеты по ним. Проблема в том, что квадратный (или иной) корень невозможно вычислить по фомуле. То есть формула-то имеется (она была предложена Героном еще задолго до Аль-Хорезми), но если произвести одно вычисление по этой формуле, то получим лишь грубо приблизительный результат: например корень из 2 - якобы 1.5 (на самом деле 1.41…), а корень из 3 - якобы 2 (на самом деле 1.73…). Чтобы получить более точный результат, расчет по формуле нужно выполнить несколько раз с поправкой исходных данных на каждом шаге. Этот метод, собственно, и был назван алгоритмом, а затем этим словом стали называть любые указания по выполнению умственных операций, по которым нужные действия следует выполнять в строго определенной последовательности.
Рассмотрим алгоритм Герона (ну не придумать более красивой формулировки!) подробно.
Если X - число, из которого извлекаем корень, а Y - значение функции, то Y = SQRT (X), где SQRT (от английского SQuare Root) - имя функции, принятое во всех нормальных языках программирования. Начальное, грубо приблизительное значение результата:
Y0 = (X+1)/2
Теперь, собственно, формула Герона:
Yn+1 = (Yn + X/Yn)/2
Откуда возникла эта формула? - очевидно, из самого смысла квадратного корня: корень - это не что иное как длина стороны квадрата, площадь которого равна X. Такую же площадь имеет прямоугольник, одна сторона которого X, а другая 1. Этот прямоугольник мы как бы последовательно трансформируем в прямоугольники такой же площади, с меньшей длиной, но большей шириной, и в конце концов получаем такой прямоугольник, у которого длина и ширина практически равны, т. е. квадрат.
Пример. Пусть X=2.25, тогда ожидаем Y=1.5. Y0=(2.25+1)/2=1.625. Подробные вычисления опускаю, привожу промежуточные результаты: Y1=1.5048, Y2=1.50000766… - получаем ряд значений, каждое следующее из которых ближе к искомому, чем предыдущее. Останавливаемся, когда очередное значение Yn+1 отличается от предыдущего Yn на величину не более заданной погрешности. Например, если мы хотим получить значение корня с точностью до 0.001, то в нашем примере такая точность уже достигнута.
Этот старый алгоритм называется итерационным, или алгоритмом последовательного приближения. Именно его нам в институте давали на лекциях по программированию. Я в своем курсовом проекте (том самом, на ЕС-1060) применял этот алгоритм, модифицированный для извлечения кубического корня. Наши горе-профессора, похоже, не догадывались, что этот алгоритм несовершенен и что в реальной вычислительной технике от него давно отказались. Что же не так в этом алгоритме?
Во-первых, в рассмотренном примере мы ожидали увидеть точный результат 1.5, а получили результат с погрешностью, и нетрудно убедиться, что для любого другого значения X результат тоже будет с погрешностью. В каких-то ситуациях это приемлемо, а в каких-то нет. Во-вторых, в нашем примере мы произвели всего 3 итерации и получили удовлетворяющий нас результат, но так будет не всегда: при больших значениях X количество итераций будет возрастать. В-третьих, на каждой итерации приходится выполнять две операции деления, а деление может занимать больше времени, чем любая другая арифметическая операция. Правда, если мы извлекаем именно квадратный корень, то одно из этих делений будет на 2, а это как раз такая операция, которую можно сделать по-хитрому. Но не на всяком языке возможно запрограммировать деление на 2 по-хитрому…
Исходя из этих соображений, в реальной компьютерной технике итерационный алгоритм извлечения квадратного корня заменен более прогрессивным алгоритмом поразрядного взвешивания (он же алгоритм «цифра за цифрой»).
Чтобы понять суть алгоритма поразрядного взвешивания, вспомним, как производится обычное взвешивание на весах с двумя чашами. У нас имеется набор из N гирь: «старшая» - самая тяжелая, а каждая следующая - в два раза легче предыдущей. Соответственно нам потребуется произвести N взвешиваний: ставим на весы очередную гирю, начиная со «старшей», и смотрим результат. Если весы пришли в равновесие, значит имеем ТОЧНЫЙ результат, и на этом останавливаемся. Если гиря перевешивает, ее убираем. Затем пробуем следующую по порядку гирю, и т. д. Правда, для того, чтобы вычислить квадратный корень, весы нам потребуются хитрые: они должны сравнивать вес «товара» с КВАДРАТОМ веса гирь. В природе таких весов не существует, но мы их смоделируем на компьютере: операция взвешивания сводится к возведению веса гирь в квадрат, т. е. к умножению его на самого себя. По итогам N взвешиваний будем иметь некоторые гири на чаше весов - соответствующие биты в ячейке, отведенной под результат, будут установлены в 1, другие гири «отдыхают» - соответствующие биты ставим в 0. Общее число верных цифр (бит) результата, очевидно, равно числу произведенных взвешиваний, если только точный результат не был получен досрочно.
Оба рассмотренных алгоритма вычисляют корень путем повторения одних и тех же действий несколько раз с изменением исходных величин. Повторение - значит затраты времени. Но при поразрядном взвешивании нам потребуется повторять, по большому счету, единственную операцию умножения (возводим пробный результат в квадрат) столько раз, сколько точных цифр мы хотим иметь в результате. Если нас устроит приблизительный результат, то и получим его быстро, если же требуется высокая точность, придется проявить упорство. Затраты времени зависят только от требуемой точности, но не от величины подкоренного числа.
Поразрядное взвешивание - это, строго говоря, не самостоятельный законченный алгоритм, а скорее принцип, «скелет алгоритма», который может обрасти различным «мясом». Он позволяет вычислить любую функцию, даже самую зловредную, если имеется «хорошая» функция, обратная искомой. Допустим, имеем функцию Y=Fbad(X), которую мы вообще не знаем как вычислить (вообразим, что мы ничего не знаем про итерационный алгоритм). Зато у нас имеется функция X=Fgood(Y), которую мы как минимум МОЖЕМ вычислить. Тогда поразрядное взвешивание будет для нас беспроигрышным решением для вычисления Fbad. А если еще окажется, что Fgood достаточно проста для вычисления (возведение в квадрат реализуется ОЧЕНЬ ПРОСТО путем умножения числа само на себя), то это серьезный аргумент в пользу того, чтобы поразрядное взвешивание предпочесть любым другим методам. И где бы этот метод ни применялся, всегда он сохраняет основное преимущество: позволяет экономить время при приблизительных расчетах.
К чему я это все? К тому, что математика за тысячелетие своего существования выработала множество путей решения разных задач (сколько методов доказательства теоремы Пифагора вы знаете?) И вот тут мы приходим к пониманию одной очень важной мысли, которую вы едва ли найдете в книгах по компьютерной технике и уж точно не услышите ни от школьных учителей, ни от университетских преподавателей - ну так послушайте старшего товарища и сделайте наоборот!
Мысль такая: если алгоритм - это чистая наука, математическая абстракция, то программа - это техническое устройство, промышленное изделие. Программа проектируется инженерами, ее создание характеризуется конечной трудоемкостью, а будучи изготовлена, программа эксплуатируется как инструмент для решения некоторой задачи, которую ставит перед нами жизнь. У математиков, как и у представителей других научных специальностей, изобретение\открытие любого метода решения какой-либо задачи (пусть этот метод хоть 51-й по счету) считается достижением. Там не принято рассуждать, что такой-то метод хорош или плох. В лучшем случае что-нибудь скажут на тему изящества, поаплодируют на каком-нибудь симпозиуме… Но инженерная деятельность отличается от науки, а программирование - это инженерная деятельность. И к нашему изделию предъявляются требования: оно должно быть хорошим инструментом. Это не значит, что рассуждения об изяществе к нему неприменимы. Есть же определенная красота в старинных стамесках и рубанках, а над современными бензопилами работают специалисты-дизайнеры. Да, все так, но если есть два алгоритма А и Б и один из них имеет недостатки, а другой преимущества, то для технического изделия однозначно следует предпочесть тот, который имеет преимущества. А чтобы предпочесть, нужно, как минимум, знать о существовании такого алгоритма, а как максимум - желать и уметь сравнить алгоритмы и понять, как они соотносятся между собой. А сделать хорошее изделие на основе несовершенного алгоритма - это вряд ли.

Лирико-математическое отступление

А сейчас давайте запасемся листком бумаги и карандашом, залезем с ногами в шезлонг в саду под яблоней, или осенним дождливым вечером в кресло у растопленного камина, или зимней непроглядной ночью на верхнюю боковую полку плацкартного вагона… это кому как нравится. Нет, писать программу сейчас не будем: нам для этого пока что не хватает теоретической подготовки. Сегодня мы ЧИСТО МЫСЛЕННО, без всякого компьютера (но с оглядкой на компьютер!), попробуем что-нибудь вычислить. Квадратный корень извлекать мы худо-бедно научились, теперь надо придумать что-нибудь позаковыристее. Простая задача: вычислить логарифм.
– Фиу, ну ты сказал: простая! Как его вычислить-то?
– В наше время логарифмы изучали в школе, в рамках «элементарной» математики, но там мы не касались вычисления их значений. В институте, в рамках курса высшей математики, преподается теория рядов. Получается, что многие хитрые математические функции можно «разложить в ряд Тейлора». Например, синус и косинус можно вычислить так:

(здесь будет формула для синуса и косинуса)

Ряды бесконечны, а в компьютерной технике ничего бесконечного, как мы знаем, не бывает. Поэтому подобные вычисления всегда выполняются с той или иной приблизительностью. Получая задание на разработку алгоритма, мы всегда требуем оговорить допуск, т. е. величину погрешности, которая приемлема для решения данной задачи.
Ряды для синуса и косинуса - знакопеременные. Для таких рядов из теории известно (да это, в принципе, и невооруженным глазом видно), что для любого числа N, если вычислить сумму N первых членов и сумму N+1 первых членов, то эти два значения будут границами, а искомое значение суммы бесконечного ряда будет где-то между ними. Иными словами, если N-ный член ряда меньше оговоренного допуска на погрешность (а каждый следующий член ряда меньше предыдущего, так что такой маленький член нам рано или поздно встретится), то на этом можно остановиться: требуемая точность вычисления результата достигнута.
Ряд для натурального логарифма будет вот такой:

(здесь будет формула для логарифма)

Эту формулу нам пишут на доске преподаватели математики, для которых эта формула - чистая наука, абстракция. А преподаватели программирования не хотят думать о сложном в жизни и советуют нам вычислять функции так, как учат на высшей математике… Если у такого препода спросить: «Зачем ты учишь молодежь плохому?», то ответ будет: «Да какая разница? Мы же не боевую программу пишем, пусть учатся просто составлять алгоритм по формулам». Я с такой позицией согласиться не могу. Как я уже говорил выше (и не устану повторять), молодежь надо учить не просто переводу алгоритмов на язык программирования, а надо учить МЫШЛЕНИЮ.
Этот ряд вообще по жизни сходится достаточно медленно. Он не знакопеременный, значит то, что было только что сказано про синус и косинус, к логарифму не относится. Если мы будем считать этот ряд член за членом, то сумма будет все время возрастать. Сколько бы членов мы ни считали, все равно останется бесконечное количество. В один прекрасный момент очередной член окажется меньше самого младшего разряда нашего машинного слова. Как говорят специалисты: «выйдет за пределы разрядной сетки». На этом вычисления волей-неволей придется остановить, потому что результат просто не будет меняться. Каждый следующий член ряда будет еще меньше, но их много - чему будет равна их сумма? Остается только гадать. А это значит, что у нас нет вообще никаких гарантий, что в полученном результате есть хоть сколько-то верных значащих цифр! Чем это может быть чревато, например, при запуске ракеты - догадайтесь сами.
Допустим, у нас под рукой мощный компьютер, способный «переваривать» 80-разрядные числа с плавающей точкой. Суммирование ряда на такой машине будет однозначно не быстрым… Но спасет ли это нас?
К чему мы пришли? Похоже, к тому, что разложение в ряд, которое так хорошо работало для синуса, применительно к логарифму более чем просто неудачно и некрасиво - это НЕГОДНЫЙ МЕТОД. С точки зрения чистой науки негодных методов не бывает: у нас есть формула Тейлора - значит надо ее рассмотреть на уроках. Но программирование - это не совсем наука - это инженерная работа…
Вдумчивый читатель, вероятно, уже догадывается, к чему я клоню: к поразрядному взвешиванию. Ага, наш логарифм - это Fbad, а обратная ему функция Fgood - это возведение в степень. Великолепно! Напишем на языке типа Фортрана:

TRY=ЕXP(GIRI)

где TRY - пробное значение, которое мы хотим подогнать к исходному числу, ЕXP - возведение числа Непера (e) в степень, GIRI - общий «вес гирь на чаше весов». Так может написать студент-программист, и пожалуй, даже может получить за это хорошую оценку… Но давайте как следует подумаем, что мы написали. Операция возведения в степень - довольно паршивая: медленная. А при поразрядном взвешивании ее придется повторять энное количество раз. В общем, красиво не получается.
А теперь давайте для полноты картины представим, что 80-разрядного компьютера с плавающей точкой у нас нет, а есть примитивный 8-разрядный микроконтроллер, и все это нужно сделать на нем.
– Да пОлно, какой микроконтроллер??? Сам только что говорил о 80-разрядных числах с плавающей точкой!
– Говорил. Я вам также говорил, что в учебнике высшей математики описаны задачи, для решения которых 80-разрядные числа действительно необходимы. Но это не наш сегодняшний случай: вычисление логарифмов к таким задачам не относится. Сегодня я вам намерен показать, что подобные (и многие другие) вычисления вполне по плечу даже самым примитивным машинкам.
Где в микроконтроллерной технике могут потребоваться логарифмы? Например там, где мы имеем дело с радиоволнами или со звуком. Логарифмические шкалы часто используют для настройки радиоприемников и радиопередатчиков. Измерение затухания радиоволн или интенсивности звуков также часто сопряжены с логарифмированием. Всевозможные стенды для испытания радиотехнических и акустических приборов очень здОрово строятся на микроконтроллерах, так что логарифмирование может потребоваться. Скажу больше: поскольку человеческие глаза и уши имеют логарифмическую чувствительность, то любые измерения-испытания, связанные с видимостью/слышимостью различных предметов для человека, без логарифмирования не обходятся.
Для упрощения задачи (мы ведь сейчас не пишем боевую программу - мы просто теоретизируем!) давайте считать, что исходное число, от которого берем логарифм, - натуральное, в размере одного байта. Это абсолютно типичная ситуация для микроконтроллерной техники (допустим, мы хотим измерить уровень звука, поступающего на микрофон). Логарифм мы выше рассматривали натуральный, а теперь будем брать двоичный:
Y=LB(X)=LOG2(X)
Нам ведь, по большому счету, все равно, какой логарифм вычислять: все логарифмы пропорциональны. Если нам скажут: «хотим стопроцентный натуральный», просто умножим полученное нами значение двоичного логарифма на известный коэффициент. Значение логарифма будем представлять как число с фиксированной точкой: по одному байту на целую часть и на дробную. Логарифм нуля не существует, логарифм 1 - всегда 0, логарифм 2 - равен 1… Все значения логарифма будут положительные, и это нам на руку. Целую часть двоичного логарифма найти очень легко: нужно найти в исходном числе старшую единицу, определить, в каком она разряде, и из номера разряда вычесть 1. Пример. Пусть исходное число 61=0b00111101 - старшая единица в шестом разряде, значит целая часть логарифма 5 (запись типа 0b00111101 всем, надеюсь, уже понятна?). Проверим: 25=32 и это меньше нашего исходного числа, а 26=64 - это перелет, значит целая часть логарифма меньше 6, то есть все-таки 5. Итак, целая часть требуемого результата определяется легко, и мы сейчас про нее забудем: она нам неинтересна. Сосредоточимся на дробной части. Если уж говорить совсем строго, то вычисление логарифма ВСЕГДА следует разделить на две части: вычислив целую часть, сразу от нее избавиться, чтобы осталась мантисса исходного числа (находящаяся в интервале значений 1⇐Mx<2 и отличающаяся от исходного числа X на целую степень двух), а для нее уже отдельным этапом вычислить мантиссу логарифма, величина которой будет в диапазоне от 0⇐My<1 - это уже совершенно нормальное дробное число с фиксированной точкой.
Мы договорились, что логарифм - это Fbad(X)=LB(X), а обратная ему функция Fgood(X)=2X. То есть при каждом взвешивании нам нужно вычислить 2GIRI, где GIRI - опять-таки «общий вес гирь». Очередная гиря, которую мы сейчас должны поставить на весы, - 0.5, при следующем взвешивании будет 0.25 и т. д. Но как возвести 2 в дробную степень? Допустим, на некотором этапе нам потребуется вычислить 20.75 - что это вообще такое, с чем его едят?
Очевидно, 20.75 = 20.5 * 20.25
А что такое 20.5? Очевидно это квадратный корень из 2 - его мы уже умеем вычислять. А 20.25 - это 21/4, т. е. корень четвертой степени из 2, он же корень из корня из 2…
Поскольку от нас требуют мантиссу логарифма размером в байт, то всего нам нужно будет выполнить 8 «взвешиваний», и понадобится для этого 8 «гирь». Но, в отличие от того как было при извлечении корня, гири потребуются хитрые: самая большая будет иметь «вес», равный корню из 2, и остальные соответственно тому что было сказано выше. Все они будут иметь целую часть, равную 1, и дробную - каждая свою. Веса гирь запишем в табличку из 8 ячеек, причем целую единицу в эту табличку можно не записывать - надо будет только не забыть ее при умножении, а в табличку занести только дробные части. Тогда для ее хранения нам потребуется всего 8 байт - мизер даже для совсем простого микроконтроллера. Вычислить эти значения нужно будет один раз при запуске нашей программы. А поскольку мы говорим о микроконтроллере, то в нашем распоряжении имеется EEPROM - почему бы не вычислить все «веса гирь» один раз с использованием вспомогательной программы и «зашить» их в EEPROM раз и навсегда?
Ради спортивного интереса я вычислил значения первых шести «гирь» (только дробные части!). Запишем как на языке ассемблера:

VESGIRI db 0b01101010     ;2 ^ 1/2 = корень из 2
        db 0b00110000     ;2 ^ 1/4 = 0.189
        db 0b00010111     ;2 ^ 1/8 = 0.0905
        db 0b00001011     ;2 ^ 1/16 = 0.0443
        db 0b00000101     ;2 ^ 1/32 = 0.0219
        db 0b00000011     ;2 ^ 1/64 = 0.0109

Обратите внимание на знак ^ - это символ возведения в степень, который используется в некоторых языках программирования (хотя и не во всех, но всем действующим программистам он понятен). Здесь я использую этот знак в комментариях, т. е. только для того, чтобы программа была понятна людям.
При «взвешивании» веса гирь придется не складывать, а умножать. В природе таких весов не существует, но мы можем их смоделировать. Разумеется, мы не будем при каждом «взвешивании» перемножать веса всех гирь - будем умножать результат предыдущего взвешивания на вес той гири, которую ставим сейчас на весы. Здесь есть подвох: «младшие» гири будут иметь очень маленький вес, не выражающийся в масштабе одного байта, да их еще придется умножать, а если умножать маленькое на маленькое, получим совсем маленькое… Значит полный байт дробной части логарифма мы не получим, придется или торговаться насчет допуска, или хранить каждую «гирю» не в одном байте, а в двух. Сам же процесс взвешивания сводится, по большому счету, к единственной операции умножения. Правда, умножение чисел с дробной частью на 8-разрядной машинке, особенно если умножать двухбайтные числа - задача нетривиальная. Готовой команды для этого мы не найдем (а есть микроконтроллеры, которые вообще умножением не владеют), значит нам придется написать процедуру из нескольких команд, возможно около 10. Надеюсь вы мне поверите, что ничего сверхъестественного в этом нет, хотя в принципе это серьезный повод задуматься о микроконтроллере с бОльшей разрядностью.

Какие бывают программы

Программы прикладные и системные. Прикладная программа (в переводных с английского книгах часто называемая просто приложением, англ. application) предназначена для решения некоторой жизненной задачи (деловой или игровой). Однако такие программы для больших компьютеров строятся так, что не могут обойтись без системных программ, которые обеспечивают им «комфортную среду обитания». Соотношение между прикладными и системными программами примерно такое же, как на железной дороге соотношение между вагонами и паровозами.
Операционная система (ОС) - программная принадлежность больших компьютеров, оправдывающая свое существование тем, что обеспечивает «уживаемость» множества прикладных программ на одном компьютере. Минимальный набор функций ОС:
* Организация хранения различных программ, данных для их решения и результатов их работы в виде файловой системы;
* Прием от пользователя команд на решение нужных ему задач и вызов соответствующих программ для выполнения этих команд;
* Организация попеременного, а при необходимости и одновременного выполнения различных программ с распределением ресурсов и устранением конфликтов;
* Обеспечение программам доступа к устройствам ввода-вывода;
* Установка и удаление прикладных программ.
«Большой» компьютер немыслим без операционной системы, но на микроконтроллерах ее обычно нет.
Операционная система представляет собой сложное техническое изделие в составе следующих важнейших частей.
Ядро ОС - это наш системный шеф-повар, который постоянно находится на своей «кухне» в полностью или почти невидимом для нас состоянии, владеет определенными профессиональными секретами, знает, где у него мясо и где картошка, где кастрюли и где плита, и выполняет наши заказы, которые мы ему передаем в виде системных вызовов.
Оболочка - это наш системный официант, которому мы непосредственно отдаем «заказы» (команды). Название «оболочка» отражает тот факт, что пользователь не имеет дела непосредственно с ядром, а имеет дело с оболочкой, и ядро как бы скрыто от пользователя оболочкой.
Утилиты (англ. utilities - «полезняшки») - инструмент и принадлежности, которые не решают прикладных задач, но порой требуются для обслуживания компьютера: настройки и модернизации, поиска и устранения неисправностей, обзора обстановки и т. д. Подобно тому как грамотный автомобилист всегда возит с собой домкрат, насос, буксирный «галстук» и бензошланг, как на корабле обязательно есть шлюпки, спасательные круги, пластырь для заделки пробоин и куча всякого другого аварийно-спасательного имущества, так и грамотный компьютерщик имеет под рукой определенный набор утилит и при необходимости пользуется ими.
Операционная система - сложное программное изделие. На больших компьютерах она «съедает» определенную долю ресурсов компьютера, прежде всего место в памяти и часть времени работы процессора. Современные операционные системы чаще всего весьма «прожорливы» и могут работать только на мощных компьютерах. Если попытаться эксплуатировать такую систему на компьютере с недостаточными ресурсами, то она будет, как минимум, «тормозить», неизбежно заставляя тормозить и прикладные программы, а в худшем случае вообще не сможет работать.
На микроконтроллерах операционных систем чаще всего не бывает. В лучшем случае на микроконтроллере имеется загрузчик - небольшая программа, «зашитая» во flash-память и решающая только одну задачу из тех, которые выше упомянуты для операционной системы: установку прикладной программы. Микроконтроллер и его загрузчик строятся так, чтобы выполнять одну-единственную прикладную программу многократно в течение длительного времени (иногда - в течение всего срока службы микроконтроллера). Прикладная программа для микроконтроллера называется скетч (англ. sketch - рисунок, набросок). Скетч пишется так, как будто ему доступны все ресурсы машины, но и на помощь операционной системы, например при вводе-выводе данных на периферийные устройства, расссчитывать не приходится.
Операция по установке скетча на микроконтроллер с помощью загрузчика называется зашивкой или заливкой.
Прошивки - это программные принадлежности к тем или иным компьютерным «железякам», обеспечивающие им хотя бы минимальную «жизнеспособность». Чаще всего прошивка «зашивается» в свое устройство на заводе-изготовителе намертво (или с возможностью замены (перепрошивки) при необходимости), но бывают и такие внешние устройства, которые в магазинах продаются без прошивок, а прошивку приходится приобретать отдельно (обычно искать в интернете и скачивать). Это типично, например, для устройств Wi-Fi.
Специализированные компьютеры (например, медицинские диагностические приборы) и сложные гаджеты типа навигашек имеют объемистые и функционально богатые прошивки, по принципу действия похожие на операционные системы, а зачастую и состоящие на 3/4 и более из «запчастей» от операционных систем. Чем такая прошивка отличается от полнопрофильной ОС? По большому счету, отсутствием функции установки прикладных программ.
Слово «прошивка» используется в двух значениях: как собственно программное изделие и как техническая операция по размещению этого программного изделия в памяти устройства (прибора, аппарата), для которого оно предназначено.
Драйвер - программа, обеспечивающая различным системным и прикладным программам работу с некоторым устройством ввода-вывода. Что общего между прошивками и драйверами и в чем различие?
Прошивка - принадлежность конкретного «железа» и не относится к какой-либо операционной системе, а драйвер является составной частью операционной системы и не может применяться в других ОС. Прошивка в процессе работы устройства находится в нем, в худшем случае ее приходится загружать в устройство один раз при его включении (подключении), после чего про нее можно забыть. Драйвер находится в оперативной памяти компьютера в постоянной готовности к действию, и каждое обращение прикладной программы к устройству производится путем вызова драйвера.
Написание прошивок и драйверов считается (и справедливо) одной из самых сложных работ в программировании, поскольку требует детального понимания работы данной конкретной «железки».
Средства разработки, среда разработки (англ. development environment) - программный инструментарий, близкий к утилитам и обеспечивающий пользователю возможность самостоятельно создавать новые программы.

Технология и инструмент в работе программиста

Определимся со значениями слова программирование. У этого слова значений несколько. Выше мы рассмотрели динамическое программирование как математический метод решения определенных задач. Другое значение: программирование - процесс написания, или точнее разработки, программ. Этим же словом называется и техническая операция закладки (установки, «заливки») программы в компьютер или иное устройство. Для этой операции в ряде случаев нужен специальный прибор - программатор.
Мы уже говорили (и я не устану повторять), что программирование - не развлечение, а инженерная работа. А инженерная работа должна выполняться по технологии.
Технология - совокупность знаний (в т. ч. изложенных в тех или иных нормативных документах) о том, как выполнить некоторую работу с наименьшими затратами и высоким качеством.
Работа по технологии обычно предполагает использование определенного инструмента.
Когда появились первые ЭВМ и программирование только начиналось, программисты составляли непосредственно машинный код. Это так и называлось: программирование в кодах. Программа при такой технологии получалась практически нечитаемой для человека. Это казалось приемлемым, пока создается новая программа «с нуля». Однако по мере развития отрасли все чаще возникала необходимость что-то изменить в программе, написанной когда-то давно (и возможно, другим человеком). Очевидно, это была задача абсолютно нереальная. Так народ пришел к решению писать не сразу машинный код, а исходный текст, который может быть прочитан человеком и, с другой стороны, может быть преобразован в машинный код по известному алгоритму. Первоначально это преобразование приходилось делать вручную. Я еще застал те времена (1980-е годы), когда программирование для микропроцессора серии К580 (единственного доступного нам тогда настоящего микропроцессора) приходилось выполнять именно по такой первобытной технологии. Однако уже в 1950-е годы пришло понимание того, что это преобразование представляет собой абсолютно машинную работу и должно выполняться не человеком, а самим компьютером по программе, которую назвали транслятором (англ. translator - переводчик). Трансляторы бывают: ассемблеры и компиляторы, а также существуют близкие к ним программы - интерпретаторы.
Ниже мы рассмотрим, в чем отличие ассемблера от компилятора, а сейчас остановимся на интерпретаторе. Это программа, которая читает некоторый текст (иногда называемый сценарием или скриптом, англ. script), трактует его содержимое как команды и тут же, «не отходя от кассы», выполняет эти команды. Скрипт может быть написан на любом языке, лишь бы существовал интерпретатор, способный понимать такой язык.
Интерпретатор выполняет команды «на лету», ему нет необходимости записывать их в какой-либо отдельный текст. В отличие от него транслятор, встретив в исходном тексте команду, не выполняет ее сразу, а записывает в свой выходной текст, который, скорее всего, будет нечитаем для человека, а близок к машинному коду. Собственно, в первые десятилетия существования компьютеров это и был самый настоящий машинный код, который можно было сразу или потом загрузить в оперативную память и запустить на выполнение. Пока программы были не очень сложные, такая технология всех устраивала.
Разработка и эксплуатация программ в интерпретационном режиме предполагает существование скрипта и интерпретатора на одном компьютере. Если задачу нужно перенести на другой компьютер, то переносить придется как скрипт, так и интерпретатор. Использование транслятора предполагает разработку программы на том самом компьютере, на котором она будет выполняться, с возможностью передачи готового машинного кода на другие компьютеры. Поскольку машинный код нечитаем для человека, люди, работающие на других компьютерах, будут вынуждены использовать этот машинный код «как есть», без возможности что-то изменить в программе. Для изменений им придется как-то приобретать исходный текст.
Что нам нужно для написания исходного текста? - Очевидно текстовый редактор. В современном компьютерном мире разнообразие текстовых редакторов не поддается счету. Какой выбрать? По большому счету - любой, какой нравится. Только не Word, потому что транслятор требует от нас «чистый» текст, а Word для этого не предназначен - он выдает текст со служебной информацией (о виде и размере шрифта и т. д.) - такой формат представления текста для наших целей непригоден.
По мере развития отрасли программы усложнялись, их исходные тексты росли в объеме. Например, АСУ производством, которую я когда-то разрабатывал, занимала порядка сотни печатных листов. Внесение поправок в такой текст довольно неудобно и хлопотно, поэтому исходные тексты («исходники») больших программ делятся на части, которые могут разрабатываться разными людьми и даже на разных языках (при интерпретационной технологии такая возможность обычно не предусматривается). Каждый файл с исходным текстом транслируется отдельно, в результате образуется соответствующий кусок машинного кода, который снабжается определенной служебной информацией - и получается объектный код. Объектный код составляется в определенном стандарте, принятом в данной операционной системе. Этот стандарт обязателен для любых трансляторов с любых языков.
Построитель задачи - программа, которая «сшивает» машинную программу из множества кусков объектного кода. Обиходное название построителя задач - линкер или линковщик (англ. link - под этим именем эта программа фигурирует практически во всех операционных системах).
«Ее знали только по имени…» - речь идет о программе make. Едва ли кто-нибудь может дать определение, что собой представляет эта программа. Просто make. Это имя известно программистам, работающим (работавшим) в DOS и OS/2, MacOS и UNIX, Linux и Windows. Эта программа - бригадир над трансляторами и линковщиками. Чтобы собрать готовый машинный код из исходных текстов, программист не обращается напрямую к этим программам, а дает просто команду make.
Мы рассмотрели технологию разработки программ, типичную для больших компьютеров. Основная идея этой технологии: для разработки программ можно использовать любой компьютер - нужно лишь оснастить его вышеперечисленным инструментарием. Программы для микроконтроллеров разрабатываются несколько иначе. Микроконтроллер чаще всего не имеет ни монитора, ни клавиатуры, ни текстовых редакторов, без которых написание исходных текстов немыслимо. К тому же приличный транслятор - достаточно сложная программа: микроконтроллеру может просто не хватить емкости памяти для работы транслятора. Поэтому разработка программ для микроконтроллеров обычно выполняется на больших компьютерах, тем более что на них обычно имеется весь необходимый инструментарий. Если же большой компьютер программно несовместим с микроконтроллером, то приходится создавать специальные инструменты: кросс-ассемблеры и кросс-компиляторы. Иногда в программировании микроконтроллеров используют симуляторы и эмуляторы - программы, «играющие роль» микроконтроллера, изображающие его действие на большом компьютере. В ряде случаев они позволяют создать программу для микроконтроллера в отсутствие его самого, но ждать чудес от таких программ я все-таки никому не советую.
Development environment - «среда разработки» - не что иное как набор вышеперечисленных программ, хорошо «подогнанных» друг к другу, создаваемый одной фирмой и поставляемый на рынок как единое изделие. Иногда используется термин Integrated Development environment - IDE (не путать с одним из типов винчестеров IDE!). Например для микроконтроллеров Atmel известна среда разработки AVRStudio, хотя Ю. Ревич в своей книге «Практическое программирование микроконтроллеров Atmel AVR на языке ассемблера» критикует этот продукт.

Языки программирования: язык ассемблера и языки высокого уровня

Программирование в кодах было дело хотя и нудное и трудоемкое, но имело важное преимущество: программист «держал в руках» каждую команду, что позволяло создавать продукт высокого качества: не допускать лишних действий, оптимизировать «тормозные» места, засекать и устранять аварийные ситуации… Чтобы не терять это преимущество, был создан способ передачи информации - язык, в котором каждая машинная команда представлена буквенно-цифровыми обозначениями, понятными человеку. Например add - сложить, mul - от слова multiply - умножить… В старых книгах можно встретить термин мнемокод (мнемонический, т. е. легко запоминающийся). Для перевода мнемокода в машинный язык была создана программа, которую назвали ассемблер (англ. assembler - сборщик), а язык мнемокодов соответственно стали называть языком ассемблера. Правильно говорить: я программирую на языке ассемблера, но в обиходе чаще говорят просто: программирую на ассемблере.
Программирование на ассемблере сохраняет все преимущества программирования в кодах, но избавляет от основного недостатка: исходный текст на языке ассемблера хотя и выглядит ужасно сложно, но все же может быть прочитан человеком (а если можно прочитать, то отчего бы не попробовать написать?). Тем не менее, ряд недостатков программирования в кодах при этой технологии сохраняется:
* Для работы на ассемблере необходимо достаточно глубокое знание особенностей компьютера, с которым имеем дело - попросту говоря, требуется высокая квалификация и серьезное отношение к работе;
* Программа пишется для конкретной машины и не может быть выполнена на компьютере, имеющем архитектурные отличия от того, для которого она предназначена;
* Программисту приходится каждое действие «разжевать и в рот компьютеру положить». Рассмотрим простой пример. Умножим вес некоторого товара на его цену, чтобы получить стоимость. На языке ассемблера некоторого абстрактного компьютера это может выглядеть примерно так:

mov  r0,VES
mul  r0,CENA
mov  STOIM,r0

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

STOIM=VES*CENA

Так появилась идея создать язык программирования высокого уровня.

Краткий исторический обзор языков высокого уровня

Подобные языки - Алгол и Фортран - появились уже в 50-е годы 20-го века, затем в этой отрасли имело место достаточно долгое и сложное развитие. На смену Алголу пришел ПЛ-1 (PL-1), затем появилось множество других языков. «Иных уж нет, а те далече»…
Появление PL-1 поначалу было принято программистами, мягко говоря, прохладно: они думали, что теперь их заставят все прежние программы переписывать на новый язык. Однако этот психологический барьер был преодолен, и новые языки стали создаваться один за другим, как новые сорта тюльпанов. Аналогия с тюльпанами особенно уместна потому, что большинство вновь создаваемых языков не представляло собой ничего принципиально нового.
Фортран (англ. FORmula TRANslation - перевод формул) превосходен как язык математиков и физиков, которые чаще всего сами не являются программистами, но ощущают потребность быстро создавать компактные и понятные коллегам-ученым программы для сложных числовых расчетов. Сейчас он имеет очень ограниченное применение: главным образом там, где от программы требуются учебно-демонстрационные свойства. Основной недостаток Фортрана - его непригодность для решения иных задач, кроме вычислений по формулам.
Кобол - Common Business-Oriented Language - в противоположность Фортрану, предназначен не для математиков и физиков, а для работников финансово-экономической сферы.
Алгол, Кобол и Фортран знаменуют собой древнекомпьютерную цивилизацию. Алгол умер, умерли его сыновья ПЛ-1 и Паскаль, но живо и процветает следующее поколение - языки семейства С. Переход от древности к средневековью в области языков начался чуть раньше, чем в области машин: в 1964 г. появился Бэйсик (англ. BASIC). Программисты моего поколения вспоминают его как кошмар, хотя, если вдуматься, в нем не было ничего такого ужасного. Возвращаюсь к мысли о том, что программа - техническое изделие, а техническим изделиям отнюдь не чужды понятия о красоте. У нас был старый верный Фортран: брутальный, как швейцарский электровоз, и крепкий, как ледокол «Красин». Его раздербанили на запчасти, 80% деталей слегка перекрасили, чтобы создать видимость обновления, еще 10% допилили напильником на коленке для обеспечения работы в интерпретационном режиме, и добавили множество подпорок, подставок и подкладок, обеспечивающих работу на абонентских терминалах. Какой же красоты можно было ожидать от такого изделия? На замену Бэйсику был придуман Фокал, но он тоже не обещал ни чудес, ни революций и в итоге оказался мертворожденным. Несмотря на критику, которой Бэйсик подвергался с «молодости», он пережил несколько реинкарнаций. Однако будущего у него нет.
В 1974 году был создан язык Паскаль, в котором воплотился многолетний опыт эксплуатации Алгола и его потомков, в частности ПЛ-1. Паскаль содержит все нужное, что было в его прототипах, и многое, чего в них не хватало, но не прощает «лишних вольностей». Его правила строги и прозрачны, что придает ему великолепные учебно-боевые свойства. Попросту говоря, изучение Паскаля по плечу даже школьнику, а освоив его однажды, вы сможете работать на нем всю жизнь, не испытывая нужды ни в чем другом. Почему он оказался заброшен и забыт?
Паскаль - не единственный потомок Алгола: даже если считать только мало-мальски жизнеспособные, то все равно получится довольно много. Остановлюсь на языке Ада. Он был создан в 1979-1980 годах в США и сразу стал стандартным языком в Пентагоне и НАСА. Предполагалось, что он станет общемировым, но этого не произошло: даже в гражданских ведомствах США он не нашел признания. В России этот язык практически неизвестен, хотя книжка (переводная с английского, разумеется) мне в руки попадалась.
Язык C (СИ) - не что иное как основательно испорченный Паскаль. Кто его испортил - задача из области уголовного следствия, я же сейчас остановлюсь на мотивах этого преступления. У тех людей, которые в 1970-е годы в гаражно-коленочных условиях создавали компьютер VAX и операционную систему UNIX, не было не только нормального экранного монитора, но даже и нормального принтера. Был телетайп - буквопечатающий телеграфный аппарат, который теперь можно увидеть разве что в музее. Он выводил данные на узкую бумажную ленту. Ленты вечно не хватало, и была она недешева, значит приходилось экономить. И вот люди решили придумать такой язык, чтобы каждое действие записывалось максимально коротко. В качестве прототипа выбрали Паскаль, что в общем-то вполне логично. Нос вытащили - хвост увяз: исходный текст стал трудно читаемым, а это не замедлило сказаться на трудоемкости разработки больших программ. Но тогда об этой стороне дела как-то не подумали, а потом, когда их разработка «пошла» и люди обзавелись мониторами, оказалось, что на новоизобретенном языке написано уже очень много, и возврат к настоящему Паскалю сочли нецелесообразным. Так началось триумфальное шествие языка C по планете и ее окрестностям. В последующие годы из языка C выросло целое семейство языков, как универсальных (C++, C#), так и специализированных (PHP, Java/JavaScript). Языки этого семейства в основном используются сейчас, хотя не представляют ничего революционного по сравнению с языками 70-х годов XX века, так что говорить о новой или новейшей эпохе применительно к языкам программирования не приходится. Это весьма печальная ситуация. Такого больше нет нигде в мире, ни в одной области человеческой деятельности.

Ассемблер vs языки высокого уровня

Рассмотрим общие черты всех упомянутых языков.
Запись типа STOIM=VES*CENA представляет собой абстракцию, не ориентированную на какой-либо конкретный компьютер. Программист на таком языке как бы «поднимается над полем боя», отсюда и название «язык высокого уровня». (Соответственно ассемблер - язык низкого уровня. У нас, как у шахтеров: чем ниже уровень, тем выше крутизна). Программисту не обязательно знать, «что там внутри», он даже может не задумываться, для какого компьютера он сейчас пишет. Стало быть, язык высокого уровня обладает кроссплатформенностью: написав на нем программу, мы потом сможем эксплуатировать ее на любом компьютере, не только нынешнем, но и будущем. Все, что для этого требуется, - это компилятор - программа, преобразующая исходный текст в машинный код. По сути, аналог ассемблера.
Казалось бы, языки высокого уровня во всем превосходят ассемблер?
Казалось бы, а оказалось, что все не так просто.
Во-первых, давайте опять-таки вспомним, что ЯВУ - это абстракция, а компьютер всегда конкретен. Мы написали исходный текст, а затем он должен быть переведен на машинный язык. Компилятор работает по известному ему алгоритму: читает исходный текст строка за строкой и преобразует каждую в некоторую последовательность машинных команд. Образующийся в результате этого машинный код всегда неоптимален: в нем много лишних действий. Например, вычисленное значение помещают в оперативную память, а для последующих вычислений читают его оттуда, хотя оно сохранилось в одном из регистров процессора. Часто компилятор «не владеет» тонкими возможностями компьютера, делает «в лоб» то, что хороший ассемблерщик сделал бы по-хитрому… Вот яркий пример. Вышеупомянутый алгоритм извлечения квадратного корня поразрядным взвешиванием на языке высокого уровня вообще невозможно записать (ну можно, конечно, постараться, но получится путано и коряво, и главное: все преимущества ассемблера с точки зрения быстродействия будут потеряны). Результат: программы, написанные на ЯВУ, неизбежно получаются более объемистыми и более «тормозными», чем аналогичные программы, написанные на ассемблере. Это объективный фактор. А есть и субъективный.
С вашего позволения, зайду несколько издалека. Как вы думаете, можно стать хорошим летчиком, не зная устройство самолета? Или, может быть, можно стать хорошим моряком, не зная навигации и лоции, гидрологии и метеорологии? А можно ли стать хорошим программистом, не зная устройства компьютера? Изучение языка C в том виде, как это делается в наших институтах, создает иллюзию, что можно… Что имеем в сухом остатке на сегодня? Язык, который каких-то 20-30 лет назад был языком мастеров и асов, стал языком халтурщиков и шабашников. Когда множество таких халтурщиков и шабашников оказывается на бирже труда, они друг другу только мешают. А руководитель фирмы-работонедателя (не важно, специализированная это программная фирма или просто завод) делает на этом свою игру. Вместо того чтобы искать серьезного ассемблерщика, а потом его холить и лелеять, он набирает дюжину недопрограммистов, любого из которых потом можно будет уволить без тяжких последствий для всего дела, и платит им соответствующую зарплату. Такие руководители не помнят дедушку Суворова с его наукой побеждать («воюй не числом, а умением») - они, наоборот, ставку делают на численное превосходство: «на биржу труда только свистни - сразу 30 человек в шляпах прибегут!» Но чтобы 30 человек в шляпах могли за какое-то вменяемое время создать приличный продукт, им нужен руководитель, который составит план работы, распределит работу между исполнителями и затем будет координировать их усилия. Найти такого руководителя среди C-программистов еще труднее, чем хорошего ассемблерщика! А без него будет много суетни, беготни, болтовни и возни, а дело никуда не продвинется. Если же вместо руководителя будет начальник, знающий в жизни две фразы: «идите работайте» и «ты уволен», то весь проект, скорее всего, закончится крахом.
Результат: сроки разработки программ затягиваются, затраты растут, страдает и качество продкута: программы очень хлопотны и затратны в эксплуатации, «тормозят», часто ошибаются, а то и просто не выполняют требуемые функции…
Часто можно услышать: «Программирование на ассемблере - это ужасно медленный процесс». Это миф. Надо признать, что некоторую историческую почву он под собой имеет, но все равно миф. Во времена Фортрана, действительно, программирование на Фортране обеспечивало скорость разработки в несколько раз больше, чем на ассемблере. Теоретически, при прочих равных условиях… Но с тех пор многое изменилось: и компьютеры, и задачи, и языки, и программисты. Да и сам ассемблер теперь другой.
Представим, что есть два программиста: один на ассемблере, другой на C, и мы посадили их в одной комнате друг напротив друга и дали задание разработать аналогичные программы (достаточно большие и сложные). Теоретически программист на сях имеет преимущество в скорости. Но это теоретически и при прочих равных условиях, а в реальной жизни прочие условия почти всегда неравны. Дело опять-таки в квалификации.
К чему я это все? - К тому, что хотя программирование на языках высокого уровня обещает некоторые преимущества перед программированием на ассемблере, но эти преимущества в действительности не так велики, как думает большинство в программном сообществе.

Что легче изучить: ассемблер или ЯВУ?

Часто можно услышать: ассемблеру очень легко научиться. С другой стороны, книга с названием вроде «Основы программирования на языке С» может иметь объем в тысячу страниц, и это только основы! На самом деле, как обычно в этом мире, не все так просто.
Язык ассемблера как таковой, действительно, изучить не представляет сложности. Но это не та вещь, которую можно изучить один раз и больше не изучать ничего. Как уже говорилось выше, программисту-ассемблерщику необходимо глубокое знание «кухни» той машины, для которой пишем. Машин разных на свете много, каждый год появляется что-нибудь новое, так что учиться приходится постоянно.

Ассемблер и С как инструменты

И вновь возвращаюсь к мысли, что программирование - не развлечение, а инженерная работа, а разные языки программирования в этой работе - инструменты.
Правило на все времена и для всех народов: каждый инструмент хорош для своей задачи. Есть алгоритмы, которые на ЯВУ реализуются с большим трудом, криво и путано - их имеет смысл писать на ассемблере. С другой стороны, есть целые большие пласты задач, которые никто никогда на ассемблере не пишет: это программы интернет-сайтов (там используются специализированные ЯВУ типа PHP и Java), различные программы в области экономики и бизнеса, основанные на реляционных базах данных (там тоже специализированные языки типа Клиппера, а также прикладные системы типа Microsoft Access, реализующие технологию «программирование без программирования»). Этот список можно продолжить.
Как выбрать подходящий язык для решения конкретной задачи? Единого рецепта нет. К тому же нельзя пренебрегать и субъективным фактором: каждый серьезный программист имеет свои предпочтения, далеко не всегда совпадающие с предпочтениями других людей. И еще. Выше мы обсудили трансляторы, объектные коды, построитель задач… Смысл этого всего в том, что большую сложную программу теперь не обязательно писать полностью на одном каком-то языке: ее можно разделить на части и для каждой части выбрать наиболее подходящий язык. Конечно, было бы совершенно неправильно, чтобы в программистском коллективе из 10 человек каждый работал бы на своем языке. Но писать основную программу на ЯВУ и делать в ней какие-то вставки на ассемблере с целью создать компактное и быстро работающее изделие - вполне хорошая практика.

igor/programmirovanie_shkolnikam.1522239705.txt.bz2 · Последнее изменение: 2018/03/28 15:21 — igor