- •Предисловие
- •Введение
- •1Архитектура эвм
- •1.1 Биты и их хранение
- •1.1.1Вентили и триггеры
- •1.1.2Другие способы хранения битов
- •1.1.3Шестнадцатеричная система счисления
- •1.2 Оперативная память
- •1.2.1Структура памяти
- •1.2.2Измерение емкости памяти
- •1.3 Устройства хранения данных
- •1.3.1Магнитные диски
- •1.3.2Компакт-диски
- •1.3.3Магнитные ленты
- •1.3.4Хранение и поиск файлов
- •1.4 Представление информации в виде двоичного кода
- •1.4.1Представление текста
- •1.4.2Американский национальный институт стандартов
- •1.4.3Iso - международная организация по стандартизации
- •1.4.4Представление числовых значений
- •1.4.5Представление изображений
- •1.4.6Представление звука
- •1.5 Двоичная система счисления
- •1.5.1Альтернатива двоичной системе счисления
- •1.5.2Дроби в двоичной системе счисления
- •1.5.3Аналоговые и цифровые устройства
- •1.6 Хранение целых чисел
- •1.6.1Представление в двоичном дополнительном коде
- •1.6.2Сложение в двоичном дополнительном коде
- •1.6.3Проблема переполнения
- •1.6.4Представление с избытком
- •1.7 Хранение дробей
- •1.7.1Представление с плавающей точкой
- •1.7.2Ошибка усечения
- •1.8 Сжатие данных
- •1.8.1Общие методы сжатия данных
- •1.8.2Сжатие звука
- •1.8.3Сжатие изображений
- •1.9 Ошибки передачи данных
- •1.9.1Контрольный разряд четности
- •1.9.2Коды с исправлением ошибок
- •2Манипулирование данными
- •2.1 Архитектура эвм
- •2.1.1Сложение двух чисел, хранящихся в оперативной памяти
- •2.1.2Кто и что изобрел?
- •2.2 Машинный язык
- •2.2.1Система команд
- •2.2.2Кэш-память
- •2.2.3Арифметико-логические команды
- •2.2.4Команды управления
- •2.2.5Деление двух значений, хранящихся в памяти
- •2.3 Выполнение программы
- •2.3.1Пример выполнения программы
- •2.3.2Команды переменной длины
- •2.3.3Программы и данные
- •2.4 Арифметические и логические операции
- •2.4.1Логические операции
- •2.4.2Сравнение вычислительной мощности эвм
- •2.4.3Операции сдвига
- •2.4.4Арифметические операции
- •2.5 Связь с другими устройствами
- •2.5.1Связь через контроллер
- •2.5.2Строение шины
- •2.5.3Скорость передачи данных
- •2.6 Другие архитектуры
- •2.6.1Конвейерная обработка
- •3Операционные системы и организация сетей
- •3.13.1. Эволюция операционных систем
- •3.1.1Однопроцессорные системы
- •3.1.2Многопроцессорные системы
- •3.2 Архитектура операционной системы
- •3.2.1Программное обеспечение
- •3.2.2Полезное единообразие или вредная монополия?
- •3.2.3Компоненты операционной системы
- •3.2.4Операционная система linux
- •3.2.5Начало работы операционной системы
- •3.3 Координирование действий машины
- •3.3.1Понятие процесса
- •3.3.2Управление процессами
- •3.3.3Модель «клиент-сервер»
- •3.4 Обработка конкуренции между процессами
- •3.4.1Семафор
- •3.4.2Взаимная блокировка
- •3.5 Сети
- •3.5.1Основы организации сетей
- •3.5.2Интернет
- •3.5.3Топология сети Интернет
- •3.5.4Система адресов Интернета
- •3.5.5Электронная почта
- •3.5.6Всемирная паутина
- •3.6 Сетевые протоколы
- •3.6.1Управление правом отправки сообщений
- •3.6.2Сеть ethernet
- •3.6.3Javascript, апплеты, cgi и сервлеты
- •3.6.4Многоуровневый принцип программного обеспечения Интернета
- •3.6.5Комплект протоколов tcp/ip
- •3.6.6Протоколы рорз и imap
- •3.7 Безопасность
- •3.7.1Протокол защищенных сокетов
- •3.7.2Группа компьютерной «скорой помощи»
- •4Алгоритмы
- •4.1 Понятие алгоритма
- •4.1.1Предварительные замечания
- •4.1.2Формальное определение алгоритма
- •4.1.3Определение алгоритма
- •4.1.4Абстрактная природа алгоритма
- •4.2 Представление алгоритма
- •4.2.1Примитивы
- •4.2.2Псевдокод
- •4.3 Создание алгоритма
- •4.3.1Искусство решения задач
- •4.3.2Итеративные структуры в музыке
- •4.3.3Первый шаг в решении задачи
- •4.4 Итеративные структуры
- •4.4.1Алгоритм последовательного поиска
- •4.4.2Управление циклом
- •4.4.3Алгоритм сортировки методом вставок
- •4.5Рекурсивные структуры
- •4.5.1Поиск и сортировка
- •4.5.2Алгоритм двоичного поиска
- •4.5.3Управление рекурсивными структурами
- •4.6 Эффективность и правильность
- •4.6.1Эффективность алгоритма
- •4.6.2Проверка правильности программного обеспечения
- •4.6.3По ту сторону проверки правильности программ
- •5Языки программирования
- •5.1 Исторический обзор
- •5.1.1Ранние поколения
- •5.1.2Интерплатформенное программное обеспечение
- •5.1.3Независимость от машины
- •5.1.4Парадигмы программирования
- •5.2 Основные понятия традиционного программирования
- •5.2.1Культуры языков программирования
- •5.2.2Переменные и типы данных
- •5.2.3Структуры данных
- •5.2.4Константы и литералы
- •5.2.5Операторы присваивания
- •5.2.6Управляющие операторы
- •5.2.7Комментарии
- •5.3 Процедурные единицы
- •5.3.1Процедуры
- •5.3.2Событийно-управляемые программные системы
- •5.3.3Параметры
- •5.3.4Функции
- •5.3.5Операторы ввода-вывода
- •5.4 Реализация языка программирования
- •5.4.1Процесс трансляции программы
- •5.4.2Реализация java
- •5.4.3Компоновка и загрузка
- •5.4.4Пакеты разработки программного обеспечения
- •5.5 Объектно-ориентированное программирование
- •5.5.1Классы и объекты
- •5.5.3Конструкторы
- •5.5.4Дополнительные возможности
- •5.6 Параллельные операции
- •5.7 Декларативное программирование
- •5.7.1Логическая дедукция
- •5.7.2Язык программирования Prolog
- •6Разработка программного обеспечения
- •6.1 Разработка программного обеспечения
- •6.1.1Ассоциация по вычислительной технике
- •6.1.2Институт инженеров по электротехнике и электронике
- •6.2 Жизненный цикл программы
- •6.2.1Цикл как единое целое
- •6.2.2Разработка программного обеспечения на практике
- •6.2.3Этапы разработки программного обеспечения
- •6.2.4Анализ
- •6.2.5Проектирование
- •6.2.6Реализация
- •6.2.7Тестирование
- •6.2.8Современные тенденции
- •6.3 Модульность
- •6.3.1Модульная реализация программы
- •6.3.2Связь модулей системы
- •6.3.3Связность модуля
- •6.4 Методики проектирования
- •6.4.1Нисходящее и восходящее проектирование
- •6.4.2Модели проектирования
- •6.4.3Разработка открытых программных продуктов
- •6.5 Инструменты проектирования
- •6.6 Тестирование
- •6.7 Документация
- •6.8 Право собственности на программное обеспечение и ответственность
- •Часть 3 организация данных
- •7Структуры данных
- •7.1 Основы структур данных
- •7.1.1Опять абстракция
- •7.1.2Статические и динамические структуры
- •7.1.3Указатели
- •7.2 Массивы
- •7.3 Списки
- •7.3.1Непрерывные списки
- •7.3.2Реализация непрерывных списков
- •7.3.3Связные списки
- •7.3.4Поддержка абстрактного списка
- •7.4 Стеки
- •7.4.1Откат
- •7.4.2Реализация стека
- •7.5 Очереди
- •7.5.1Проблема указателей
- •7.6 Деревья
- •7.6.1Реализация дерева
- •7.6.2Сбор мусора
- •7.6.3Пакет бинарного дерева
- •7.7 Пользовательские типы данных
- •7.7.1Пользовательские типы
- •7.7.2Классы
- •7.7.3Описательное и процедурное знание
- •7.7.4Стандартная библиотека шаблонов
- •7.8 Указатели в машинном языке
- •8Файловые структуры
- •8.1 Роль операционной системы
- •8.1.1Таблицы размещения файлов
- •8.2 Последовательные файлы
- •8.2.1Обработка последовательных файлов
- •8.2.2Консорциум производителей программного обеспечения для www
- •8.2.3Текстовые файлы
- •8.2.4Текстовые и двоичные файлы
- •8.2.5Вопросы программирования
- •8.2.6Семантическая сеть
- •8.3 Индексация
- •8.3.1Основные положения индексации
- •8.3.2Вопросы программирования
- •8.3.3Расположение файлов на дисках
- •8.4 Хэширование
- •8.4.1Хэш-система
- •8.4.2Проблемы распределения
- •8.4.3Аутентификация посредством хэширования
- •8.4.4Вопросы программирования
- •9Структуры баз данных
- •9.1 Общие вопросы
- •9.2 Многоуровневый подход к реализации базы данных
- •9.2.1Система управления базой данных
- •9.2.2Распределенные базы данных
- •9.2.3Модели баз данных
- •9.3 Реляционная модель баз данных
- •9.3.1Вопросы реляционного проектирования
- •9.3.2Системы баз данных для персональных компьютеров
- •9.3.3Хронологические базы данных
- •9.3.4Реляционные операции
- •9.3.5Вопросы реализации
- •9.3.6Язык sql
- •9.4 Объектно-ориентированные базы данных
- •9.5 Поддержка целостности базы данных
- •9.5.1Пространственные базы данных
- •9.5.2Протоколы фиксации/отката изменений
- •9.5.3Блокировка
- •9.6 Воздействие технологий баз данных на общество
- •10Искусственный интеллект
- •10.1 Интеллект и машины
- •10.1.1Конечный результат или имитация
- •10.1.2Истоки искусственного интеллекта
- •10.1.3Тест Тьюринга
- •10.1.4Машина для решения головоломки из восьми фишек
- •10.2 Распознавание образов
- •10.3 Мышление
- •10.3.1Продукционные системы
- •10.3.2Интеллект, основанный на поведении
- •10.3.3Деревья поиска
- •10.3.4Эвристика
- •10.4 Искусственные нейронные сети
- •10.4.1Основные свойства
- •10.4.2Приложение теории
- •10.4.3Ассоциативная память
- •10.5 Генетические алгоритмы
- •10.6 Прочие области исследования
- •10.6.1Обработка лингвистической информации
- •10.6.2Рекурсия в естественных языках
- •10.6.3Роботы
- •10.6.4Системы баз данных
- •10.6.5Экспертные системы
- •10.7 Обдумывая последствия
- •10.7.1Сильный искусственный интеллект против слабого
- •11Теория вычислений
- •11.1 Функции и их вычисление
- •11.1.1Теория рекурсивных функций
- •11.2 Машины Тьюринга
- •11.2.1Основы машины Тьюринга
- •11.2.2Истоки машины Тьюринга
- •11.2.3Тезис Черча-Тьюринга
- •11.3 Универсальные языки программирования
- •11.3.1Скелетный язык
- •11.3.2Существуют ли инопланетяне?
- •11.3.3Универсальность скелетного языка
- •11.4 Невычислимая функция
- •11.4.1Проблема останова
- •11.4.2Неразрешимость проблемы останова
- •11.5 Сложность задач
- •11.5.1Измерение сложности задачи
- •11.5.2Пространственная сложность
- •11.5.3Полиномиальные и не полиномиальные задачи
- •11.5.5Детерминированность против недетерминированности
- •11.6Шифрование с открытым ключом
- •11.6.1Шифрование при помощи задачи о ранце
- •11.6.2Популярные системы шифрования
- •11.6.3Модульная арифметика
- •11.6.4Обратно к шифрованию
11.3.2Существуют ли инопланетяне?
Студенты редко удивляются, когда им говорят о существовании задач, которые невозможно решить алгоритмически. Когда же их просят привести пример, они задают вопросы, подобные «Выживет ли человеческая раса через тысячу лет?» или «Существуют ли инопланетяне?». Но что действительно может удивить — так это то, что на такие вопросы можно ответить алгоритмически, и, что еще более удивительно, при помощи очень простых алгоритмов. На каждый из предыдущих вопросов может ответить алгоритм, состоящий из одного шага — «Выдать ответ да» или «Выдать ответ нет». Мы просто не знаем, какой из алгоритмов правильный.
Чтобы разъяснить ситуацию, представим себе все возможные программы на скелетном языке, организованные в длинный список, в начале которого стоят короткие программы, за которым находятся все более длинные. Вопрос, можно ли решить определенную задачу алгоритмически, превращается в вопрос, существует ли в списке программа для решения этой задачи. Это не то же самое, что действительный поиск в списке программы, решающей требуемую задачу. Существует множество проблем, которые решаются программами, место для которых в списке еще не определено. То есть для большого количества алгоритмически решаемых задач алгоритмические решения еще не найдены. Например, для задачи о том, существуют ли инопланетяне.
Каждый из трех операторов присваивания требует изменения содержимого переменной, используемой в операторе. Первый из них позволяет помещать в переменную строку нулей. Его синтаксис:
clear name;
где name — любое имя переменной.
Оставшиеся операторы присваивания являются антиподами:
incr name:
и
deer name:
Здесь name также является любым именем переменной. Первый из этих операторов увеличивает значение указанной переменной на единицу. Термин i ncr (increment) обозначает интерпретацию битовой последовательности как целого двоичного числа и изменение последовательности, чтобы она представляла целое значение на единицу больше. Например, если с переменной Y до выполнения оператора incr Y:
была связана последовательность 101, то после выполнения оператора значение переменной Y представляет последовательность 110. То есть к значению переменной Y была добавлена единица.
В свою очередь, оператор deer (decrement) используется для уменьшения значения указанной переменной на единицу. Исключением является лишь случай, когда значение переменной равно нулю, тогда оператор не изменяет значения. Таким образом, если до выполнения оператора deer Y:
с переменной Y было связано значение 101, то после его выполнения это значение равно 100. Если же значение переменной Y было равно нулю перед выполнением оператора, оно не изменится и останется равным нулю.
В скелетном языке есть только одна управляющая структура, представленная парой операторов while-end. Последовательность операторов while name not 0 do:
end:
(где name — это любое имя переменной) обозначает, что любой оператор или набор операторов между словами while и end выполняется до тех пор, пока значение переменной name не станет равным нулю. Более точно, когда структура while-end появляется во время выполнения программы, значение указанной переменной сначала сравнивается с нулем. Если оно равно нулю, структура пропускается и выполнение продолжается с оператора, следующего за end. Если же значение переменной не равно нулю, выполняется последовательность операторов внутри структуры while-end, и управление возвращается оператору while, после чего снова выполняется сравнение. Обратите внимание, что часть ответственности за управлению еиклом лежит на программисте, который должен явно изменять значение переменной в теле цикла, чтобы избежать бесконечного выполнения цикла. Например, последовательность
incr X:
while X not 0 do;
incr Z; end:
приведет к бесконечному процессу, так как после достижения оператора while значение переменной X никогда не станет нулем. Однако последовательность
clear Z:
while X not 0 do;
incr Z:
deer X: end;
в итоге прекратит выполняться, а переменная Z получит значение, ранее принадлежавшее переменной X.
Обратите внимание, что операторы while и end должны всегда использоваться в паре, причем первым должен идти оператор whi I e. Однако пара операторов while-end может появиться среди инструкций, которые повторяются внутри другой пары while-end. В таком случае разбиение на пары операторов while и end выполняется путем просмотра написанной программы от начала до конца и соотнесения каждого оператора end с ближайшим предшествующим оператором while, для которого пара еще не найдена. Хотя этого не требует синтаксис, мы часто используем отступы для улучшения читаемости подобных структур.
Приведем последний пример. Последовательность инструкций (листинг 11.1) приводит к тому, что произведение значений переменных X и Y присваивается переменной Z, а побочным эффектом программы является изменение значения X, если оно не равно нулю. (Структура while-end, которой управляет переменная W, восстанавливает исходное значение переменной Y.)
Листинг 11.1. Программа на скелетном языке для умножения X на Y
clear Z:
while X not 0 do: clear W:
while Y not 0 do; incr Z; incr W; deer Y: end;
while W not 0 do; incr Y; deer W: end; deer X; end;
Программирование на скелетном языке
Помните, цель нашего знакомства со скелетным языком — исследовать его возможности, а не практическое его применение. Скелетный язык, вероятнее всего, было бы крайне неудобно использовать в реальной ситуации. С другой стороны, скоро мы увидим, что этот простой язык справляется с ролью скромного, без излишеств, универсального языка программирования. Сейчас же мы просто продемонстрируем использование скелетного языка для записи некоторых элементарных операций.
Для начала заметим, что при помощи комбинации операторов присваивания данной переменной можно назначить любое значение (любую битовую комбинацию). Например, следующая последовательность присваивает комбинацию битов 11 (бинарное представление 3) переменной X, для чего сначала удаляет ее предыдущее значение и затем увеличивает значение на единицу три раза:
i
clear X; incr X: incr X;
incr X;
Другое действие, которое часто выполняется в программах, — копирование данных из одного местоположения в другое. В терминах скелетного языка это означает, что нам необходимо уметь присваивать одной переменной битовую комбинацию, которая ранее была присвоена другой переменной. Это можно выполнить, сначала очистив целевую переменную, а затем увеличивая ее на единицу подходящее количество раз. Действительно, мы уже видели, что последовательность
clear Z:
while X not 0 do:
incr Z:
deer X; end;
передает значение, связанное с X, в переменную Z. Однако у этой программы есть побочный эффект — она разрушает исходное значение X. Чтобы исправить эту ошибку, мы можем ввести вспомогательную переменную, которой присвоим в начале программы рассматриваемое значение. Затем эта вспомогательная переменная будет использоваться как источник данных, из которого мы восстановим исходную переменную, одновременно помещая нужное значение в целевую переменную. Таким образом, присваивание переменной Tomorrow значения переменной Today можно выполнить при помощи последовательности команд, приведенных в листинге 11.2.
Листинг 11.2. Реализация команды «скопироватьToday в Tomorrow» на скелетном языке
clear Aux; clear Tomorrow; while Today not 0 do;
incr Aux;
deer Today: end; while Aux not 0 do;
incr Today;
incr Tomorrow;
deer Aux; end;
Мы будем использовать синтаксис copy namel to name2;
(где namel и name2 — имена переменных) для краткого обозначения структуры операторов, приведенной в листинге 11.2. Поэтому, хотя в скелетном языке не существует явной команды копирования, мы будем писать программы так, как если бы она существовала, понимая, что для преобразования таких неформальных программ в настоящие программы на скелетном языке нам понадобится заменить операторы сору на эквивалентные структуры while-end с использованием вспомогательной переменной, имя которой не встречается где-либо еще в программах.
