Text
                    ест


i t
I 11
. I
I
11 .
I .
11
.
11 ...


-


"""'"


"-"


р


па u <. с






 j


,.


de


.


.


I


TRU
.


en










".


rdou l с а ......0 u


IJ


00


1


11


I



.


.
,",......


11


"


"ои tpu


{О,


.


+....
.


fl


.


ru


.u


..


..


v lue:
..


I


.
,





Вячеслав Шелест Проrраммирование СанктПетербурr «БХВПетербурr» 2002 
УДК 681.3.06 Шелест В. д. Проrраммирование. СПб.: БХВПетербурr, 2002.  592 С.: ил. ISBN 5941570589 Книrа учит тому, как писать проrpаммы, более TOro, хорошие проrраммы, по схеме структурированный аЛi!оритм + язык nРОi!раммирования + стиль == nросраМ.ма. Излаrае мый материал широко иллюстрируется примерами. Для записи проrpамм используют ся языки ТшЬо Pascal, Вщlапd С++ и современный FOltl'ап. Приведены упражнения, для выполнения которых достаточно здравоro смысла, знания элементарной MaTeMa тики и начальных сведений из математическоro анализа и линейной алrебры. Рекомендуется учащимся лицеев, rимназий и школ, колледжей и техникумов, CTyдeH там младших курсов институтов и университетов, всем изучающим и преподающим проrpаммирование. для начинающих np0i!pOhIМUCmOB УДК 681.3.06 fруппа подrотовки издания: rлавный редактор Зав. редакцией Редактор Корректор Дизайн обложки Зав. производством Екатерина Кондукова Наталья Таркова Анна КУЗМlllна Зинаида Дмитриева Jfi!ОРЯ L(ырульникова Николай Тверских Ориrиналмакет подrотовлен В. Д. Шелестом Лицензия ИД N, 02429 от 24.07.00. Подписано в Печать 26.03.02. Формат 70х100'/,.. Печать офсетная. Усл. nеч. л. 47,73. Доn. тираж 3000 экз. Заказ N, 144 "БХВ-Петербурr". 198005. Санкт-Петербурr. Измайловский пр., 29. rиrиеническое заключение на Продукцию, товар No 77.99.1.95з.п.950.3.99 от 01.03.1999 r. выдано Департаментом rсэн Минздрава России. Отпечатано с сотовых диапозитивов в Академической тиnоrрафии "Наука" РАН 199034, Санкт-Петербурr, 9 линия, 12. ISBN 594157058.9 4:J Шелест В. д., 2001 <l:' Офпр"ление, издательство "БХВ-Петербурr", 2001 
3 Содержание Предисловие........................................................ 9 ЧАСТЬ 1. РАЗРАБОТКА Алrоритмов ДЛЯ PE ШЕНИЯ ЗАДАЧ НА КОМПЬюТЕРЕ.... 17 fлава 1. Линейные алrориТМы................................... 19 Алrоритм . . . . . . . . ., .. . . . .. .. . . . . . . . " . . .. ... . . . . .. ... . . . . . . .. . . . .. .. . . . .. 19 Данное. . . . . . . . .. .. .. . . . .. . . . . . . .. . .. .. . . .. ... .. .. . . .. . .. . . . . .. ... .. .. . . .. 20 Тип данных. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 20 Константа и переменная . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ., 22 Выражение. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 22 Язык проектирования проrрамм . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 23 Декларативная часть. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 23 Исполняемая часть. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 25 Команда присваивания. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 25 Команды ввода/вывода. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 26 Пошаrовая детализация. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 27 Решение задачи на ко:,шьютере.. . ., ., .. .. ... .. . . . . ... .. . . . . .. . .. .. . . . . .. 31 Постановка задачи. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 31 Построение математической модели. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32 Разработка алrоритма. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 33 Проверка проекта . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 34 Вид данных на внешних носителях информации. . . . . . . . . . . . . . .. 38 Кодирование. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 39 Выполнение проrраммы . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 39 Проrраммирование ФОРЫУЛ. .. . . . . .. . .. . . .. . . . .. . . " .. .. . .. .. " .. . 41 
4 Упражнения . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 45 fлава 2. Разветвляющиеся алrоритмы.. . . . . . . . . . . . . . . . . . . . . . . . .. 50 Условие. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 50 Альтернатива. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . " 52 Мнor'означное ветвление.. .. .. " . . . .. . . .., .. .. .. " ... .. . . ..... .. . . .. .. ... 55 Упражнения . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 58 fлава 3. Циклические алrоритМы................................ 63 Вид цикла. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 63 Структура цикла. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 65 Повторение. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 67 Арифметический цикл. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 73 Одномс-рный массив. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 75 Упражнения.... .. .. ... .... ........... '" .. ...................... ........ 81 И теративный цикл. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 84 Бесконечная последовательность.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 86 Бесконечное произведение . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . '. . . . . . . " 93 Упражнения.. . . .. . . .. . .. .. ., . .. . . . . . . .,. .. ., ., . . .. . .. .. ., " . .. " ., . . .... 96 Вложенный цикл. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 100 Множество точек плоскости.. . .. . . . . . . . . ... .... . . .. . . . ... . . .. . . .. . . ., 101 Упражнения. . .. . . . . . .. .. . . . .. ., . . " . . . . . . . .. ... .. .. " .. . .. . . .. .. ... . . .. 104 Степенной ряд. . . . . . .. . . . . . .. " .. . ., . . .. . . ... .. .. .. . . . . . . . '. . . '" . . ., ... 107 Упражнения. . . . ., . .. . . . . .., .. .. .. .. . " . . .. .. . '. . . .. . . . . . . . .. . . .. ... " ., 114 fрафик функции. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 116 Упражнения. . .. . .. .. . . .. . .. .. . . ., .. .. . .. .. .. ... .. .. .. . . '" .. . . .. . . . " .. 122 fлава 4. ПодчиНеННыеалrоритМы.............................. 124 Функциональная схема. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 124 АлI'OРИТМфУНКЦИЯ и алr'оритмпроцедура . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 130 Двумерный массив. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 136 Матрица. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 137 Мar'ическиt! квадрат.. .... ....... ........... .. ..... .. .... ..... .. .. ... 142 Упражнения. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 156 Цепная дробь.. .. . . .. . .. .. .. . . " . " . . . . " ... .. . . .. ... . . " ., ... .. . . ., . . .. 160 Упражнения. . .. . ., .. . . .. ... .. " . . . . . ., . . . . '" .. .. " .. .. .. . . . .. . . . . . . ... 166 Арифметика. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 169 Упражнения. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 174 Сортировка. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . : . . . . . . . . . . . . . . . . . . .. 178 
5 Упражнения. . .... . .. . . .. '" .... ., .. ... . . .. . . ... " .. .. .. ... .. .. .. . . . ., .. 183 Статистические испытания. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 184 Упражнения. . . . . .. .. ., . . . .. . . . . . . .. ... .. .. .. ... .... .. ., ., . ., .. " . .. . . " 190 Рекурсия. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 198 Упражнения. . . . . ., .. .. . . ". . . ., .. .. .. . . . .. . . . . . .. . . .. " '" .. . . .. ... . . .. 202 Самостоятельная работа. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ., 205 ЧАСТЬ 11. КОДИРОВАНИЕ Алrоритмов ....... 221 fлава 5. Кодирование линейных алrориТМов................... 223 Наша первая проrрамма. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 223 Алфавит языка. . ... .. . .' . " . . . . . . . .. ... .. . . .. .. '" . . ., .. ... . . " " " .... 225 Словарь языка... ... ........... ......... .... .... ..... ......... .......... 226 Константа. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 227 Целое число. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ., 227 Вещественное число. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 229 Комплексное число. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 233 Лоrические константы. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 233 Символьная константа. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . " 233 Строковая константа. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 234 Имя. . . . . . . . . . . . . . . . . . . . . . . . . . . .'. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 235 Переменная . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 235 Объявление простых переменных в Паскале. . . . . . . . . . . . . . . . . . . . . . . .. 236 Объявление скалярных переменных в Си. . . . . . . . . . . . . . . . . . . . . . . . . . .. 238 Объявление простых переменных в Фортране. . . . . . . . . . . . . . . . . . . . . . .. 240 Задание констант и начальных значений. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 241 Константы и начальные значения в Паскале. . . . . . . . . . . . . . . . . . . . . . .. 241 Константы и начальные значения в Си . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 243 Константы и начальные значения в Фортране. . . . . . . . . . . . . . . . . . . . . .. 244 Стандартные функции. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 246 Предопределенные функции и процедуры Паскаля.. .. . . .. '" .... ... 246 Предопределенные функции Си. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 248 Предопределенные функции и процедуры Фортрана............ ..... 251 Арифметическое выражение. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 258 Оператор присваивания. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 262 Стандартный ввод/вывод.. . " " .. . . ... . . .. .. .. . . . .. . . .. . . . .. .. .. ... . . .. 265 Ввод/вывод в Паскале. " . . . .. .. . . .. . .. . . .. . . . .. ., .. .. . . . .. .. .. .. . ... 266 Ввод/вывод в Си . . . .. .. . . . . . .. . . . . .. . .. . . " . . . .. . . . . " .., .. .. .. . . . ... 271 
6 Ввод/вывод в Фортране... .... .. ., . . . .. . . ", ., .. . . " ... . . .. .. . ., ..... 280 Операторы приостанова и останова. Пустой оператор. . . . . . . . . . . . . . . . ., 290 Структура и запись проrраммы . ..... .. .. ... .. .. .. .. ... ., .. " ... .. ..... 291 Паскальпроrрамма ... . . .. '" .. .. .. . . ... .. ....... .... .. . .... . .... . .., 291 Сипроrрамма .. .. .. '" .. .. .. ... .. ., .. .. .. . " .... ... ., .. .. .. ... .. " . .. 293 Фортранпроrрамма . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 296 fлава 6. Кодирование разветвлений............................ 301 Лоrическое выражение. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 301 Оператор перехода и условный оператор. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 305 Оператор выбора. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 309 Упражнения. . ., .. . " . . . . '" .. ., .. . . '" .. " .. . .. .. .. .. .. . .. .. . . . . ... .. .. 313 fлава 7. Кодирование циклов....... ..... .. ............... ...... 315 Операторы ЦИКЛа. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 315 Операторы цикла в Паскале. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 317 Операторы цикла в Си . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 321 Операторы цикла в Фортране. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 324 Массив. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . " 326 Массивы в Паскале. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ., 327 Массивы в Си .. . . .. ... .. " .. . . . .. . . .. " ... . . .. . .... .. .. . . .. . . . .. ., ... 330 Указатели в Си....................................................... 333 Массивы в Фортране.. .. .. .. . .. .. .... .,. .. . . .. . . ... .. .. .. '" .. " .. ... 341 Строковые функции. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 349 Строковые функции Паскаля. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ., 349 Строковые функции Си . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 351 Строковые функции Фортрана. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ., 356 Упражнения. . . . . . . . . . . . . ... . . .. . . . . . . . .. .. . . . . . .. . . . . . . ... .. .. .. .,. .. ., 358 fлава 8. Кодирование подчиненных алrоритМов............... 362 Подпроrрамма Паскаля. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ., 362 Функция. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ., 362 Процедура. . . . . .... .. . . . . . .. . . . . .,. . . ., . . .. . . . .. .... .. . . . .. .. . .. . . .. .. 369 Подпроrрамма Си. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . " 372 Обычная функция. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 372 Функция уоЫ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ., 377 Подпроrрамма Фортрана. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . " 385 Операторная функция. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ., 385 Функция function.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 386 
7 Процедура. . .. . . . .. ., .. .. . " ., .. ... .. .. .. .. '" .. ., ..... . . .. " ..... .... 390 Упражнения. . .. . ., .. .... ... .... .. . . ... " ., .. '" .. .. " .. ... .. .. . . .., .. .. 394 МодулЬ....... " ....... ........... '" .. .................. .. .... ., ....... 400 . Модуль в Паскале. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 400 Сборка Сипроrраммы................................................ 412 Модуль в Фортране. .,. .. " " .. .,. . . .. . . .,. .. .. . . . .. .. " . . . . '" " . . .. 416 rлава 9. Составные типы.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 418 Множества... . ... " ., .. . . . .. " .. .. .. . '" . ..... " .. .. .. ... . . " .. ... " " .. 418 Структура. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ., 421 Структуры в Паскале. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 423 Структуры в Си ..................................................... 424 Структуры в Фортране .............................................. 426 Упражнения. . " '" .. . . .. .. . . . " .. .. .. . .. . . . . . .. .. .. .. . . .., . . .. ., . .. ., " 432 Файл. . . . ... . . . . .. . . . .. . . ., . . . .. .. .. .. . . . .. . . . . " . .. . . " . . . . . . . .. ., .,. ... 441 Файлы в Паскале. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ., 443 Файлы в Си .......................................................... 450 Файлы в Фортране ....... . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . " 459 Упражнения. . . . . " ., . . " ... . . .. . . ., .. . .. .. .. . .. . . " . . . . .. . .. " .. '" ., .. 468 rлава 10. rрафики............................................... 475 Построение rрафика средствами Паскаля. . .. . . . . . .. . . .. .. ..... .. .. . . .. 477 Построение r-рафика средствами Си . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 488 Упражнение..... .. ............................... ... ...... .. ... ......... 493 rлава 11. Списки................................................ 494 Упражнения. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 504 ЧАСТЬ 111. ПРИЕМЫ КОДИРОВАНИЯ И ОТЛАДКИ ПРоrРАММ............... 509 rлава 12. Декларативная часть................................. 511 Выбор алrоритма . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . " 511 Выбор имен и констант. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 513 rлава 13. Исполняемая часть................................... 515 Выражение. . .. ... .... ....... .... .. ..... ....... .... .... ....... ......... .. 515 Присваивание значения. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . " 517 Ввод и вывод............. ...... ....... ....... .... ....... .... ......... '" 519 
8 Разветвление. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . " 520 Повторения. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 523 fлава 14. Подпроrрамма........................................ 529 Процедура и функция. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . " 529 Запись проrраммы . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 532 Вопросы и задачи для проверочной работы. . . . . . . . . . . . . . . . . . . . . . . . . . .. 533 Задачи для самостоятельной работы. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 545 Заключение.. . . ... .. .. .. .. . .. .. . . .. .. . . . . . .. . .. .. .. .. .. '" .. .. . . ... .. '" 551 Приложение 1..................................................... 553 Приложение 2.................................................... 555 Системы счисления. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 555 Формы представления чисел. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 556 Перевод из ричной системы в qичную. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 557 Перевод из qичной системы в ричную. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 558 Список дополнительной литературы............................ 561 Предметный указатель. .. ..... .. .. .., .. . .... .... ..... .... ..... ... 567 
9 Проrраммирование  зеркало разума. Д. Вей'1t6ер;? Предисловие Книrа, которую вы открыли, познакомит вас с решением вычисли тельных задач на компьютере. Сейчас трудно представить себе мир без компьютеров. Человек, не умеющий общаться с ними, находится в положении HerpaMoTHoro, попавшеrо в библиотеку: на полках MHO ro интересных книr, а как их прочтешь? Культура общения с KOM пьютером стала частью общей культуры человека. Но чтобы пользо ваться услуrами компьютера, надо уметь правильно сфомулировать ему задание: компьютер не может мыслить, не умеет додумывать недосказанное. Любое задание для компьютера нужно Формулиро вать четко, однозначно и на языке, который он понимает, тоrда это задание будет исполнено в миллионы и миллиарды раз быстрее че ловека. Научить читателя rотовить такие задания (проrраммы) основная цель данной книrи. Слова "проrраммирование", "проrрамма" часто связывают с вычи слительной техникой. Но заметьте, проrраммой является план лю бой работы: физик планирует (читайте  проrраммирует) экспе римент, портной рассчитывает (читайте  проrраммирует) процесс раскроя ткани, домашняя хозяйка проrраммирует семейный бюд жет. .. и поскольку каждый из нас так или иначе занимается про rраммированием, то научить рациональным приемам проrраммиро 
10 вания  также цель этой книrи. Любую цель леrче поставить, чем реализовать. Вас ждут ошибки, поражения и разочарования, так как проrраммирование научнотехнических задач  одна из самых TPYД ных ветвей прикладной математики. Это топь, в которой может увяз нуть не один незадачливый пользователь компьютера. Чтобы это не произошло, вы должны работать очень тщательно, аккуратно, BДYM чиво и настойчиво. Каждому проrраммисту компьютер выдает то, что тот заслужил. Но проrраммирование  это и искусство. Оно доставляет удоволь ствие радостью творчества, созданием из очень rибкоrо материала вещей, полезных себе и друrим, возможностью постоянно учиться. Очарование, заключенное в самом процессе разработки сложных, заrадочных объектов, проrрамм, значительно перевешивает rорести ремесла [10]. Книrа состоит из трех частей и двух приложений. Мы будем pe шать в основном математические задачи. Разработке их проектов посвящена первая часть. Решение любой задачи начинают с поста новки, построения модели и разработки алrоритма. СреДСТВ0М, по зволяющим cTporo и кратко записывать такие проекты, является ал rоритмический язык: блоксхемы (см. Прuло;ж;е'ttuе 1) и псевдокод. В книrе для представления алrоритмов используется псевдокод  русифицированный вариант языка описания процессов PDL [23]. Он, с одной стороны, похож на разrоворный язык, а с друrой, в силу близости к языку проrраммирования, позволяет четко и лаконично выразить структуру, лоrику алrоритма и будущей проrраммы. Но проект проrраплы, записанный псевдокодом, нельзя еще транслиро вать, зато он весьма просто переводится на язык проrраммирования. Любую работу можно выполнить различными способами. Здесь за дачи решены методами нисходящеrо проектирования и CTPYKTypHoro проrраммирования [10, 12,14, 15,23,36,41,66]. От алrоритма Tpe буется такая реализация, чтобы она была проста для доказатель ства правильности, леrка для понимания, надежна и эффективна при выполнении, универсальна, удобна для модификации и TpaHC портабельна. А как все эти требования соединить в одной проrрам ме? Как получить "хорошую" проrрамму? Коrда задача сформули рована, поставлена, как правило, сразу не удается представить себе в деталях всю проrрамму в ее "хорошей" реализации, так как для 
11 этоrо пришлось бы сразу осмыслить и переработать большой объем информации. Решить проблему помоrает метод нисходящеrо проек тирования, называемый также методом" сверху вниз", "от обще20 х: 'Частному". Он предполаrает разбиение задачи на несколько более простых частей или подзадач. Их выделяют таким образом, чтобы проектирование подзадач было независимым. При этом составляют план решения всей задачи, пунктами KOToporo и являются выделен ные части. План записывают rрафически в виде функциональной схемы (схемы иерархии, подчинения), rде определяют rоловную и подчиненные подзадачи и связи между ними, т. е. интерфейс. Здесь же устанавливают, какие начальные данные (или значения) получа ет каждая подзадача для правильноrо функционирования и какие результаты она выдает. Затем производят детализацию каждой под задачи. Число шаrов детализации может быть произвольным. ДeTa лизацию продолжают до тех пор, пока не станет ясно, как проrрам мировать данный фраrмент алrоритма. Дальше задача решается методом CTPYKTYPHoro проrраммирования. Любой алrоритм состоит из последовательных действий, разветвле ний и повторений. Их можно представить основными управляющими структурами, которые соответственно называются цеnо'Чх:а, ветвле ние и повторение (структуры "ветвление" и "повторение" имеют и друrие названия: составные команды еСJIИ, выбор и ДJIЯ ВЫПОJI НЯТЬ, пока ВЫПОJIНЯТЬ, ВЫПОJIНЯТЬ пока). Из этих и только из этих базовых структур должен быть построен проект любой под задачи. С помощью вызовов все подзадачи связывают в одно еди ное целое  структурированный проект проrраммы. Заметим, что применение CTPYKTypHoro метода сопровождается побочным эффек том  ликвидацией в проекте команд перехода иди к. Но метод CTPYKTypHoro проrраммирования rибок. Он допускает использова ние команд перехода (такие команды бывают необходимы, напри мер, для выполнения специальноrо выхода из тела цикла, коrда xo чется сказать просто: ИДИ к метх:а). Чтобы команды перехода не превращали проект проrраммы в ВSпроектl, они должны переда вать управление только вперед (переход назад предполаrает цикл и структуру "повторение"). В конечном итоrе структурированный про ект проrраммы характеризуется не отсутствием команд перехода, а 1 BS (от анrл. bowl of spaghetti)  блюдо спаrетти. 
12 наличием структур управления "цепочка", "ветвление", "выбор" и "повторение". Затем в решении задачи следует этап реализации алrоритма: Про верка ero правильности и написание проrраммы на языке проrрам мирования. Краткое описание трех языков, Турбо Паскаля, Си++ и cOBpeMeHHoro Фортрана 2 , приведено во второй части. В полном объ еме здесь оно не нужно, так как, вопервых, попытка представить во вводном курсе весь язык вызовет нехватку времени на изучение более важных проблем и, BOBTOpЫX, большой объем сведений о язы ке, полученный начинающим проrраммистом слишком рано, скорее мешает ему, чем помоrает. Преподаватель же, опираясь на данное руководство, при необходимости может всеrда включить в свой курс дополнительную информацию о языке. Язык Паскаль назван в честь Блеза Паскаля (1623  1662), вели Koro французскоrо физика, математика, философа, создателя счет ной машины (арифмометра). Первое сообщение о языке было опу бликовано Никлаусом Виртом (ВПШ, Цюрих, Швейцария) в 1968 r. К этому времени уже сложилось законченное представление о том, что хорошо и что плохо в проrраммировании. Паскаль был заду ман как язык учебнообразцовый, алrоритмический З . Успех Паска ля превзошел все ожидания. Выйдя за рамки учебноrо языка, он стал популярным языком проrраммирования, так как позволил pe шать не только вычислительные задачи. Паскаль был базовым при разработке языков Ada, Modula и Delphi [33]. Ведущие разработчи ки проrраммных средств, фирмы Мiсrоsоft и Borland International Inc., реrулярно поставляют на рынок новые версии этоrо языка. Ero диалект, Турбо Паскаль [17, 30, 34, 40, 43, 44, 54, 58, 59], естествен, элеrантен и универсален. У ниверсальный язык проrраммирования Си (rод первой публикации о нем  1972 r., BTOP  Дэннис Ритчи, фирма Bell Laboratories, США) был третьим в цепочке языков А, В, С. Именно Си завое 2ИзвеСТНbI три реализации cOBpeMeHHoro Фортрана: первая  Lahey Фор тран 90 версии 2.01 (кратко именуется LF90 2.01), вторая  Мiсrоsоft Fortran PowerStation версии 4.0 (наЗblвается FPS 4.0; см. [4]) и третья  Visua\ Fortran 5.0 Digita\ Equipment (DVF). ЗСм. Йенсен К., Вирт Н. Паскаль. Руководство для пользователя и описание ЯЗblка.  М.: Компьютер, 1993.  256 с. 
13 вал особую популярность блаrодаря уникальному сочетанию в нем возможностей языков BbIcoKoro и низкоrо уровней [27,55]. Продукт фирмы Borland, язык Си++  великолепное средство создания си стемных и прикладных проrрамм [11, 24, 28, 46, 48, 49, 50, 56, 67]. Изящный по форме, мощный и rибкий по своим возможностям, он в мире проrраммирования стал языком номер один. Имя языка Фортран образовано из слов fоrшulа translator  пере водчик формул. Первое сообщение о нем (после рассекречивания) появилось в ноябре 1954 r. Автор языка  дp Джон Бэкус (фирма IBM, США). С Фортрана началась эра автоматизации проrраммиро вания [4,5,6,7,42,52,62]. Он позволил инженеру и ученому писать формулы в привычном виде, не прибеrая к услуrам профессиональ ных проrраммистов. После опубликования стандарта Фортрана 90 стало ясно, что Фортран превратился в универсальный язык про rраммирования. Он продолжает развиваться 4 , что отражено в CTaH дартах Фортрана 95 и Фортрана 2000. Перечисленные языки про rраммирования будем ниже называть кратко: Паскаль, Си и Фор тран. Кроме Toro, во второй части сформулированы контрольные вопросы и задачи, ответы на которые даны в тексте. Здесь же предлаrаются упражнения по языкам проrраммирования. Большое внимание уделено стилю проrраммирования. Обучение xo рошему стилю [12, 68] ведется по принципу: "следуйте за мной, дe лайте как я, делайте лучше меня". В третьей части даны peKOMeHдa ции по созданию и кодированию хороших проrрамм. Там же приве дены примеры. Все это позволяет выработать практические навыки по кодированию алrоритмов. Заметим, что решение любой задачи имеет не один проrраммный вариант. Отметим еще некоторые особенности книrи. Задачи, сформулиро ванные в первой части, решены полностью. Для них были COCTa 4 }I(ивучесть Фортрана объясняется наличием большой библиотеки алrорит мов, записанных Фортраном (см. [7] и Сборник научных проrрамм на Фортра не: Пер. с анrл.  М.: Статистика, 1974.  540 с.). Это сделало ero язы ком проrраммирования номер один в области научных исследований. Прав да, недруrи Фортрана (а такие проrраммисты и пользователи, как ни странно, есть) нередко объясняют живучесть первоrо языка проrраммирования действи ем "проrраммистскоrо закона": "Все, что делает фирма IBM,  верно". 
14 влены Паскаль, Си и Фортранпроrраммы и получены результа ты. Тексты проrрамм не приводятся. В конце каждой темы указано, на каких страницах второй части можно прочитать о необходимых средствах кодирования проектов. Здесь же даны упражнения. Они предназначены для выдачи заданий обучающимся. Задачи весьма различны по трудности. Первые пятнадцать задач просты, осталь ные сложнее. Часть задач сформулирована впервые, друrая заим ствована из работ [9, 12, 22, 25, 35, 47, 57]. Книrи подобноrо рода нередко являются коллекцией фактов и знаний. fрамматика языков проrраммирования излаrается словесно и с по мощью синтаксических формул, состоящих из переменных обозначе ния (метапеременных), основных символов, ключевых слов и MeTa символов: мноrоточия и наклонных квадратных скобок [ и }. Me тапеременные образуются из строчных букв латинскоrо, rреческо ro или pyccKoro алфавита с возможными индексами, опущенными ниже строки, как это принято в обычной записи. Метапеременные представляют синтаксические элементы языков проrраммирования. Основные символы в синтаксических формулах  это запятая, точ ка, точка с запятой, двоеточие, круrлые и фиrурные скобки и знак равенства. Ключевые слова псевдокода и языков проrраммирова ния в тексте книrи выделены (для удобства чтения) полужирным шрифтом, а имена (идентификаторы), метапеременные и определе ния  курсивом. Мноrоточие означает, что стоящие перед ним MeTa переменную и разделитель можно повторять по аналоrии произволь ное конечное число раз. Наклонные квадратные скобки указывают, что заключенные в них синтаксические элементы можно опустить и тоrда будут действовать правила умолчания. Вертикальная запись синтаксических единиц означает, что надо сделать выбор одной из них. В заключение отметим, что проrраммирование научных задач  удел избранных. В современной жизни для большинства людей aKTY альным стало умение пользоваться информационными технолоrия ми [20,65]. Однако важность численных расчетов от этоrо нисколько не снизилась. Как и раньше, компьютер управляет полетом космиче ских аппаратов, рассчитывает параметры новых моделей автомоби лей, самолетов и кораблей, предсказывает поrоду и т. д. Создав Ma тематическую модель HeKoToporo процесса (физическоrо, биолоrиче 
15 cKoro, социальноrо и т. д.), можно написать проrрамму исследования ero во времени, а задавшись различными начальными условиями,  экспериментировать с ним. Часто вычислительный эксперимент бы вает незаменим: он, как правило, дешевле обычноrо эксперимента и, нередко, безопаснее, а, к примеру, при проверке космолоrических rипотез  это единственно возможное средство исследования. Блаrодарности Спасибо сотрудникам кафедры "Прикладная математика" СПбrТУ5: Валерию Лыдкину, Вячеславу Дороту, Иrорю Ануфриеву, Алексею Качурину, Наталии Измайловой, Светлане Клавдиевой, Вере Улья новой, Кириллу Замятину, Владимиру Сколису, Владимиру Клав диеву.. . 5Политехнический институт Императора Петра Велико['о (основан в 1899['.). 
1 Линейные алrоритмы 2 Разветвляющиеся алrоритмы 3 Циклические алrоритмы 4 Подчиненные алrоритмы Часть 1 Разработка алrоритмов для решения задач на компьютере 
19 r лава 1 Линейные алrоритмы Цель этой части  объяснить понятие nол1tО20 nострое1tи.я аЛ20 ритма, основными этапами KOToporo являются постановка задачи, построение математической модели, планирование структуры дaH ных, проектирование проrраммы, тестирование проекта, кодирова ние, проверка проrраммы и составление документации. Простейшими являются лu1tе't11tые аЛ20рuтмы. С них мы и начнем. Алrоритм АЛ20рuтм  это точная конечная последовательность предписаний, исполнение которых позволяет посредством конечноrо числа шаrов получить решение задачи, однозначно опреде'1яемое исходными дaH ными. Исполнителем алrоритма может быть человек или aBTOMa тическое устройство, способное воспринять предписания и выпол нить предусмотренные в них действия. Понятие алrоритма OTHO сится к основным понятиям математики. Математическая теория алrоритмов примыкает к одному из наиболее изысканных разде лов математики  математической лоrике. Алrоритмы встречают ся и в повседневной жизни, причем на каждом шаrу, под названи ями "инструкция", "рецепт", "метод решения" и т. д. ПрО2рамма  это тоже алrоритм, записанный на языке Проrраммирования и Пред назначенный для исполнения компьютером. В проrрамме действия 
20 ДОЛЖНЫ быть описаны до мельчайших подробностей в точном COOT ветствии с синтаксисом языка. Однако не всякое предписание является алrоритмом. Инструкция "действуй по обстановке" или известное из мира сказок "поди TY да  не знаю куда, принеси то  не знаю что" не есть алrоритмы, так как они неточны, не указывают на конкретную последователь ность действий. Алrоритм должен предусмотреть обработку любых ситуаций. которые MorYT возникнуть при ero исполнении, и OДHO значно указать, что делать в каждой из них. Характеристики алrоритма  определенность, дискретность, pe зультативность и массовость. ОnределеЮiOсть подразумевает oд нозначность результата при заданных исходных данных; диcк:peт ность  расчлененность алrоритма на отдельные элементарные действия; результатU6ность означает, что через некоторое конеч ное число шаrов алrоритм выдаст результат (цель достиrнута, зада ча решена; цель недостижима, задача не имеет решения), а Macco 60сть предполаrает, что алrоритм даст результат для любых исход ных данных из HeKoToporo их множества. Такие характеристики  общие свойства вычислительных алrоритмов (численных, экономи ческих, вероятностных и т. д.) иневычислительных (иrровых, ин формационных, интуитивных и прочих). Панное Решение большинства задач связано с преобразованием данных. Данные есть общее название Bcero Toro, чем оперирует компьютер, причем проrраммой обрабатываются nроблемные данные, а при op rанизации передач управ.riения и для формирования адресов памяти используются уnра6л.яющuе данные (метки). Тип данных Проблемные данные MorYT быть разных типов. Перечислим пре жде Bcero стандартные типы: 'Ч,UСЛО60i1 (или арифметический), ло 2u'Ч,еск:ui1 (или булевский), СUМ60льныi1 и стРОК:О6ыi1. Одно значение любоrо типа является элементноi1 (ск:ал.ярноi1) 6елu'Ч,uноi1. Данное, представленное набором элементных величин, называется cocтa6 ным. Каждый тип данных предназначен для определенных целей 
21 и имеет свое внутреннее представление (на "атомарном", битовом уровне каждое данное состоит из комбинации нулей и единиц). Числовые данные имеют общепринятый смысл и MorYT быть X:OM nлех:сными и действительными (типа 'Целый, вещественный и двой ной то'Ч,ности). J(омnлех:сное данное  это упорядоченная пара дей ствительных (часто, вещественных или двойной точности) величин. Целые данные  это специальные данные. К ним относятся счет чики, номера, индексы и их rраницы, размеры векторов, матриц, " 11 Й параллелепипедов и т. д., порядки уравнени и систем, показатели степени (часто) , переключательные и специальные величины. Для компьютера целое данное  это всеrда точное представление цело [о значения, арифметические операции над которым выполняются точно. Все остальные числовые данные MorYT быть вещественными или двойной то'Ч,ности. Вещественное данное  это процессорное приближение действительноrо значения. Операции над такими вели чинами выполняются приближенно, что, как правило, не приводит к существенной неточности результатов (допускается поrрешность в пределах ошибок окруrления, так как в компьютерных вычисле ниях участвует конечное количество цифр). Однако иноrда ошибки MorYT быть значительными. Определенную опасность таят аддитив ные операции (сложение и вычитание). Сложение большоrо числа с малым сопровождается потерей значащих цифр (изза выравни вания порядка малоrо числа). В разности близких величин также может не оказаться нескольких, а то и всех значащих цифр (явле ние сокращения). Опасно деление на близкие к нулю числа (поэто му, например, неравенство la/51 ::::; с в проrрамме лучше заменить неравенством laj::::; с 151, не содержащим явноrо деления на 5; здесь предполаrается, что 5  О и даже 5 == О). Таким образом, в KOM пьютерных вычислениях обычные для арифметики законы ассоци ативности и дистрибутивности MorYT не выполняться [14]. Так как в языках проrраммирования определены даННЫе двойной точности (их точность представления выше более чем в два раза в сравнении с типом вещественный), проrраммист может управлять степенью при ближенности действительных значений и операций над ними [45, 61]. Заметим, что множества Z целых чисел и R действительных чисел в математике бесконечны. Но в компьютерной арифметике эти множе ства оrраничены (к примеру, целые числа изменяются в диапазоне 
22 от 216 до 216  1, т. е. принадлежат промежутку [32768; 32767]). Данное, которое может быть либо истинным, либо ложным, называ ется ЛО2и'Чесх:и.М. Символ'Ьное данное  это данное, значением KOToporo является оди ночный произвольный символ из множества символов кодовой Ta блицы, а строх:овое  любая последовательность (цепочка) симво лов. В проектах проrрамм значения двух этих типов будем окай млять апострофами. Константа и переменная Некоторые данные известны на стадии разработки алrоритмов. Их нельзя переопределить, т. е. изменить в процессе исполнения алrо ритма. Такие данные называются х:онстантами. Данные, значения которых порождаются в процессе исполнения алrоритма (к приме ру, исходные, промежуточные и выходные данные), называются ne ременными.. Для ссылки на переменную величину ей нужно дать имя. Любые символы MorYT входить в Hero, но в языках проrрамми рования имя должно начинаться с буквы латинскоrо алфавита или с символа разбивки  и может содержать буквы, цифры и символы разбивки. Итак, данное характеризуется тремя атрибутами: именем, типом и значением, rде только для переменной третий атрибут являет ся переменным. Тип и значение константы однозначно определя ются ее записью. Например, обозначение 123 в языках проrрам мирования есть имя константы типа целый и постоянноrо значе ния 123 (сто двадцать три); последовательности символов 123.0 и 123еО представляют вещественное числовое значение "сто двадцать три", записанное соответственно в фиксированной и экспоненциаль ной формах (сравните с обычным изображением 123, О и 123 х 100). Точно также строковая константа, образованная из шести символов М, а, р, И, н, а в указанном порядке, будет обозначаться 'Марина' на языках Паскаль, Фортран 90 и PLjM, "Марина"  на языках Си++, Фортран 90, Алrол 68, Modula и Ada. Выражение Над значениями можно выполнять ту или иную последователь ность операций, описываемую выражением. Данные, входящие в BЫ 
23 ражение, называются оnеранда'ми. Каждый язык проrраммирова ния определяет свои типы выражений: арифметические, лоrические (в частности, сравнения, или отношения), символьные, строковые, сцепления (конкатенации) и т. п., любое из которых может быть CKa лярным или составным. Результатом вычисления выражения явля ется значение. Ero тип зависит от типа операндов и от вида опера ций, выполняемых над операндами. Язык проектирования проrрамм Наша цель  научиться единообразно и точно записывать алrорит мы, используя систему обозначений и правил, называемую язых;о,М nроех;тирования nросра'м'м. Этот язык, с одной стороны, близок к разrоворному языку, так как алrоритмы на нем записываются и чи таются как обычный текст. С друrой стороны, язык проектирования включает в себя математические символы, и некоторые ero пред ложения (объявления, команды) построены по образцу описаний и операторов языков проrраммирования. По этой причине язык проек тирования называют nсевдох;одо'м. Он позволяет описывать алrорит мы с учетом их лоrики, без учета специфики конкретной вычисли тельной системы и занимает промежуточное положение между eCTe ственным языком и языками проrраммирования. Псевдокод имеет свой словарь. Основу ero составляют слова, смысл и способ употре бления которых заданы раз и навсеrда. Эти слова называются х;л1О- чевъt,Ми. Они выделяются полужирным шрифтом при печати или подчеркиваются при написании и используются (по желанию) в co кращенной форме. Декларативная часть Алrоритм, представленный псевдокодом, должен иметь дех;ларатив- НУ1О и исnолняе.ллу1О части. Первая состоит из засоловх;а алсорит- ,ма и обоявлениi1. В заrоловке за ключевым словом алrоритм (или алr) нужно указать имя алrоритма. Имя выбирается так, чтобы бы- ло ясно, какая задача решается (любое имя в проекте и проrрамме должно быть мнемоническим). Далее с новой строки MorYT следо вать объявления (констант, типа, массивов и общих  rлобальных, внешних  данных). Зачем они нужны? Как, к примеру, в спор 
24 те действует правило: к соревнованиям допускаются только спорт смены, чьи фамилии числятся в заявке, так и в проrраммировании можно оперировать лишь данными, относительно которых известно, "кто есть кто, сколько их и как их нужно понимать". Чтобы указать тип данноrо, перед ero именем пишут сокращенное ключевое слово: компл для "комплексный", вещ для "вещественный", двточн для "двойной точности", цел для "целый", лоI' для "лоrический", симв для "символьный", строк для "строковый" И т. д. Если несколько данных имеют одинаковый тип, соответствующее объявление типа можно сократить (например, цел i, j) k вместо цел i цел j цел k). Итак, если словом тип назвать любое из ключевых слов компл, цел и т. д., то оббЯ6ле1tие типа пepe.мeппыx можно написать так: тип V1, V2, ..., V n rде V1, V2, ..., V n  имена переменных. Здесь же в декларативной части некоторым или всем переменным можно задать 1tа'чаль1tыe з1tаче1tия: тип V1[ f----- а1}, V2[ f----- а2}, ..., V n [ f----- а n } В этом объявлении а1, а2, ..., а п  константы; знак f----- читается "присвоить значение" (например, фраза V1 f----- al означает: перемен ной V1 назначить значение а1)' В некоторых языках проrраммирования (Фортран, PL/M) тип Пере мен ной при отсутствии явноrо объявления определяется по первой букве имени: если имя начинается с одной из букв i, j, k, 1, т или n, то устанавливается тип цел; в противном случае  тип вещ. Неявное определение типа признано крайне вредным, так как оно снижает надежность и ухудшает читаемость Проrрамм [12,41,68]. Если в алrоритмах содержатся математические константы (напри !'о1ер, С  постоянная Эйлера), физические (например, 9  YCKope ние свободноrо падения) и т. Д., то посредством объявления КОНСТ С f----- 0..57721.5664901.5329, 9 f----- 9.8066.5 им можно задать значения. Здесь типы С и 9 определяются типами значений: они соответственно есть двточн и вещ. В общем случае 'Констапта.М С1, С2, ..., СП можно 1tаз1tачить з1tа'Че1tия следующим образом: КОНСТ [munl} С1 f----- а1, [т и п2} С2 f----- а2, ..., [т и п n } сп f----- а п 
25 Исполняемая часть Исполняемая часть алrоритма начинается за словом начало. Она состоит из nредложениti, каждое из которых записывается (по же ланию) с новой строки. Роль предложений иrрают 'Команды, т. е. предписания выполнить отдельное законченное действие. Заверша ется проект словом конец. Алrоритм может иметь комментарии. Текст каждоrо из них должен размещаться между символами /* и */. Итак, общиti вид аЛ20ритма, записанноrо псевдокодом, таков: алrоритм им,Я [обб,Явлени,Я } начало 'Команды конец Как и предложения разrоворноrо языка, 'Команды в алrоритмах бы вают простые и сложные (составные). Простая команда предПИ сывает безоrоворочно выполнить указанное действие. Она должна быть повествовательным предложением, содержащим rлаrол в пове лительном наклонении и дополнение, определяющее объект или объ екты, над которыми производится действие. Простые команды Becь ма разнообразны. К ним, в частности, относятся команды присва ивания, ввода/вывода, передачи управления и останова. Составная команда (коротко, сери'я) либо состоит из последовательности Про стых команд (команда "цепочка"), либо содержит условие, в зависи мости от KOToporo выполняется та или иная команда из числа BXO дящих в составную (команды "ветвление", "выбор" и "повторение"). Команда присваивания f( О.ма нда и........а читается "и присвоить значение а" и называется ""oMaHaoti npиcвa ивани,Я. Это самая распространенная в записи алrоритма простая команда. Здесь 'и  имя (простой) переменной, элемента массива (переменной с индексами) или алrоритмафункции, а  выражение (1) называют .мишенью, а  источни'Ком). Заметим, что вместо сим 
26 вола присваивания +----- можно использовать символы :== или ==. Выполнение команды присваивания заключается в вычислении зна чения выражения а при текущих значениях операндов и замене зна чения мишени V на значение источника (например, определить CKO рость Vt точки, движущейся равнопеременно, в момент времени t и пройденный путь s за время t можно с помощью команд присваива ния: Vt +----- vo+at и s +----- v o t+at 2 /2). Источник должен содержать только те операнды, которые используются в алrоритме, и только те опе рации, которые MorYT быть реализованы исполнителем. Сложныu вид этой 'К;оманды таков: Vl +----- V2 +----- . . . +----- V N +----- а Сделаем замечание относительно выбора имен переменных. Лица с физикоматематическим образованием MorYT себе позволить писать команды вида '/)t +----- Vo + at и s +----- vot + at 2 /2. Содержательные же обо значения с'К;оростъ +----- на'Чалънаяс'К;оростъ+ ус'К;орение х время расстояние +----- на'Чалъная с'К;оростъ х время + ус'К;орение х (время)2/ 2 лучше, так как соответствующие команды, а значит, алrоритмы леr че читаются. Команды ввода/вывода До сих пор ничеrо не rоворилось о том, каким образом исходные данные для работы алrоритмов передаются проrрамме и как она информирует пользователя о результатах работы. Исходные дaH ные можно задать командами присваивания, объявлениями типа или командами ввода. Команда ввода. ввести Vl, V2, ..., V N присваивает переменным, элементам массива и (или) массивам Vl, V2, ..., V N значения исходных данных, набираемых на клавиатуре. Базы данных MorYT быть размещены на жестком диске. Переменная не определена, если при выполнении алrоритма она не получила KOHKpeTHoro значения. К примеру, если скорость Vo точки в начальный момент времени равна 7 м/с, ускорение а == 0.6 м/с 2 , время t == 10 с, тоrда в проекте 
27 проrраммы можно написать либо три команды присваивания (Vo +------ 7 а+------ 0.6 t +------10), либо одно объявление (вещ Vo +------ 7, а +------ 0.6, t +------ 10), либо команду ввода (ввести Vo, а, t). Какой способ лучше? Конечно, третий, ибо первые два способа не универсальны. КоманДа вывода вывести al, а2, . . . , а п передает на внешний носитель информации (экран, принтер) значе ния выражений al, а2, ..., а п числовоrо, символьноrо, CTpoKoBoro и/или лоrическоrо типов. Заметим, что языки проrраммирования часто имеют специальные средства (объявления формата), позволяющие учитывать структуру, расположение и форму представления вводных/выводных данных, указывать необходимые преобразования данных и т. п. Пошаrовая детализация Разработка алrоритма является творческим процессом и, как пра вило, требует определенной эрудиции и изобретательности. Подrо товим проект проrраммы определения скорости Vt и пути 5, прой денноrо точкой при равнопеременном движении. Не будем ставить целью получение проекта решения этой простой задачи немедлен но, сразу. Может быть, нам и не удастся ero создать за один этап, так как проrраммирование  составной процесс, а результатом ero должен быть удовлетворительный конечный продукт, отвечающий определенным спецификациям. Проrрамма (а значит, и ее проект) должна быть: О nрави.//,ъно71 (всякая проrрамма создается для Toro, чтобы OTBe чать некоторому требованию и должна ему удовлетворять); О надеЭfCно71 (проrрамма должна давать разумные результаты во всех возможных ситуациях, анормальных условиях, вырожден ных случаях и обрабатывать их); о .//,ес","о-ч,uтаемо71 (проrрамму в первую очередь и чаще читают лю ди, а затем компьютеры; ясную, понимаемую проrрамму леrче отладить, тестировать, верифицировать и модифицировать); О эффе","тuвно71 (проrрамма должна выполняться за приемлемое 
28 время и умещаться в заданном объеме памяти); о уtiuверса-лыюi1 (универсальную проrрамму леrче корректиро вать, модифицировать и эксплуатировать); О траtiсnортабе-лъtiоi1 (проrрамма должна леrко адаптироваться к изменению среды: смене компьютера, внешних устройств, опера ционных систем, трансляторов и т. п.). Итак, разберемся в постановке сформулированной ранее задачи BЫ числения скорости и расстояния. Выясним: 1. Какие объекты известны. 2. Каковы связи между ними. 3. Какие действия нужно выполнить над ними. 4. Что же требуется найти. Ответами будут: 1. ио  скорость в момент начала отсчета времени (t О), а  ускорение движущейся точки и t  время. 2. Vt  скорость в момент t и s  путь, пройденный за время t, представляются формулами Vt == ио + at и s == vot + at 2 /2. 3. Арифметические. 4. Vt и s. При составлении алrоритма надо: 1. Определить объекты, с которыми будем работать. 2. Классифицировать их на исходные, вспомоrательные (текущие, промежуточные) и искомые (выходные). 3. Исходным объектам задать начальные значения. 4. Указать порядок действий, ведущий к искомому результату. Ответами будут: 1. ио, а, t, Vt и s. 2. ио, а, t  исходные; Vt может cbIrpaTb роль вспомоrательной Be личины; Vt И S  искомые. 3. ио == 7 м/с, а == 0.6 м/с 2 , t == 10 с. 4. Vt == ио + at, s == vot + at 2 /2. 
29 Приступим К составлению алrоритма. При разработке проекта при меним метод пошаrовой детализации. Алrоритм (назовем ero C1'\,o ростъ u рассто,Ян,uе) будем рассматривать как некоторый посто янно совершенствуемый объект: из начальной версии (от которой требуется пока лишь, чтобы она была корректной) даже, может быть, в ущерб эффективности, путем последовательных преобразо ваний получим такой вариант, который обладает перечисленными ранее качествами. Итак, сформулируем алrоритм сначала в самых "крупных" командах (при этом в проекте MorYT появиться команды, ВЫХОДЯЩИе за рамки возможностей исполнителя): алrоритм С1'\,оростъ u рассто,Ян,uе объявить данные начало ввести исходные данные вывести заrоловок задачи и исходные данные вычислить скорость вычислить расстояние вывести заrоловок выходных данных и результаты конец На следующем, втором шаrе уточним отдельные детали алrорит ма: вместо предложения "объявить данные" напишем объявле ние вещественных переменных, rде список переменных пока He определен; конкретизируем команду ввода, заменив ее KOMaв: дой "ввести ио, а, t"j расшифруем первую команду вывода так: "вывести u Вычислениеuскорости uиuпройденноrоuпути. u Исходные uданные:uvо == 7uua == 0.6uut == 10" (здесь символ u означает "пус то, пробел"); вместо команд вычисления скорости и пути наШI шем соответственно команды присваивания Vt  ио + at и s   vot + ае /2 и, наконец, детализируем вторую команду BЫBO да: "вывеСТИuОтветы: UCKOpOCTbuu == 'ЦЦ. цuрасстояние == 'Ц'Ц'Ц. 'Ц", rде Ц'Ц. Ц и ЦЦЦ. Ц  описатели внешней формы значений Vt И S COOTBeT ственно (здесь Ц  цифра от О до 9, а 'Ц'Ц.'Ц, например, означает: если Vt примет наименьшее значение, равное нулю, оно будет выведено в виде uO.O; наибольшее возможное значение Vt равно 99.9). Представим новый, уточненный вариант проекта: алrоритм С1'\,оростъ u рассто,Ян,uе вещ переменные 
30 начаJ10 ввести VO, а, t вывести uВычислениеuскоростиuи uпройденноrоuпути. uИсходныеuданные: uVo == 7uua == 0.6uut == 10 Vt t----- Vo + at s t----- vot + at 2 /2 вывести uOTBeTbI: uCKOpOCTbuu == 'Ц'Ц. 'Ц uрасстояние == 'Ц'Ц'Ц.'Ц конец На третьем шаrе детализации уточним объявление переменных. К данному моменту известны все переменные величины алrоритма, поэтому можно написать: "вещ Vo, а, t, Vt, s". Получим алrоритм, состоящий только из команд, понятных исполнителю. Заметим, что можно построить более эффективный алrоритм определения paCCTO яния. Сейчас вычисление выражения vot + at 2 /2 выполняется за BO семь операций. Сократим их количество вдвое, записав vot + at 2 /2 в виде (vo + Vt) t /2. И наконец, заменив операцию деления операцией умножения, получим, что путь равен (vo+Vt) t х 0.5 (арифметические операции в порядке убывания скорости выполнения располаrаются так: :1:, х, /, "возведение в степень"). Приведем конечную версию проекта 1 : аJ1rоритм Ок;оростъ u рассто.я:нuе объявить данные { вещ переменные { вещ VO, а, t, Vt, S начаJ10 ввести исходные данные вывести заrоловок задачи и исходные данные { ввести Vo, а, t вывести uВычислениеuскоростиuи uпройденноrоuпути. u Исходныеuданные: uVo == 7uua == 0.6uut == 10 вычислить скорость { Vt t----- Vo + at 1 В проектах и проrраммах в тексте комментариев нередко используется аб бревиатура ео (от анrл. end of)  конец. 
31 вычислить paCCTO { S  vot + at 2 /2 {s  (vo + Vt) t/2 {s  яние  (vo + Vt) t х 0.5 вывести заrоловок { вывести uOTBeTbI: выходных данных uCKOpOCTbuu== ЦЦ. Ц И результаты uрасстояние==ццц. Ц конец /* ео алr Ок;оростъ и расстояние */ Итак, решение любой задачи, какой бы простой она ни была, Tpe бует разбиения ее на уровни абстракции, т. е. "лоrические слои", и применение метода последовательноrо улучшения. Решение задачи на компьютере Решение любой задачи на компьютере требует специальной техноло rии и производится в несколько этапов. Часть этих этапов выполня ет человек (постановка задачи, построение математической модели, разработка алrоритма, доказательство ero правильности и планиро вание тестирования, планирование структуры исходных и выходных данных, кодирование), друrую часть  человек и компьютер (pea лизация алrоритма на компьютере, включающая отладку и тестиро вание), затем человек ( анализ результатов) и снова человек и KOM пьютер (составление документации). Весь процесс решения задачи от ее постановки и до оформления отчета называется np02paMMиpo ванием. Познакомимся кратко с этапами этоrо процесса и выясним, как они объединяются в единое целое. Постановка задачи Это первый этап решения задачи. Пусть дано... Такими словами ча сто начинается формулировка условий математических задач. Затем на языке cTporo определенных математических понятий излаrаются исходные предпосылки (в частности, входные данные или значения, знач) и цель исследования, т. е. указываются объекты, которые Tpe буется найти (результаты, рез). После постановки задачи следует этап поиска метода ее решения  построение алrоритма. Заметим, что не всеrда предлаrаемые для решения задачи хорошо сформу лированы, и нет ничеrо хуже, чем неполное и неточное описание 
32 задачи. Поэтому прежде чем приступать к построению алrоритма, проrраммист должен добиться точности в определении задачи и пра вильном понимании условия. На это не надо жалеть времени. Построение математическоit модели Несколько иначе обстоит дело с прикладными задачами [23]. В них обычно дан реальный нематематический объект: физический, произ водственный, экономический, биолоrический или социальный про цесс. Решение начинается с формализации объекта, описания ero в математических терминах, для чеrо выделяются наиболее суще ственные характеристики объекта, и с помощью математических средств (языка алrебраических, дифференциальных, интеrральных и т. п. уравнений, аппарата математической лоrики, теории Bepo ятностей, теории множеств и т. д.) строится соответствующая MaTe матическая модель. Так как в процессе моделирования допускаются упрощения, то модель не тождественна реальному объекту, а являет ся приближенным отображением ero. Степень соответствия модели объекту проверяется практикой. OHaTO и ставит оценку построен ной модели. Разработка математической модели  один из наиболее интерес ных, сложных и ответственных этапов, так как он требует соедине ния специальных и математических знаний. Правильно построить модель  решить задачу более чем на половину. Трудность раз работки и исследования модели зависит от сложности изучаемой проблемы. Приведем 'К:лассифи",ацию сложности решаемых задач [23, 68]. Задачи системноrо проrраммирования (разработка операци онных систем) по крайней мере в три раза труднее, чем задачи раз работки трансляторов, которые, в свою очередь, в три раза сложнее задач прикладноrо проrраммирования (математических, инженерно технических и т. п.). Разработка системных проrрамм, предназначен ных для функционирования в режиме реальноrо времени, в три раза сложнее разработки обычных системных проrрамм, и, наконец, co здание проrрамм, применяемых в диалоrовом режиме, как правило, в два раза сложнее разработки проrрамм, используемых в обычном режиме. 
33 Разработка алrоритма Теперь можно приступать к построению алrоритма  поиску Me тода решения сформулированной математической задачи и проек тированию проrраммы. Выбор метода зависит от выбора модели. В прикладных задачах нас, как правило, интересуют количествен ные значения искомых (выходных) данных. В простейших случаях последовательность операций, с помощью которых можно найти OT вет, задается формулами. Алrоритм, для KOToporo не удается получить ответ в явном виде, может быть основан на следующем приеме: строится итеративный процесс 2 , сходящийся к искомому решению. Он обрывается на HeKO тором шаrе, а найденная приближенная величина принимается за решение задачи. Такой приближенный результат ни в чем не YCTY пает точному, ибо сходимость процесса rарантирует: для любой за данной точности е (е > О) всеrда найдется номер итерации N, при котором ошибка в решении не превзойдет е. Проблема применения любых а.пrоритмов, как правило, в большом объеме вычислений, поэтому нужно выбирать надежные, простые и эффективные методы [1,2,13,14,18,21,26,31,32,45,51,53, .57,60, 61] и уделять особое внимание первым этапам решения задачи. Все этапы, перечисленные ранее, взаимосвязаны: первые из них влияют на последующие, а последние rенерируют обратную связь, которая может привести к пересмотру любоrо из начальных шаrов решения задачи. Но в работе проrраммистов прослеживается тенденция бы стрее перейти к написанию проrраммы, что можно, наверное, объ яснить двумя причинами: вопервых, для некоторых проrраммистов кодирование и отладка проrраммы З  это наиболее интересная и захватывающая часть их работы, и, BOBTOpЫX, некоторые админи страторы считают, что проrраммисты работают тоrда, коrда пишут конкретные команды. Таким образом, очень важно сопротивляться кодированию, чтобы 2Итерация (от лат. iteratio)  повторение, неоднократное применение какой нибудь математической операции. 30тладка  устранение синтаксических и очевидных лоrических ошибок; она производится с помощью компьютера и предполаrает, что проrрамма не рабо тает или выполняется неверно; если же проrрамма "семантически правильна" , работает "верно", то тоrда она тестируется [12]. 
34 этап разработки завершился успешно. rлавное правило  нельзя проектировать и кодировать первый подвернувшийся, предложен ный или созданный алrоритм, а нужно проанализировать и сравнить самым тщательным образом несколько вариантов и выбрать лучший из них (по надежности, сложности, количеству операций и длине). Как правило, простой и ясный алrоритм трансформируется в леrко читаемую проrрамму, которая быстрее работает и меньше занимает памяти, чем проrрамма, соответствующая сложному алrоритму. И так, выбран хороший алrоритм и можно приступать к проектиро ванию проrраммы  записи ее псевдокодом. Этом язык удобен при нисходящем проектировании и хорошо соrласуется с методом поша rовой детализации. Следуя этому методу, представим алrоритм как набор "независимых" подзадач; например, если некоторый алrоритм А состоит из трех подзадач A 1 , А 2 , Аз, ero можно сначала записать так: алrоритм А [оббявления} начало выполнить Al выполнить А 2 выполнить Аз конец Затем проектируем A 1 , А 2 и Аз  более простые задачи, чем перво начальная А. Расшифровываем каждую из них шаr за шаrом посте пенно, пока не придем к простым командам. Про верка проекта Следующим шаrом в решении задачи является аттестация  вери фикация проекта и планирование тестирования проrраммы. Оба ша ra служат целям доказательства ее правильности. Правилъноl1 Ha зовем проrрамму, не содержащую синтаксических ошибок, не имею щую ошибок на этапе трансляции, сбоев при выполнении и для всех возможных входных данных обеспечивающую получение правиль Horo результата. Отметим, что наш псевдокод позволяет обращаться с командами как с математическими объектами. Например, следующую команду при 
35 сваивания D..+-----axb+cxd можно представить в виде функции f(Xl' Х2, Хз, Х4) +----- Хl Х Х2 + Хз х Х4 И написать вместо исходной команды такую: D.. +----- Ла, Ь, с, d) Аналоrичным образом можно заменить любую команду псевдокода, а проrрамму рассматривать как функцию, преобразующую входные данные в выходные. Верuфuх;аци.я  математическое доказатель ство правильности проrрамм. В таком доказательстве применяется аксиоматический подход, который использует исчисление предика тов. Эти доказательства весьма трудоемки, составляют отдельную дисциплину и здесь не рассматриваются. Если верификация призвана помочь избежать ошибок в буду щей проrрамме, то тестирование позволяет определить состояние "правильно" выполняющейся проrраммы и убедиться, что она yдo влетворяет сформулированным требованиям, соответствует проект ным спецификациям. Ошибки в "правильно" работающей проrрам ме возникают по разным причинам. Неверные или неполные спе цификации  основной источник ошибок, друrой  ошибки алrо ритмизации и, как следствие, неверное проектирование и третий  случайные ошибки или описки. Причиной ошибок MorYT быть He брежность начинающих проrраммистов, недоразумения и путаница, недоrоворенности и неоднозначные толкования фактов Изза pac плывчатой формулировки целей и т. д. Замечено, что две трети всех ошибок вносится именно на этапе проектирования и лишь треть  на этапе кодирования. Стоимость же выявления одной ошибки на этапе кодирования в два раза выше, чем на этапе u:роектирования, а обнаружение ошибки при тестировании "правильной" проrрам мы обходится соответственно в 10 раз дороже [12], поэтому важно как можно раньше начать проверку работоспособности "конечноrо продукта" (в проrраммировании, также как, к примеру, в лекарском деле, "предупреждение болезни обходится значительно дешевле, чем ее лечение"). К даННОJ\fУ моменту таким продуктом является проект проrраммы. EroTo и надо испытать. Эффективным, но весьма трудоемким средством проверки проекта 
36 является .метод руч1-tоll nро-к:рут-к:и. Ero идея основывается на сле ДУЮЩИХ соображениях: о проект, свободный от ошибок,  абстрактное теоретическое по нятие; О алrоритмический язык (псевдокод, блоксхемы) дает статиче ское изображение алrоритма, а ошибки проявляются в динами ке, при ero активизации, поэтому проrраммист должен, поставив себя на место компьютера, вручную команда за командой выпол нить ("прокрутить/) алrоритм, проследив за текущими и конеч ными результатами ero работы. На время прокрутки проrраммист может "забыть" о предыстории, ходе разработки и даже содержании алrоритма. Он должен aKцeH тировать внимание только на том, что делает алrоритм, и анализи ровать правильность ero действий. В процессе прокрутки нужно проверить все спецификации, имена переменных, константы, входные данные, списки aprYMeHToB и па раметров. Каждая команда, любая ветвь, любой путь в проекте Ha до выполнить хотя бы один раз. При этом следует выписать все имена, "работающие" в рассматриваемом фраrменте проекта, и их значения. При каждом изменении значений переменных старые зна чения зачеркиваются, а рядом записываются новые. Эти значения (контрольные точки) можно использовать в будущей проверке про [раммы на компьютере. Недостатком прокрутки является большой объем ручной работы. Среди опытных проrраммистов весьма популярен метод обсужде 1-tU,я npoe-к:тО6. Суть ero такова. Проектировщик выступает с сооб- щением о проделанной работе перед своими коллеrами. Последние в начале рассказа MorYT ничеrо не знать о проекте, тем более об ero тонкостях. Не понимая, быть может, некоторые детали проекта, они просят автора давать пояснения, что, как правило, приводит к дис куссии, анализу работоспособности проекта и ero оценке. Этот метод зарекомендовал себя как одно из самых эффективных (в отношении стоимости) средств испытания проектов и проrрамм. На этапе аттестации задачи следует составить план проведения Te стирования проrраммы и подrотовить тестовые данные, которые Ha до подобрать так, чтобы можно было испытать проrрамму в HOp 
37 мальных, экстремальных и исключительных условиях. Результаты тестирования должны быть известны до нача.ла ero выполнения. OT метим полезность следующеrо "проrраммистскоrо закона": поболь ше предварительной подrотовки, поменьше творчества за диспле ем. Проверка в 'Н,ормал'Ь'Н,ых условиях предполаrает использование данных, которые типичны в реальных условиях работы проrрам мы. Правильный подбор значений переменных для создания Э1Ссmре .мал'Ь'Н,ых условий зависит от решаемой задачи. Каждая проrрамма характеризуется своими собственными экстремальными данными. Их надо выбрать так, чтобы можно было провести rраничные ис пытания и испытания на rраничные объемы данных. Существуют экстремальные значения как входных, так и выходных переменных. Для числовых данных в rраничных испытаниях следует использо вать начальные и конечные значения области изменения переменной или области определения функции (например, если величина k типа цел принадлежит промежутку [т; n], то надо спланировать провер ку проrраммы при значениях k, равных т, m::i::1, n и n::i::1, адля вещ переменной х Е [а; Ь] испытать значения а, а ::i:: Б, Ь, b::i:: Б, rде Б  по ложительное малое число). Типичные примеры экстремальных зна чений  очень большие и очень малые числа, нулевые значения и отсутствие данных. При проверке символьных и строковых данных следует использовать типичные символы из набора символов, в част ности цепочки из звездочек, нулей, пробелов или пустые символьные константы. Испытания на rраничные объемы проводят для COCTaB ных объектов, причем планируют проверку проrраммы в случаях, если ей на обработку не поступит ни одноrо элемента данных, будет предоставлен только один или слишком MHoro элементов. Провер ка в UС1СЛlОчumел'Ь'Н,ых ситуациях проводится для данных, значения которых лежат вне области определения функций. Такая проверка должна дать ответ, например, на следующие вопросы: что произой дет, если проrрамма, предназначенная для обработки натуральных чисел, станет иметь дело, скажем, с неположительными целыми чи слами, вместо целых чисел (их диапазон возможных значений COCTa вляет промежуток [32768; 32767])  использовать длинные целые числа (диапазон [2147483648; 2147483647]), или если фактические размеры коллекций данных станут превосходить размеры, допусти мые объявлениями, например, будут обрабатываться цепочки сим волов, которые короче или длиннее, чем предусмотрено, и т. д. 
38 В качестве примера проведем анализ правильности алrоритма C""o ростъ и рассто,яние. Этот алrоритм разрешает поставленную зада чу. Действительно, подставив Vt == vo+at в формулу s == (vo+Vt)txO.5, получим s == vot + at 2 /2, что соответствует формуле пути s, прой денноro точкой за время t при равнопеременном движении. Работу алrоритма можно проконтролировать при t == О (тоrда Vt == Vo, s == О), при некоторых фиктивных (но удобных для счета) значениях Vo, а, t (например, Vo == а == t == 1; тоrда Vt == 2, s == 1.5). Исключитель ная ситуация: t'o < О, t < О. Нетрудно выполнить проверку и при заданных в задаче значениях Vo == 7, а == 0.6 и t == 10 (тоrда Vt == 13, s == 100). Тестирование надо выполнять очень тщательно: нет ничеrо хуже в проrраммировании, чем неверно сделанное тестирование. К сожале нию, часто начинающие проrраммисты не планируют тестирование, а пишут проrраммы, надеясь, что они сразу начнут функциониро вать нормально. Вид данных на внешних носителях информации Для упрощения написания проrраммы и удобства пользования ею надо тщательно продумать орrанизацию ввода/вывода. При BBO де естествен свободный, 2иб""иl1 формат данных, представленный простыми правилами; например, "число начинается с цифры или точки (отрицательное число  со знака минус), а заканчивается цифрой или точкой и отделяется от возможноrо последующеrо дaH Horo хотя бы одним пробелом". Ввод данных может сопровождать ся и :ж;ест""ими форматами (см. разд. "Стандартныl1 660д/6Ы60д" 2ла6Ы 5). Выходная информация  важный документ любоrо алrоритма. Она должна начинться с заrоловка решаемой задачи. Любую порцию выводных данных следует снабдить пояснительным TeK стом. Он будет служить комментарием к результатам работы бу дущей проrраммы. При выводе наряду с rибкими шаблонами дaH ных удобны и жесткие форматы. Но их обязательно надо сплани ровать, "нарисовав соответствующие картинки". Выходная инфор мация должна иметь такой вид, чтобы ее можно было без дополни тельноrо редактирования поместить в отчет, в документацию про rpaMMbI. Помните, что компьютер поручает проrраммисту ту рабо 
39 ту, которую тот не возложил на компьютер. Везде, [де это имеет смысл, результаты представьте в табличной форме, в виде rрафиков или диаrрамм. Подумайте об объеме выводимой информации. Как правило, начинающие проrраммисты либо слишком "молчаливы"  "печатают rолые" числа, либо "болтливы"  склонны выводить больше информации, чем требуется. Задайтесь вопросами: вся ли выводимая информация действительно нужна; хватит ли времени и терпения, чтобы ее прочитать. Помните шутку проrраммистов: "Покажи мне твою проrрамму или распечатку, и я скажу, кто ты". Кодирование Наконец наступил черед написания проrраммы  записи алrоритма на языке проrраммирования. Сейчас в мире проrраммирования Ha считывается более двух тысяч языков и среди них  несколько дe сятков очень развитых, мощных, универсальных. Конечно, пользо вателю не надо знать всех их, а достаточно хорошо изучить одиндва языка проrраммирования BbIcoKoro уровня и, работая с ними, OCBO ить правила и приемы составления проrрамм. Нередко выбор языка предопределен стандартами орrанизации (университета, фирмы, OT дела), но так как разные языки имеют MHoro общеrо, то перейти от одноrо языка к друrому в случае необходимости бывает не очень сложно (процедурноориентированнные языки (Паскаль, Си и Фор тран) близки между собой как, скажем, языки славянской rруппы (русский, белорусский и украинский)). Обычно этап кодирования особых трудностей не вызывает, однако иноrда отдельно взятый шаr алrоритма может быть выражен в фор ме, которую нелеrко заменить соответствующей конструкцией язы ка проrраммирования. Заметим, что кодирование должно быть про стым И естественным, так как изощренные средства и хитроумные способы MorYT помешать отладке и модификации проrрамм. На этом этапе решения задачи важно придерживаться так называемоrо KISS принципа: Кеер it simple, stupid! (Делай проще, rлупышка!) [66]. Выполнение проrраммы I Проrрамма написана. Она может состоять из нескольких или co тен тысяч строк текста. Предложена следующая классификация длины проrрамм [68]: малая (меньше 100 строк), средняя (100  1000 
40 строк), большая (1000 10 000 строк) и очень большая (больше 10000 строк). Итак, наступает этап эксплуатации проrраммы. Он состоит из шаrа ввода, заrрузки проrраммы в память компьютера, из шаrа перево да, трансляции проrраммы, шаrов отладки и выполнения. Пользо ватель набирает проrрамму на клавиатуре. Она будет обработана трансляторо.м  "проrраммирующей" проrраммой, предназначен ной для перевода предписаний исходноrо кода в операции, непосред ственно выполняемые компьютером. Различают два вида трансля торов  компиляторы и интерпретаторы. [(о.мnuлятор сначала пе реводит всю исходную проrрамму, создавая ее компьютерный aHa лоr  "литературный" перевод (в нем соответств ие между отдель ными словами подчас и найти трудно, но при этом смысл и дух ис ходноrо текста сохраняется). Запуск компилятора производит поль зователь. Интерпретатор  это пошаrовый транслятор. Он COBMe щает трансляцию с выполнением  сразу после перевода каждый оператор языка выполняется. Такой принцип работы напоминает дословный перевод, подстрочник. Заметим, что интерпретаторы Me дленны (к примеру, при обработке циклов приходится MHoroKpaT но транслировать одни и те же команды), но удобны при работе в диалоrовом режиме (упрощен, облеrчен процесс отладки и модифи кации проrрамм). в режиме интерпретации часто обрабатываются Бейсикпроrраммы и выполняется работа с математическими паке тами Mathematica, MatLAB и Maple. Дальше следует шаr отладки проrраммы. Начинающий проrраммист часто переоценивает свои возможности, считая, что в созданной им проrрамме ошибок нет, и если при ее выполнении получается He суразный ответ, то "виноват" компьютер. К сожалению, в проrрам мах любой длины и сложности есть ошибки  либо синтаксические (возникают при кодировании изза нарушения правил синтаксиса используемоrо языка проrраммирования), либо семантические, т. е. смысловые (MorYT проявиться на любом этапе решения задачи). Pa боту по локализации ошибок называют отладк;оi1. Ошибки синтак сиса не представляют серьезной проблемы, так как в их локали зации участвует транслятор. Более неприятны смысловые ошибки, поскольку проrрамма выполняется, но не так, как мы ждали. Леrче найти ошибки, вызванные исходными данными, сложнее  ошиб 
41 ки, проявляющиеся нереrулярно и не имеющие очевидной связи с исходными данными. Трудно обнаруживаемы и тяжелы ошибки, дo пущенные на этапах постановки задачи, при построении математиче ской модели или разработке алrоритма, так как тоrда проrраммист должен признать свое заблуждение, а потом переделать работу. Такие средства языков, как опции Debug (Evaluate/modify  ариф метический след проrраммы: что она вычисляла; Breakpoints  трассировка проrраммы, информация о всех пройденных контроль ных точках, лоrический след проrраммы: <де она "ходила"), аварий ные выдачи (сообщения о делении на нуль, переполнении разряд ной сетки и т. п.) И выборочные выводы на принтер очень полезны при определении последовательности действий и значений, которые, быть может, явно пользователю не известны. Отметим, что отладка может занять до 90% времени в общем плане решения задачи. После отладки проrрамма сначала тестируется, а потом исполня ется. Так или иначе на этом этапе хозяйничает компьютер. Здесь сказывается ero преимущество над человеком в скорости, точности и аккуратности. Выдача результатов проrона проrраммы производится в разнообраз ном виде. Числа, тексты, таблицы, rрафики, диаrраммы, рисунки можно вывести на экран и/или на принтер, нарисовать rрафопо строителем на листе бумаrи и, таким образом, получить твердую копию результатов. Как правило, компьютеры снабжены электрон ным звукомодулятором, который "иrрает" мелодиюрезультат. И, наконец, последний этап в решении задачи  составление документации. Здесь чрезвычайно полезны текстовые редакторы (Scientific Word, MS Word), настольная издательская система 'ТЕХ и пакеты подrотовки научных публикаций (Scientific Work Place, Math Office и прочее). Проrраммирование формул в алrоритмическом языке лuпеuнымM является алzорuт.М, состоящий из последовательности простых команд (ввода/вывода и присваива ния). Они в записи алrоритма располаrаются в том порядке, в каком должны быть выполнены предписываемые ими действия. Такой по 
42 рядок выполнения называется естественным. Последовательность команд образует составную OMaHдy "цепочка", которая в записи псевдокодом и блоксхемой имеет вид, приведенный на рис. 1.1. OMa'Ндal OMaHдa2 o.мa'Ндan I пом{наа n I Рис. 1.1. Блоксхема команды "цепочка" в математике к линейным алrоритмам относятся алrоритмы, пред ставленные формулами. Они наиболее просты для проrраммирова ния. Заметим, что естественный способ кодировки формул делает проrрамму леrкочитаемой, но нередко приводит к лишним вычисле ниям, поэтому, чтобы избежать повторных вычислений и сократить общее количество операций (а значит, компьютерное время и, может быть, память), выполняйте тождественные преобразования выраже ний. С друrой стороны, надо знать, что не всеrда следует осуще ствлять оптимизацию, поскольку она является не правилом, а ис ключением. Этому есть три причины, rлавная из которых состоит в том, что оптимизация ухудшает наrлядность проrрамм, вторая  выrоды от оптимизации должны быть существенными ("не экономь те на спичках") и третья  современные системы, как правило, име ют удовлетворительные оптимизирующие компиляторы. Рассмотрим при.мер линейноrо алrоритма. Составим проrрамму BЫ числения арксинуса по формуле 
43 arcsin Х  п : (1+ 1:2 : (3+ 12 : (5+ 7(::2J )), [де Iхl < 1. Пусть Х == 0.1234. Этот алrоритм практически поле зен, например, в ситуации, коrда ваш калькулятор не имеет кнопки ARCSIN. Решение таково. Уделим особое внимание эффективности будущей проrраммы. После очевидных преобразований формула для аркси нуса примет вид . Х 50х 4  155х2 + 105 arCSlnX  . V l  х2 24х4  120х 2 + 105 Теперь построим алrоритм вычисления значения полинома Рп(х) == == аох п + alxnl + . . . + anlX + а п в точке Х. ПО сути дела формула Рп(х) == 2:7=0 aixni уже является правилом вычисления последова тельных степеней xni, умножения их на коэффициенты полинома а; и суммирования получающихся произведений aixni. При этом для вычисления Рп(х) потребуется 2n 1 умножен ий и n сложений. Существует друrой, эффективный способ вычисления значения по линома в одной точке, который называется правилом Торнера: Рп(х) ==(... ((аох + al)x + а2)Х +... + anl)x + а п .  nl скобка Такая вложенная форма записи требует n умножений и n сложений, поэтому, кроме экономии КО!lfпьютерных ресурсов (времени, памя ти), она обычно приводит к более точному результату. Назовем t == х 2 И запишем формулу для арксинуса в виде . х (50t  155)t + 105 аrсsшх   . у 1  t (24t  120)t + 105 Ее правую часть обозначим через J( х, t). Теперь все, что мы хотим сделать в проrрамме, опишем псевдоко дом. Этот шаr MHoroe раскрывает. Если вдруr окажется, что мы не можем изложить алrоритм естественным языком, то вряд ли нам удастся составить хорошую проrрамму. (Проrраммисты в Ta ком случае шутят: "Бросьте проrраммирование, займитесь друrой деятельностью". ) Предложенная для решения задача проста, поэтому при разработ ке алrоритма достаточно сделать два шаrа детализации. Их опи 
44 сание псевдокодом дано ниже, rде Уприбл есть значение арксинуса, полученное по заданной формуле, а Уконтр  контрольное значение арксинуса, вычисляемое с помощью стандартной функции arcsin х языка проrраммирования (если в языке не определена така я фун к ция, можно воспользоваться формулой arcsinx == arctg(x/ V 1  х 2 ), Ixl < 1). Запишем искомый алrоритм: алrоритм Арксинус объявить переменные {вещ х, t, Уприбл, Уконтр начало подrотовить исход ные данные вычислить значения арксинусов вывести результаты конец { ввести значение х вывести заrоловок задачи и значение х { :ПРИБЛ := ;(:,:) Уконтр ....... arcsin (х) { вывести заrоловки выходных данных и значения Уприбл> Уконтр /* ео алr Арксипус */ Заметим, что исходные данные нужно, как это сделано в проекте проrраммы, сразу распечатать после их считывания в память KOM пьютера. Это действие называется эхоnроверкоi1. Данные часто Be дут себя в соответствии с законом Мэрфи: "Все, что может испор титься, портится" [66]. (Друrими словами: "Мякину заложишь, мя кину получишь".) Проверку проrраммы выполним при х == О, х == ::!::0.5, х == ::!::V2/2 и х == ::!::VЗ/2. Должны получиться числа О, ::!::0.5235988, ::!::0.7853982 и ::!::1.047198. Кроме Toro, всеrда, коrда имеется возможность про контролировать вычисления с помощью компьютера, будем этой ВОЗ1\ЮЖНОСТЬЮ пользоваться. В данном случае проrраммный KOH троль осуществим с помощью стандартной (встроенной) функции языка проrраммирования (arctan(x/sqrt(1.0  х * х))  в Паскале, asin(x)  в Фортране и Си++). Ошибка 6.==УприблУкотр xapaKTe ризует качество Уприбл' Исходными данными в этой задаче будет число 0.1234. Вид BЫBOД ных данных следующий: 
45 u=================== uАрксинус. uuuuИсходныеuданные: u x =O.1234  u UUUUOTBeTbl: uуuприбл.=uц.цццц uуuконтр.=uц.цццц u=================== Здесь символ u означает пробел (пусто), а символ Ц заменяет любую из цифр О, 1, . . . ,9. Теперь выберем имена, под которыми переменные будут существо вать в проrрамме: дадим х имя Х, t  имя Т, Уприбл имя У и YKOHTP имя Yctrl. Результаты решения таковы: Уприбл == 0.1237, УКОНТР == 0.1237. Замечание Средства языков проrраммирования, необходимые для КОДИрОВа ния линейных алrоритмов, изложены в 2лаве 5. Упражнения Запроrраммируйте предложенные ниже линейные алrоритмы. 1. Выполните вычисления по формуле сложноrо квадратноrо ради к ала: J а т. vb == J (а + v а 2  ь) /2 т. J (а  V а 2  Ь ) /2; а == 3, Ь == 8. 2. Вычислите число 7r по формуле faycca: 7r == 48 arctg(1/18) + 32 arctg(1/57)  20 arctg(1/239). Результат сравните со значением 7r, полученным по формулам 7r  355/113 и 7r == 16 arctg(1/5)  4 arctg(1/239). Замечание pi  Паскаль, 4dO * atan(ldO)  Фортран и MPI  Си++. 3. По формуле Стирлинrа 
46 ( n ) n ( 1 1 139 571 ) n! == v27rn  1 + 12n + 288n2  51840n3  2488320п 4 + . . . вычислите факториал большоrо числа для n == 20. Совет е == 2.718281828459045, 7r == 3.141592653589793. 4. Теорема Харди  Рамануджана дает оценку числа Р(n) разбие ний натуральноrо числа п на натуральные слаrаемые (например, Р (5) == 7, так как 1 + 1 + 1 + 1 + 1 == 1 + 1 + 1 + 2 == 1 + 1 + 3 == 1 + 4 == == 1 + 2 + 2 == 2 + 3 == 5): Р(п)  2" ( Jб(п = 1/24)  2(п  :/24)'/2 ) ехр ../ 2(п  1/24)/3. Подсчитайте число Р(n) при n == 5; 10; 15; 20. 5. Вычислите ne число Фибоначчи по формуле Бине: Рn == (((1 + V5)j2)n  ((1  V5)j2)n)jV5, Рn Е N; n == 5. 6. Подсчитайте суммы следующих числовых (конечных) рядов: n L p==n2(n+1)2j4, k=l n L k4==n(n+1)(2n+1)(зn2+3n1)j30, k=l n L (2k  1)2 == n(4n 2  1)j3, k=l n L (2k  1)3 == n 2 (2n 2  1); n == 100. k=l 7. По приближенной формуле 9 == 978.049( 1 + 0.005288 sin 2 ер  0.000006 sin 2 2ер)  0.0003086h вычислите значение 9 (в cMjceK 2 ) ускорения свободноrо падения на небольших высотах h (в м) над уровнем моря 4 . 8. По приближенной формуле J1(x) == Х (0.5 + а2(хjз)2 + а4(хjз)4 + а6(хjз)6), [де а2 == 0.562499S, а4 == 0.2109357, а6 == 0.03954289, Х == 2.3, вычислите значение функции Бесселя J1(x); абсолютная поrреш ность формулы не превышает 104. 9. Для чисел а, Ь и с найдите произведение р двух наибольших; а == 101, Ь == 77, с == 123. 4 Стандартное (нормальное) зна'Ченuе g, принятое для барометрических pac четов и при построении систем единиц, равно 980.665 см/сек 2 . 
47 Совет Воспользуйтесь формулой р == abc/min(min(a,b), min(b,c)), rде min(11,v) == ((11 + v)  111  vl)/2. 10. Вычислите значения функций "целая часть", "взятие остатка", "дробная часть", "передача знака", "окруrление", min(Xl,X2) и "положительная разность", представленных соответственно форму лами: Е(х) == [х], frac(x) == Х  [х], round(x) == [х + 0.5], dim(xt,x2) == Х}  min(Xt,x2); xt(mod Х2) == Х}  [Xt/X2]X2' Х2 =1 О, sign(Xt,x2) == !Xtlsgnx2, min(xl,x2) == ((х! + x2)IXt  Х21)/2, Хl == 15, Х2 == 4. 11. Вычислите значения функций по формулам: deg(x) == 180Х/71", rad(O') == 71"0'/180, ext ( х) == 1 ОХ , 19 Х == ln xfln 10, log2 Х == ln x/ln 2, maX(Xt,X2) == ((х! + Х2) + IXl  Х21)/2; Х == 1.234567, 0'==45°, Хl == 15, Х2 == 4. 12. AprYMeHT функции sin Х приведите к промежутку [1; 1] по фор муле z == '{(Х!  1)/4}4  21  1, rде Х} == 2Х/71". Вычислите значение sinx == sin(71"z/2); Х == 9.87654321. 13. AprYMeHT функции cos Х приведите к промежутку [1; l]по фор муле z == '{(Х!  1)/4}4  21  1, rде Х} == (71"/2  Х)/(71"/2). Вычислите значение cos Х == sin(71"z/2); Х == 1.23456789. 14. AprYMeHT функции sin Х приведите к промежутку [71" /2; 71" /2] по формуле z == '{(Х  71"/2)/(271")}271"I  71"  71"/2 и вычислите значение синуса; Х == 9.7531. 15. Величина уrла а задана rрадусами 0'0, минутами а' и секундами а". Получите уrол а в радианной мере; 0'==17°10'49". 16. Величину уrла а, заданную в радианах, представьте в rрадус ной мере. Ответ приведите в rрадусах, минутах и секундах; а == == 0.2998524. 
48 17. Определите длину жизни в секундах. Исходные данные  дата дня рождения и текущая дата задаются тремя числами: днем, меся цем и rодом. 18. Приведите проrрамму распределения k мячей между n спорт сменами (k  n). Сколько мячей останется? 19. В сбереrательный банк сделан вклад А рублей из расчета Т% rодовых. Какую сумму получит вкладчик через n лет? Окруrлите результат с точностью до двух знаков после точки; А == 1940 руб., Т == 3, n == 1 О лет. 20. Два вкладчика положили в Сбербанк одинаковые суммы. Пер вый из них взял вклад по истечении т месяцев и получил р руб., а второй, взяв вклад через n месяцев, получил q руб. Сколько Ka ждый из них положил в Сбербанк и сколько процентов выплачивает Сбербанк? 21. Население страны ежеrодно увеличивается на 1/80. Через сколь ко лет население удвоится? 22. Книжный маrазин платит издательству 90% цены, обозначенной на обложке книrи, а продает книrу по обозначенной цене. Сколько процентов составляет наценка маrазина? 23. Пусть у  число, равное rоду выбранной даты, d  выбранная дата. По формуле n == [365.259]  694066 + [зо.56т] + d определите количество дней, прошедших с 28 февраля 1900 rода. Здесь 9 == У  1 для января и февраля, для остальных месяцев 9 == у; т == 14 для января, т == 15 для февраля, а для остальных месяцев т на единицу больше порядковоrо номера месяца выбранной даты (например, если выбрана дата 10 января 1974 rода, то у == 1974, 9 == 1973, т == 14 и d == 10). 24. Определите количество дней между двумя датами (например, между 1 ноября 1969 rода и 1 ноября 2069 rода). 25. Повесть Р. Брэдбери называется "451 о по Фаренrейту". Каким MO rло быть название повести, если температуру измерять в rрадусах Реомюра, Цельсия, Кельвина. Результаты окруrлите с точностью до n знаков после ТоЧКИ. 1 
49 26. Определите, на какой день недели приходится некоторая дата (например, 23 aBrYCTa 1994 rода). Замечание Найдите для этой даты значение n (см. упражненuе 23 даннои славы), разделите n на 7, дробную часть частноrо умножьте на 7 и произведение окруrлите до ближайшеrо целоrо числа. Нуле вой результат соответствует воскресенью, единица  понедельни КУ и т. д. 27. По формуле n = ([2.6т  0.2] + d + у + [у/4] + [с/4]  2с + 777) mod 7 определите, на какой день недели приходится некоторая дата. Здесь d  день месяца, m  номер месяца (1  для марта, 2  для апре ля, ..., 12  для февраля), у  rод столетия (от О до 99; для января и февраля значение у уменьшается на единицу) и с  номер столе ТИЯ (например, для 27 aBrYCTa 1961 rода d == 27, m == 6, у == 61 и с = 19). Значение, равное нулю, соответствует воскресенью, едини ца  понедельнику и т. д. 28. Определите время посадки самолета (в часах, МИНjCтах и ceKYH дах), вылетевшеrо в h часов, m минут, s секунд и находящеrося в полете t секунд. У чтите возможный переход на друrие сутки. 29. Подсчитайте высоту ropbI по результатам визирования ее Bep шины из концов базисноrо отрезка длиной 1; о:' == 7.540, fЗ == 7.650, 1 = 1000 м. 30. Найдите расстояние между Москвой и Севастополем. Координа ты Москвы: широта 55°45', долrота по rринвичу 37°33'; Севастопо ля  44°36' и 33°34' соответственно. Средний радиус Земли равен 6371.032 км. Замечание Воспользуйтесь формулой сферической теоремы косинусов. 
50 rлава 2 р азветвляющиеся алrоритмы При исполнении алrоритмов приходится не только находить значе ния величин, но и анализировать их свойства, сравнивать их друr с друrом и в зависимости от результата сравнения выбирать ту или иную ветвь алrоритма. Алrоритмы, имеющие несколько ветвей (Ha правлений вычислений, действий), называются 1iели1iеf11iыи.. К Ta ким относятся разветвл,Яющиес,Я и 'ЦИ1Сли'ЧеС1Сие ал20ритмы. Для их записи применяются составные команды (аналоrичные сложным предложениям pyccKoro языка). Речь идет о командах "ветвление" и "повторение". Любая из них содержит условие, в зависимости от KOToporo выполняются или не выполняются команды из последова тельности (серии) команд, входящих в составную. Условие Любое свойство величин, которое может соблюдаться или не соблю даться для их текущих значений (число может быть четным или нечетным, одно число может быть меньше или не меньше друrоrо, быть кратным или некратным некоторому значению и т. п.), назы вается условие.w. Условие должно быть таким, чтобы исполнитель алrоритма Mor проверить, соблюдается (истинно) оно или не соблю 
51 дается (ложно) для любых значений входящих в это условие величин (например, равенство х == у выполняется при х == 1 и у == 1 и, скажем, не выполняется при х == 1 и у == 0.9999999; свойством "n  чет но" обладают числа вида n == 2k, k Е N и не обладают числа n == 2k  1 и т. п.). Условием может быть любое понятное исполнителю высказывание, выраженное словесно или аналитически. В частности, условие  это лоrическое значение (истина или ложь), лоrическая перемен ная (переменная, объявленная как имеющая тип лоI') или отноше ние. В алrоритмическом языке отношения представляют равенства и неравенства математики. В них используются общепринятые зна ки (>, <,;?,, ==, #); например, отношение 1 < 2 истинно, а значение отношения Ь 2 4ac;? О зависит от текущих значений коэффициентов а, Ь и с. Заметим, что отношение следует трактовать не как YTBep ждение факта, а как некоторое высказывание, которое может быть истинным (условие соблюдается, отношение выполняется) или лож ным (условие не соблюдается, отношение не ВЬiполняется); напри мер, отношение 1 < 2 не означает, что единица меньше двойки, а ero надо понимать как вопрос: "Верно ли, что 1 < 2?" Простъtе услови'я (высказывания, лоrические значения и перемен ные, отношения) можно соединять союзами и, или. Условия TaKoro вида называются составныlи.. Использование связок и, или анало rично их применению в обычном языке. Пусть Ь 1 и Ь 2  условия. Составное условие Ь 1 и Ь 2 истинно, если соблюдается вместе и b 1 , И Ь 2 (например, двойное неравенство 1  х  2, записываемое в алrо ритмическом языке условием 1  х и х  2, будет истинным, если х Е [1; 2], и ложным, если х tf. [1; 2]). Условие Ь 1 или Ь 2 истинно, коrда соблюдается, по крайней мере, одно из условий Ь 1 или Ь 2 , He важно какое. Перед условием можно написать частицу не. Тоrда, например, условие не Ь 1 истинно, если Ь 2  ложно, И наоборот. Заметим, что лоrические связки и, или и частица не в алrебре лоrики соответствуют лоrическим операциям 1СОН51ОН1С1.{ии (друrие названия: лоrическое произведение, функция совпадения, обознача емая знаком &, /\ или х), ди351ОН1С1.{ии (лоrическая сумма, функ ция разделения, обозначаемая знаком v) и отри1.{ани'я (обозначае мая знаком"" или ). Помимо и, или, не в условиях MoryT присут ствовать следующие связки: исклили (исключающее или, называе 
52 мое также сумма по модулю 2, разделительная дизъюнкция, отри цание эквивалентности, функция неравнозначности, обозначаемая знаком '11 или +), импл ((материальная) импликация, обозначае мая знаком => или -------т) И экв (эквивалентность, тождество, функция равнозначности, обозначаемая знаком =, f----+ или '"'-'). Тоrда условие Ь 1 исклили Ь 2 ложно, если оба условия Ь 1 и Ь 2 либо соблюдаются, либо не соблюдаются; в противном случае данное составное условие истинно. Условие Ь 1 импл Ь 2 всеrда истинно, кроме случая, коrда Ь 1 == истина, а Ь 2 == ложь. Значением условия Ь 1 ЭКВ Ь 2 будет исти на при совпадении значений Ь 1 и Ь 2 ; в противном случае это условие ложно. Альтернатива Сначала определим ?\,ома'НДу (безусловноrо) перехода. Так называ ется простая команда вида иди к мет?\'а, rде метапеременная Meт ?\,а  какоелибо имя (лучше мнемоническое) или номер команды, которой будет передано управление данной командой перехода. Ho мером может быть произвольное натуральное число (например, 10, 20,30 и т. д.). Пометить можно любую команду алrоритма. Теперь познакомимся с ?\,oMaHaoi1 "ветвление". Как известно, rерои сказок по дороrе в тридесятое царство встречали на перекрестке Ka мень с надписьюальтернативой. П роrраммист, разрабатывая алrо ритм, также нередко сталкивается с необходимостью запроrрамми ровать альтернативу и, таким образом, выполнить одно или друrое действие в зависимости от сформулированноrо условия. Эту пробле му помоrает решить команда "ветвление". Она имеет две формы  полную и сокращенную. Полная ?\'оманда ветвления в записи псев докодом и блоксхемой (рис. 2.1) имеет вид если условие то серия 1 иначе сеР ИЯ 2 конецесли 
53 Рис. 2.1. Блоксхема полной команды ветвления Работает она так. Сначала проверяется, соблюдается ли условие. Если оно соблюдается, то выполняется сери'я'l, и на этом работа команды заканчивается. Если же условие не соблюдается, то BЫ полняется сери'я'2, после чеrо работа команды завершается. Команды серий реализуются подряд, каждая по своим правилам. Например, известное из мира сказок "Направо поедешь  себя спасешь, коня потеряешь. Налево поедешь  коня спасешь, себя потеряешь. Пря б " мо поедешь  женатому ыть в записи псевдокодом представляется так: если направо nоедеш'Ь то себя спасешь коня потеряешь иначе если налево nоедеш'Ь то коня спасешь себя потеряешь иначе женатому быть конецесли конецесли Со?\'ращенна'я' ?\'оманда "ветвление" имеет вид (рис. 2.2): если условие то 
54 серия конеЦесли Рис. 2.2. Блоксхема сокращенной команды ветвления Она предполаrает, что при соблюдении условия следует выполнить серию, а при несоблюдении  не делать ничеrо (точнее  пропу стить серию и перейти к выполнению команды, следующей за клю чевым словом конецесли). Команды "ветвление" (с лаконичными условиями и сериями) можно писать "в линию", например: если условие то сеРИЯl иначе сеРИЯ2 конецесли если условие то серия КОНеЦесЛИ Ключевые слова если и конецесли иrрают роль скобок, окаймля ющих команду. Вместо комбинации слов конецесли можно исполь зовать всеесЛИ или, короче, все. Серия может состоять из любых команд (в частности, пустых). К примеру, ранее рассмотренная за дача выбора пути имеет еще и менее краткое решение: если направо поедешь то себя спасешь коня потеряешь конецесли если налево поедешь то коня спасешь себя потеряешь конецесЛИ 
55 если nр,я,мо поедешь то женатому быть конецесли Мноrозначное ветвление Практически нередко приходится выбирать не из двух, а из несколь ких возможностей. Такую ситуацию (мноrозначное ветвление) мож но описать вложенными друr в друrа командами ветвления или (что бывает короче)  х;о.мандой выбора. Она в записи псевдокодом и блоксхемой (рис. 2.3) имеет вид: выбор выражение сnисох; зна'ЧениU1 выполнять сери,я,1 сnисох; зна'ЧениU2 выполнять сери,я,2 сnисох; зна'ЧениUk иначе конецвыбор выполнять сери,я,k выполнять серu.яо сп зна'Чk  сокращение от сnисох; зна'ЧениUk Рис. 2.3. Блоксхема команды выбора Эта команда работает так. Сначала определяется значение выpa жени,я,. Если оно принадлежит сnисх;у зна'ЧениUi (i == 1, 2, ..., k), то выполняются команды cepUUi, и на этом работа всей команды 
56 завершается. В противном случае (значение не принадлежит ни oд ному CnUC1l:Y зН,а'Ч,еНUUj) работают команды сериио, указанной после слова иначе. Например, ранее описанный выбор пути можно теперь представить так: выбор nоедешъ направо выполнять себя спасешь коня потеряешь коня спасешь себя потеряешь женатому быть налево выполнять иначе выполнять конецвыбор В заключение решим задачу вычисления арксинуса по заданному значению х: если 'хl < 1, то arcsin х  х + х 3 /6 + зх 5 /40+ 5х 7 /112; если 'хl == 1, то arcsin х == sgn(x) 7r /2; в противном случае (Ixl > 1) выведем сообщение об ошибке (' uОшибка: u I х I >1. uАрксинусы .') и завершим задачу. Пусть дано х==0.1234. Решение таково. Введем переменную t == х 2 . Используя вложенную форму полинома, получим arcsinx  (((Ы/112 + 3/40)t + 1/6)t + 1)Х. Обозначим правую часть последнеrо равенства через f( х, t). Теперь займемся проектированием алrоритма. Вначале объявим пе ременные и подrотовим исходные данные, а затем приступим к BЫ числен ию арксинусов. Не станем сравнивать вещественные числа (Ixl == 1). Примем следующий порядок проrраммирования ветвей алrоритма. Сначала проверим неравенство 'хl < 1 (оно чаще дpy rих будет истинным) и, если оно выполняется, подсчитаем значение Лх, t). Затем проанализируем условие Ixl > 1. Если оно соблюдает ся, выведем сообщение об ошибке в задании aprYMeHTa и посредством команды стоп прервем выполнение алrоритма; в противном случае (Ix 1== 1) найдем arcsin х ==хп /2. После выполнения действий, задан ных условиями Ixl < 1 и Ixl == 1, вычислим контрольное значение арксинуса и выведем результаты работы. Сделаем два шаrа детализации. Пусть Уприбл есть значение функции, найденное по заданным формулам, а УКОНТР  контрольное значение арксинуса, полученное с помощью стандартной функции языка про 
57 rраммирования. Представим алrоритм в записи псевдокодом: алrоритм Арксинусы объявить переменные начало подrотовить исходные данные вычислить значения арксинусов вывести результаты конец { вещ х, t, Уприбт Уконтр { ввести значение х вывести заrоловок задачи, значение х и заrоловок выходных данных если IxJ < 1 то t  х 2 Уприбл  (((Ы/112 + 3/40)t + l/б)t + l)Х иначе если 'хl > 1 то вывести сообщение об ошибке стоп иначе Уприбл  sgn( х) 7r /2 конецесли конецесли { Уконтр  arcsin (х) вывести значения Уприбл, Уконтр / * ео алr Арксинусы * / Теперь спланируем тестирование. Проверку проrраммы сначала выполним в нормальных условиях (при х == о, х == хО.5, х = :i::V2/2 и х == :i::vЗ/2; результаты  о, ХО.5235988, хО.7853982 и х1.047198), затем в исключительных ситуациях (при Ixl = 2; результат  co общение об ошибке) и, наконец, проведем rраничные испытания в экстремальных условиях (при 'хl = 1; результат  :i::7r /2). Исход ные и выходные данные в этой задаче будут точно такими же, как в ранее рассмотренном примере вычисления арксинусов (СМ. разд. 
58 "ПРО2раммuрованuе формул" 2лавы 1). Теперь переменным проrраммы дадим имена: для х выберем имя Х, дЛЯ t  Т, дЛЯ Уприбл имя У и дЛЯ YKOHTP Yctrl. Результаты работы проrраммы при х == 0.1234 таковы: uуuприбл.=uО.1237 uYuKQHTp.=uO.1237 Замечание Напомним определение функции знак числа (сиrнум): { 1, еслихЕR+; sgn х == о, если х == о; 1, если х Е R. Обозначается также sign х. Замечание Средства языков проrраммирования, необходимые для кодирова ния разветвлений, даны в 2лаве б. Упражнения Запроrраммируйте предложенные далее разветвляющиеся алrорит мы. Считайте все переменные (входные данные) известными. Замечание Переменные а и Ь типа вещ равны, если выполняется условие la  ы  Е. 1. Вычислите значения полиномов Лаrерра Ln(x): 1, если n == о,  х + 1, если n == 1, Ln(x) == х 2  4х + 2, если п == 2, хз + 9х 2  18х + 6, если n == 3, х 4  16х З + 72х 2  96х + 24, если n == 4; n == 3, х == 0.5. 2. Присвойте минимальному значению кубов переменных а, Ь, с, d и е знак переменной с. 
59 3. Х == {х I ах 2 + Ьх + с == О, х Ее}. 4. При заданных n и х вычислите значение cos nх: 2cos 2 х  1, если n == 2, 4соs З х  3cosx, если n == 3, cos nх == 8 cos 4 Х  8 cos 2 Х + 1, если n == 4, 16 cos 5 х  20 соs З х + 5 cos х, если n == 5. 5. По заданным сторонам треуrольника а, Ь, с найдите ero площадь S и радиусы rl описанной и r2 вписанной окружностей. Замечание Треуrольник существует, если полупериметр р больше любой из сторон. 6. Присвойте переменной Q единицу, если точка А(х,у) лежит BHY три Kpyra радиуса r с центром в точке В(Ха, уа), правее прямой х == с и ниже прямой, проходящей через точки D(Xl, Yl) и Е(Х2, У2); в про тивном случае значение Q равно нулю. 7. По формулам понижения степени подсчитайте значение cos n х: (CoS 2х + 1)/2, если n == 2, (cos 3х + 3 cos х) /4, если n == 3, (cos 4х + 4 cos 2х + 3)/8, если n == 4, (cos5x + 5cos3x + 10cosx)/16, если n == 5. cos n Х == 8. Присвойте переменной R единицу, если ближайшее к значению х целое число  четное и отличное от нуля; в противном случае зна чение R равно нулю. 9. Назначьте переменной L единицу, если переменная n делится Ha цело на m или на k, или при делении ее на 1 получается остаток, кратный m или k; в противном случае значение L равно нулю. 10. По заданным х и), вычислите у == f(z,),)+0.1234567, rде z =8х З + 9х,  { Z5 + .sz4 л + 10ZЗ2 + 10z 2 л З + 5zл 4 + ),5, если Z> 1, f( Z, л)  О, если  1  '"  1, Z5  5z4), + 10z З ),2  10z 2 ),З + 5z),4  ),5, если z < 1. 
60 11. Даны прямая у == kx + ь и окружность х 2 + у2 == r 2 . Выясните, пересекаются, касаются или не пересекаются эти линии; а) k == 1, Ь == 2, r == 10; б) k == О, Ь == 10, r == 10; в) k == 4, Ь == 20, r == 1. 12. Определите, пересекаются, касаются друr друrа или не имеют общих точек окружность (х  а)2 + (у  Ь)2 == R2 И прямаяу == kx + [. 13. Даны эллипс х 2 /а 2 + у2/Ь 2 == 1 и прямая у == kx + [. Выясните, пересекаются, касаются или не имеют общих точек эти линии. 14. Пусть а, Ь, с, d  стороны четырехуrольника, а а, (3, /, Б  ero уrлы. Вычислите площадь четы рехуrольника 5 == V (p  а )(р  Ь)(р  с)(р  d), р == (а + ь + с + d) /2; р > а, р > Ь, р > С, р > d. Выясните, можно ли в четырехуrольник вписать окружность и мож но ли около Hero описать окружность. 15. Дана система линейных уравнений аl Х + Ь 1 у + CI Z == d 1 , а2Х + Ь 2 у + С2 '::: == d 2 , азх + Ьзу + Сз Z == d з . Определите, совместна ли она, имеет единственное решение или бес конечное множество решений. 16. Даны точка А(х, у) и вершины треуrольника Р 1 (Хl, Уl), Р 2 (Х2, У2), Рз(хз, Уз). Определите, принадлежит ли эта точка внутренней обла сти треуrольника. 17. Выясните, лежит ли точка Р(Ха, Уа) на прямой у == ах + Ь. При положительном ответе найдите расстояние от этой точки до начала координат; при отрицательном  на прямой найдите точку, имею щую такую же ординату, как точка Р. 18. Преобразуйте прямоуrольные координаты двух точек н(хl, Уl) и Р 2 (Х2, У2) в полярные: .6.х == Х2  хl, .6.у == У2  Уl, (} == v (.6.x)2 + (.6.у)2, ер == т + ер*, { о, если.6.х? о, .6.у ? о, * { % sgn(.6.y), если.6.х == О, т == 71", если.6.х < О, ер == .6. у arct g  если .6.х ..J. О. 271", если.6.х  О, .6.у < о; .6.х' f 
61 19. Даны два треуrольника. По заданному признаку проверьте их pa венство. 20. Даны два треуrольника. Проверьте их подобие по заданному при знаку. 21. Выясните, лежат ли три заданные точки Н(Хl,Уl), Р 2 (Х2,У2) и Рз(Хз, Уз) на одной прямой. 22. Даны прямые А 1 х + в 1 у + С 1 == О И А 2 х + в 2 у + С 2 == О. Проверь те, параллельны или взаимно перпендикулярны они. Если прямые параллельны, найдите расстояние между ними; в противном случае определите координаты точки пересечения. 23. Выясните, лежит ли точка А (Ха, Уа) на прямой у == k х + ь, ниже или выше прямой. Вычислите квадрат расстояния от точки ДО этой прямой. Если точка находится ниже прямой, квадрат расстояния возьмите со знаком минус. 24. Проверьте, принадлежит ли точка А 1 (Хl, Уl) перпендикуляру к прямой у == kx+l, ПрОХОДЯЩЕ'му через точку А 2 (Х2,У2). Если принад лежит, найдите расстояние от точки А 1 дО прямой; если нет, опре делите расстояние между точками А 1 и А 2 . 25. Подсчитайте полярные координаты (r, у) точки по ее прямо уrольным координатам (х, у): О, если х == О, У == О, arctg(y / х), если х > О, У  О, 1т /2, если х == О, У > О, 1т + arctg(y/x), если х < О, 31Т /2, если х == О, У < О, 21Т + arctg(y/x), если х> О, У < О. r == V X2 + у2, у== 26. Определите, является ли треуrольник, заданный координатами вершин Р 1 (Хl, Уl), Р 2 (Х2, У2), Рз(Хз, уз), равносторонним, равнобед ренным (не равносторонним) или общеrо вида. 27. Выясните, можно ли из отрезков а, Ь, с построить треуrольник. Определите ero вид (остроуrольный, прямоуrольный, тупоуrоль ный). 28. В треуrольнике даны уrлы СУ и (3. Выясните, является ли этот 
62 треуrольник остроуrольным, прямоуrольным, тупоуrольным, paBHO сторонним, равнобедренным (не равносторонним) или общеrо вида. 29. Даны стороны четырехуrольника а, Ь, с, d и ero уrлы а, /3, /, /j. Выясните, является ли данная фиrура квадратом, прямоуrольником (но не квадратом), ромбом (но не квадратом и не прямоуrольником), параллелоrраммом (но не квадратом, не прямоуrольником, не pOM бом), не является ни одной из перечисленных фиrур. ЗО. Проверьте, пересекаются ли прямые а1Х+Ь1У+С1 = О, а2Х+Ь2У+ +С2 = О И азх + ьзу + сз = О в одной точке, т. е. а1 Ь 1 С1 а2 Ь 2 С2 = О ? аз Ь з сз 
63 r лава 3 Циклические алrоритмы Теперь рассмотрим циклы. Они  непременная составная часть He линейных алrоритмов. В решенных ранее задачах каждая команда работала не более одноrо раза. Так как наш компьютер с оrромной скоростью выполняет арифметические операции, то ему стоит пору чать задачи, которые требуют MHoroKpaTHoro повторения действий (при разных значениях переменных). rруппа последовательных дей ствий (серия), завершающаяся переходом при выполнении HeKOTOpo ro условия на первую команду этой rруппы, называется цшсло-м. Вид цикла Существуют два основных вида циклов. В одних (циклах сuзвtст пы.М ЧllСЛО-М повторении) явно задается управляющая количеством повторений переменная (nара-метр цикла), ее начальное и конеч ное значения и шаr изменения. Примером TaKoro цикла, называемо [О ариф.м'етuческu.lvt, является задача вычисления в электротехнике общей электроемкости батареи при параллельном соединении KOH денсаторов с емкостями С 1 , С 2 , . . . , Сп по формуле п С пар == С 1 + С 2 + . . . + Сп == L С\. k=l Здесь индекс суммирования k  параметр ЦИК.'lа; ero начальное зна чение и шаr изменения равны единице, а конечное значение есть n. 
64 Имеем налицо цикл типа арифметической проrрессии: а1 == 1, d == 1 и а n == n. Пример друrоrо рода  степенной ряд для вычисления функции Бесселя 00 ln(х) == I: (l)k (x/2)2k+n/(k!/ (n + k)!). k=O В этом алrоритме ачальное значение и приращение параметра цикла k известны, а конечное значение не определено. Процесс CYM мирования здесь можно завершить, как только очередной вычислен ный член ряда ИН1 (х), вошедший в частичную сумму SH1 (х), станет по модулю не больше произведения с ISk+1(X)I, [де Е  заданное Ma лое положительное число. Еще один пример  алrоритм repoHa, позволяющий найти KBaдpaT ный корень из положительноrо числа а по формуле ХН1 == (Xk + a/xk) /2, k Е Zo. Эта формула является penyppeHmHoi1 (от лат. recurrens  возвраща ющийся), так как она позволяет выразить (k + l)й член последо вательности приближений через предыдущий, kй. Последователь ность (Xk) определяется выбором нулевоrо члена ха. Можно ДOKa зать, что если в качестве начальноrо приближения взять любое по ложительное число (например, ХА == (1 +а)/2), то последовательность сходится к корню . Запишем рекуррентную формулу в форме Ньютона Рафсона: Xk+l == Xk  6. k , [де 6. k == (Xk  a/xk) /2, k Е Zo. Она лучше приспособлена для компьютерных вычислений. Процесс итераций закончим, как только добавка (невязка) 6. k == JXk+1  чl станет по модулю не больше Е. Циклы TaKoro рода ('циплы с неизвестнъl.lv( 'ЧислоМ повторениi1) HO сят название итеративных. Часто они реализуют какойлибо про цесс последовательных приближений. Завершается он при условии, что некоторая величина становится (по модулю) достаточно малой. В подобных циклах параметр цикла может быть явно и не задан. Сказанное подтверждают, например, задачи обработки файла или контроля напряжения сети с помощью компьютера: передача файла закончится, как только будет прочитап "конец файла"; компьютер, управляющий работой электрической цепи, постоянно выполняет 
65 операцию "проверить напряжение сети". Здесь налицо бесконечный цикл (бесконечный означает на практике, например, "до ближайшей аварии"). Структура цикла Любой цикл состоит из трех частей: начала, проверки и серии. Ha '{ало  всеrда первая часть цикла. rлавная ero функция  подrо товить цикл, т. е. назначить начальные величины всем переменным, значения которых изменяются в цикле (например, параметру цикла, если он есть). Друrая функция 'Н,а'чдла  выполнить чистку цикла: вычисления, не зависящие от параметра цикла, вынести за цикл и произвести при ero подrотовке. Проверх:а определяет момент выхода из цикла. Она содержит завися щее от переменных серии условие, которое может соблюдаться или не соблюдаться. Именно условие устанавливает, сколько раз подряд будет выполняться сери-я. Сери-я (или тело цикла) состоит из рабо'Чеi1 'Части и продвиJlCе'/iи-я. В первой производятся, например, вычисления по формулам алrо ритма, пересылка данных, вывод текущих результатов и т. п. BTO рая означает: сделать очередное обновление параметра цикла (или величины, иrрающей роль параметра). Отметим, что в итеративных циклах пpoaBUJICe'/iue нередко сливается с рабо'Чеi1 'Частъю. Составные части серии MorYT меняться местами, что влияет на Ha чальное значение параметра цикла (предпервое, первое) и на запись условия. Кроме Toro, проверх:а и сери-я переставимы друr к друrу. Это приводит к тому, что одни циклы ('Цих:лы с предусловие.ч) MO rYT не выполняться вообще, а друrие ('Цих:лы с постусловием) бу дут всеrда работать хотя бы один раз. Поясним сказанное. Решим задачу вычисления общей емкости С пар == I:=l Ck известными cpeд ствами  с помощью команд "цепочка" и "ветвление". Расположим составные части цикла в определенном порядке (рис 3.1). '/iа'Чало  проверх:а  сери-я  Рис. 3.1. Порядок размещения частей цикла с предусловием 
66 Получим 'Цикл с предусловием: С пар  о k  1 } н,а-чало } проверка метка если k  п то С пар  С пар + Ck } k k+l } рабо-ча.я -часть } сери.я npoaeU:JfCeHue ИДИ К метка конецеСJ1И Здесь до входа в цикл начальное значение суммы равно нулю (С пар  О), а значение параметра цикла  еДИНИЦе (k  1). Если с caMoro начала условие не соблюдается (k > п), цикл не выполня ется ни разу, С пар останется равной нулю и управление передается за слово конецеСJ1И. Если же условие k  п истинно, то цикл вы- полняется п раз. Тоrда в теле цикла (в серии) по рекуррентным формулам накапливается сумма емкостей (С пар  С пар + C k ) и ПОk считываются новые значения счетчика цикла (k  k + 1). Заметим, что находящуюся справа от знака присваивания  переменную С пар нужно понимать как старое, предыдущее значение суммы, а слева  как новое, последующее ее значение. Точно также действие команды k  k + 1 можно описать равенством kпоследующий = kпредыдущий + 1. Теперь рассмотрим 'Цикл с постусловием. Порядок следования ero составных частей представлен на рис. 3.2. ..............- н,а-чало  сери.я ..............- проверка  Рис. 3.2. Порядок размещения частей цикла с постусловием в серии продвижение и рабочую часть разместим двояко, сначала так: nродви:JfCен,иерабо-ча.я -часть, а затем в обратном порядке: ра- бо-ча.я астьnрод6и:JfCен,иеl. Получим еще два решения сформули- рованной ранее задачи: lТак же можно было поступить в случае цикла с предусловием. 
67 С пар +------ О } на-чало k +------0 мет-х:а k +------ k + 1 } продвижение } серия С пар +------ С пар + C k } раБО'iая -частъ если k < n } nрО6ер<а то ИДИ к мет-х:а конецесли и С пар +------ О } на'iало k +------1 мет-х:а С пар +------ С пар + Ck } рабо-чая -частъ } серия k +------ k + 1 } продвижение если k ::; n } то nровер-х:а ИДИ к мет-х:а конецесли Здесь серия всеrда выполняется, по крайней мере, один раз, незави симо от начальноrо значения параметра цикла. Повторение Теперь познакомимся со средствами алrоритмической нотации, по зволяющими в ясной И лаконичной форме представлять циклы. Речь идет о командах "повторение". Цикл с предусловием можно описать командами пока выполнять и для выполнять. Это составные команды. Первая из них имеет вид, записанный псевдокодом и пред ставленный rрафически на рис. 3.3. пока условие выполнять серия конеццикл 
68 Рис. 3.3. Блоксхема цикла с предусловием Приведем правила ее работы: сери,я выполняется, пока условие co храняет силу; если же с caMoro начала условие не соблюдается, серия не выполняется ни разу. Часто на практике условие  это лоrиче ское выражение (способное принимать одно из двух значений: исти на или ложь). Тоrда, например, бесконечный цикл .метх;а сери,я иди к .метх;а без труда моделируется командой пока выполнять вида: пока истина выполнять серия конеццикл [де истина есть true в Паскале, 1  в Си и . true.  в Фортране. Зада"tа вы"tислепи,я С пар теперь решается так: С пар +----- О k +----- 1 пока k  n выполнять С пар +----- С пар + C k k +----- k + 1 конеццикл Команда для выполнять предназначена для описания цикла с па раметром. Как только что мы видели, для тех же целей можно поль зоваться командой пока (она универсальнее команды для), однако ДЛЯ делает описание цикла с параметром более лаконичным, на- rлядНЫМ, а значит, и простым. В общем случае команда для BЫ 
69 полнять имеет вид: для i Е М выполнять серия конеццикл rдe i  параметр цикла, а М  некоторое множество. П редпола rается, что известен порядок выборки элементов из множества М. Если в М элементов нет, цикл заканчивается; в противном случае выполняется серия и выбирается очередной элемент. Вид простой команды для выполнять в записи псевдокодом пред ставлен ниже, а блоксхемой  на рис. 3.4. для i от j1 до jз [шаr j2} выполнять серия конеццикл i  jзl (ijз)J i  j1,jз{jJ ri > jз 1( i < jз) Рис. 3.4. Блоксхема простой команды ДЛЯ выполнять Здесь У1 И jз  начальное и конечное значения параметра i, а У2 шаr изменения i. ИЗЛОЖИМ правила работы этой команды с помощью КОМаНД "ветвление" и "цепочка" при j2 > О и2 < О): если Уl  jз /* Уl  jз при У2 < О */ то l  J1 i  Уl + У2 i  Уl + 2У2 l  Jз конецесли серия серия серия серия 
70 Таким образом, серия выполняется, если соблюдается условие i ::::; jз (i ;;::: jз при j2 < О), и не выполняется, если сразу i > jз (i < jз при j2 < О), или коrда в процессе повторений значение i превзойдет jз (i станет меньше jз при j2 < О). Если фраза шаr j2 опущена, по умолчанию предполаrается j2 == 1. Приведем пример, в котором применение команды "повторение" с параметром позволяет упростить запись алrоритма подсчета общей электроемкости: Спар t----- О для k от 1 до п шаr 1 выполнять Спар t----- Спар + C k конеццикл Цикл с постусловием можно описать командой выполнять пока. В записи псевдокодом она имеет вид: выполнять серия пока условие Блоксхема этоrо цикла представлена на рис. 3.5. Рис. 3.5. Блоксхема цикла с постусловием Здесь серия всеrда выполняется один раз, каким бы ни было началь ное значение условия, а затем повторяется до тех пор, пока условие остается верным. К примеру, рассмотренная ранее задача вычисле ния общей емкости имеет еще и такие два решения: 
71 С пар f-------- О k f-------- О выполнять k f-------- k + 1 С пар f-------- С пар + C k пока k < n С пар f-------- О k f-------- 1 выполнять С пар f-------- С пар + C k k f-------- k + 1 пока k :::; n Командная скобка конеццикл в команде выполнять пока не нужна. Ее роль иrрает фраза пока условие. Отметим, что команды повторения с предусловием очень популяр ны (может быть, изза Toro, что, "прыrая в яму, лучше посмотреть до прыжка, куда прыrаем"). Но они не имеют преимуществ перед командой с постусловием (и наоборот). Выбор команды повторе ния задается алrоритмом. Именно он диктует, какую циклическую команду следует применять. Так, если иноrда цикл выполнять не надо (например, при вычислении степени а n или факториала n!, rде n == О или n == 1), то требуется команда ДЛЯ (или, в крайнем случае, команда пока выполнять). Однако при записи алrоритма последо вательных приближений посредством команды с предусловием MO rYT возникнуть затруднения. К примеру, представим алrоритм re рона, используя команду пока выполнять. Дадим переменным Хо, Xk и XHl имя х, а tl k  имя tl. Обратите внимание на подrотовку цикла, на величину tl, равную миллиону (это фиктивное значение ; оно выбрано таким, чтобы на первом витке цикла условие Itll > С было истинным). Вот текст этоrо алrоритма: алrоритм repOH вещ а, С, х, tl начало вывести подсказку I а > О, СИСХОДНЫЙ  Скомпьютерный ======> I ввести а, С вывести заrоловок задачи, а, С Х f--------(1+a)/2 tl f-------- 106 пока Itll > С выполнять tl f-------- (х  а/х)/2 Х f--------Xtl конеццикл / * по с * / выполнять tlf--------0.5x(xa/x) х f--------Xtl пока Itll > С 
72 вывести заrоловок результата, х, контрольное значение va конец / * Терон * / в нем стрелку == == ==> (см. подсказку ) надо интерпретировать как If " С rлаrол вводите. права от команды пока выполнять приведена для сравнения команда выполнять пока, с помощью которой по лучено друrое решение данной задачи. Оно лучше, уместнее первоrо (в нем отсутствует команда подrотовки цикла  t----- 106, что делает алrоритм более ясным); впрочем, оба варианта алrоритма Терона дe фектны: они ненадежны, так как пользователь, несмотря на подсказ ку, может ее проиrнорировать и задать ошибочное, неположительное значение а и/или значение поrрешности Е, меньшее компьютерноrо Е. Предложим надежный вариант ввода исходных данных: выполнять вывести 'ua > Ou ===>' ввести а пока а  О выполнять вывести 'U[исходный  [компьютерныйU ===>' ввести [ пока [< [компьютерный в дополнение к сказанному приведем алrоритм вычисления КОМПЬЮ TepHoro Е. При заданном типе данных он позволит правильно BЫ брать входное значение максимально возможной точности Е. Текст этоrо алrоритма таков: алrоритм Epsilon вещ [, Е начало [ ....... 1.0 /* Компьютерный [ */ выполнять [ ....... 0.5 х [ пока Е > 1.0 вывести' u[ компьютерный =', 2.0 х [ Е.......[+1.0 конец /* ео алr Epsi/on */ При типе данных двойной точности надо заменить объявление вещ с, Е объявлением двточн Е, Е. Кроме Toro, в проrрамме константы 
73 1.0, 0.5 и 2.0 следует представить в форме с двойной точностью. Теперь определим команду прервать. Она, передавая управление за концевую фразу команды "выбор" или "повторение", произво дит специальный выход из тела составной команды к ее преемнику. Команда прерывания в Паскале и Си++  это оператор break, а в Фортране  exit. И наконец, отметим, что умение правильно выбрать команду повто рения и составить проrрамму для циклов разных типов  это значит постичь азы проrраммирования. А рифметический цикл Арифметический цикл  непременная часть алrоритмов табулиро вания функций, вычисления конечных сумм, произведений и т. д. Для их описания везде далее применяется команда для выполнять (см. рис. 3.4), rде в роли i, )1, )з И )2 используются целочисленные данные. Табулирование фУН1\'Циi1  составление таблиц для функций. Таб лицы являются Важным вспомоrательным средством в различных расчетах и исследовательской работе. Для построения таблиц, Be доюстей, rрафиков и т. д. языки проrраммирования Паскаль, Си и Фортран имеют специальные средства (например, rрафические паке ты). к роме Toro, существуют разнообразные текстовые, табличные и rрафические процессоры, СУБД и т. п. [65], но здесь и далее мы будем придерживаться правила: чтобы чемунибудь научиться, надо все делать своими руками. Любая таблица состоит из трех частей: zолов1\И ("шапки") таблицы, ее тела и основания. Тело простейшей таблицы устроено так: в пер вом ее столбце помещается ряд значений apryMeHTa (Хо, Х1, . . . , Xk), а во втором  соответствующие значения функции (УО, У1, .. ., Yk). Разность между двумя соседними значениями aprYMeHTa называет ся шаzом табли'Цы l1i1 == Xi  Xil (i == 1, 2, . . . , k). В большинстве таблиц шаr постоянен. Будем ero ниже обозначать буквой h.. Итак, решим следующую задачу табулирования: для значений apry мента Х == xO(Xk)h, rде ХО и Xk  соответственно начальное и конеч ное значения Х, а h  ша.r изменения Х, построим таблицу полинома 
74 Чебышева 2 TpeTbero порядка Тз(Х) = 4хЗЗх. Пусть Ха = 1, Xk = 1 и h = 0.2. Приступим К решению. Сначала разработаем алrоритм. Зададим ero aprYMeHTbI (ввести Ха, Xk, h), выведем заrоловок задачи, значе ния Ха, Xk, h и "шапку" таблицы. Табулирование функций является циклическим алrоритмом, в котором количество повторений цикла (число строк таблицы) известно. Подсчитаем ero по формуле n = [(Xk  xa)/h + 0.5] + 1. Здесь значение дроби может быть получено с поrрешностью (напри мер, с недостатком), поэтому к (Xk  xa)/h добавляется 0.5. Упра влять циклом будет переменная i, которая принимает начальное значение, равное единице, и изменяется до n включительно с шаrом, равным единице. Текущее значение Х будем находить по формуле Х = Ха + (i  1 )h, rдe i = 1, 2, . . . , n. От формулы Xi = Xil + h, откажемся, так как при таком способе BЫ числения aprYMeHTa ошибки окруrления (усечения) накапливаются. Имея Х, подсчитаем Тз(Х) и выведем элементы строки таблицы. По сле формирования n строк таблицы завершим работу построением ее основания. Приведем текст алrоритма в записи псевдокодом: алrоритм Табулирование вещ Ха, xk, lz, Х, ТЗ цел z начало ввести Ха, Xk, h вывести заrоловок задачи, Ха, Xk, h и "шапку" таблицы для i от 1 до [(Xk  Ха)/ h + 0.5] + 1 шаr 1 выполнять Х +-----xa+(il)h ТЗ +----- (4х 2  3)х вывести Х, ТЗ конеццикл /* по i, т. е. по Х */ вывести основание таблицы конец /* алr Табулирование */ Теперь спроектируем структуру выводных данных. Возьмем KapaH даш, ластик и лист бумаrи "в клетку". Придерживаемся правила 2ЧебbIшёв П. Л. (1821  1894)  русский математик и механик, основатель петербурrскоt\ математической ШКОЛbI. 
75 "один символ  одна клетка". Пробел будем изображать, как и paHЬ ше, символом U или оставлять пустую клетку. Спланируем строку таблицы. В ее начале предусмотрим поле из одноrо пробела. Bы вод значения Х выполним в виде (подруrому, в формате) UUId'Ц.'Ц, а значения Тз(х)  в формате UUId'Ц.'Ц'Ц'Ц, rде символ Ц заменяет oд ну из цифр О, 1, ..., 9. Вертикальная запись пробела и минуса Id означает, что перед первой цифрой неотрицательноrо числа будет выведено "пусто", а у отрицательноrо  знак "минус". Над каждым столбцом значений в центре столбца поместим ero имя, а в центре, над таблицей  имя таблицы. Строкой из минусов отделим исход ные данные от выходных, а строками из знаков = (вверху и внизу) укажем rраницы области вывода. Итак, должна получиться таблица следующеrо вида: u=============================== uТаблицаuфункцииuТ3(х)=4х**33х. uuuuИсходныеuданные: uxO=1.0uuuuh=uO.2uuuuxk=ul.0 u uuuuOTBeTbl: uПолиномuЧебышева uuuuux uuuu T3(x) UUUIdЦ'ЦUUIdЦ'ЦЦЦ u=============================== Контрольные точки в этой задаче таковы: Тз(l) = 1, тз(а) = О, Т з (1)=l и Тз(::!:0.4)==F0.944. Перед кодированием выберем переменным имена: Ха назовем ха, Xk  Xk, h  Н, Х  Х, Тз  ТЗ, п  N и, наконец, i дадим имя 1. Алrоритм был представлен Паскалем, Си, Фортраном и успешно выполнен. Одномерный массив Элементы коллекций (структур данных) часто нумеруются. Так в формулировках ноrих задач встречаются обозначения аа, Ь 1 , Xj, Yi+1, C k И т. п. Эти переменные являются координатами векторов, коэффициентами полиномов, элементами таблиц и т. д. Например, в 
76 задаче вычисления конечной суммы С пар == Lk=l C k электроемкости С 1 , С 2 , ..., Сп образуют линейную таблицу из п элементов с общим именем С. Каждому элементу таблицы поставим в соответствие ero порядковый номер (индек:с). Теперь стоит задать индекс, и сразу ясно станет, о каком элементе таблицы идет речь. Перенумерован ный набор элементов называют массивом, а линейную коллекцию данных, элементы которой имеют одинарный индекс (координаты, коэффициенты и т. д.),  одномерным массивом. Любой массив  это составное данное с произвольным доступом, так как, вопервых, все ero элементы одноrо (базовоrо) типа и, BOBTOpЫX, все элементы одинаково доступны и MorYT выбираться непоследовательно. Чтобы указать: "некоторая коллекция является одномерным масси вом", пишут объявление массива, ['де задается тип ero элементов (компл, вещ, двточн, цел, лоr, симв, строк и т. п.), затем ключе вое слово массив (можно таблица), потом имя массива (V1, V2, ..., V n ), за которым в квадратных скобках стоят начальный (Н1, Н2, ..., 'Н: n ) и конечный (в1, в2, ..., в n ) порядковые номера ero элементов, разделенные двоеточием (если начальный номер есть единица, мож но писать только конечный номер). Вот вид об5,явлени,я массивов V1, V2, ..., V n : тип массив V1[[H1 :}в1], V2[[H2 :}в2], ..., Vn[[H n :}в n ] Начальный и конечный порядковые номера определяют COOTBeT ственно нижнюю и верхнюю rраницы изменения индекса. Разность между ними плюс еДиница равна прот,яженности измерени,я, а .мощностъ (длина, "к:ардиналъное число") массива есть количество ero элементов (заметим, что значения протяженности и мощности у одномерноrо массива совпадают). В объявлении массива ero элемен там можно присвоить начальные значения. В роли rраниц измерений разрешены имена переменных. Их тип и значения следует указать в объявлении типа. Приведем пример объявления и задания массива С. Пусть батарея состоит из трех конденсаторов (п == 3) и С 1 == 1000 мкф, С 2 == 20 мкф, С з == 100 мкф,. Вот возможные объявления и задания значений Mac сива с: LJ вещ массив С[l : 3] ввести С 
77 LI вещ массив С[З] f-------- 1000,20,100 LI цел п f-------- 3 вещ массив С[п] f-------- 1000,20,100 и т. д. При этом с массивом можно работать как с неделимым объек том (ввести С), но чаще нужны ero элементы. Они обрабатываются (вычисляются, пересылаются и т. п.) так же, как любые друrие пе ременные. В операциях с составными данными лучше создать базу данных, что удобно, выrодно, надежно. Рассмотрим еще один пример использования одномерноrо массива. Решим следующую задачу: на плоскости на расстояниях (21, (22, . . . , (}n от центра KpyroBoro кольца с радиусами r1 и r2 расположены точки. Необходимо определить количество точек, попавших внутрь кольца. Решение начнем с построения математической модели. Из расстоя ний (21, (22, . . . , (2n образуем массив Р == ((2i) (i == 1, 2, . . . , п). Условия попадания iй точки внутрь кольца запишем в виде двойноrо Hepa венства r1 <: (2i < r2 (i == 1, 2, ..., п). В алrоритмической нотации оно имеет вид r1 < f!i и (2i < r2. Пусть число точек на плоскости равно десяти (п==10). Теперь разработаем алrоритм. Чтобы сделать ero универсальным, введем в рассмотрение константу lim со значением 1000, после че [о можно объявить вещ массив P[lim] заведомо большей длины, чем фактический массив Р[п] длины п. Вот шаrи алrоритма: объ явим константу, переменные и массив, подrотовим исходные данные и приступим к проектированию цикла. Обозначим через k счетчик числа точек, находящихся внутри кольца. Ero начальное значение должно быть равно нулю, поэтому в подrотовке цикла предусмотрим действие k f-------- О. ДЛЯ подсчета числа точек, попавших внутрь кольца, зададим последовательность целочисленных значений переменной i, начиная от единицы. Будем п раз проверять условие r1 < (2i и (2i < r2' Если на очередном витке оно соблюдается, увеличим счетчик k на единицу и выберем для проверки следующее значение (2i. Так как элемент массива (2i более одноrо раза используется в условии, заме ним ero, например, простой (т. е. неиндексированной) nереме1t1tой t. От такой замены будущая проrрамма станет эффективнее (по BpeMe ни исполнения; обращение к элементу массива производится за два 
78 шаrа: первый  подсчет индекса и второй  выборка значения ин дексированной переменной ). Перебор значений f!i выполняется, пока истинно неравенство i  n. Коrда i превзойдет значение n, выйдем из цикла, т. е. перейдем к следующему по порядку действию  выводу результатов работы алrоритма. В процессе конструирования алrоритма сделаем два шаrа детализа ции. Они в записи псевдокодом представлены ниже: алrоритм Мишень объявить данные начало подrотовить и скопировать исходные данные подrотовить цикл подсчитать число точек вывести результаты конец конст lim f----- 1000 цел n, k, i вещ массив P[lim] вещ rl, r2, t ввести n, массив Р и радиусы rl, r2 вывести заrоловок задачи и значения n, Р, rl, r2 { k f----- О для l от 1 до n шаr 1 выполнять t f----- f!i если rl < t и t < r2 то k f----- k + 1 конецесли конеццикЛ { вывести заrоловки выходных данных и значение k Теперь спланируем тестирование. Проверку проrраммы в нормаль 1* ео алr Мишень * I 
79 ных условиях выполним при n == 10 и m == 2, rде m  число точек, находящихся внутри кольца. В экстремальных условиях rраничные испытания проведем для n == 1, n == 1000, m == О, m == 1, m == 1000. Подберем расстояния и радиусы: р == 12.34 56.78 90.98 7.6 0.54 0.03 21.0 12.89 7.41 99.99 Т} == 12.35 Т2 == 56.78 Выходные данные в этой задаче будут иметь вид: u================================== uМишенъ . uuuuИсходныеuданные: u n =uu 10 uМассивuР [n] : uu12.З4uu56.78uu90.98uuu7.60uuuО.54 uuuО.ОЗuu21.00uu12.89uuu7.41uu99.99 uruвнутр=12.56uuuuruвнеш=56.78 u uuuuOTB ет : uвнутриuццццuточек. u================================== Пjшступим К кодированию. Для константы lim выберем имя Lim, для переменной n  имя N, дЛЯ k  имя К, дЛЯ i  имя 1, для массива Р  имя Р, дЛЯ переменной Т}  имя R1, дЛЯ Т2  имя R2 и для t  имя Т. Результат работы Паскаль, Си и Фортран проrрамм  вывод сообщения: uвнутриuuuu2uточки. Замечание О средствах языков проrраммирования, использованных при KO дировании циклических алrоритмов, СМ. славу 7. При решении задач, сформулированных далее в упражнениях, MorYT потребоваться: алrоритм нахождения наибольшеrо (наименьшеrо) из множества значений; алrоритм вычисления частичной суммы; алrо ритм вычисления значения полинома; алrоритм нахождения остатка от деления m на n. Изложим их. Пусть дана конечная последовательность (Xi) (i == 1,2, ..., n). Для определенuя nаuболъшеzо ее 'Члеnа выберем начальное значение Х mах , 
80 равное заведомо малому числу (например, Х тах == 1038 дЛЯ IBM совместимоrо компьютера), а затем используем формулы { Xi' Х тах == Х тах , если Xi > Х тах , если Xi :::;; Хтах' Наименьшее значение Xmin находим так: { Xi' Х min == ;{min, если Xi  xmin' если Xi < Xmin, Здесь начальное значение Xmin  заведомо большое число (напри мер, 1038). В обоих случаях цикл можно начать со значения i == 2, но тоrда исходное значение Х тах (или Xmin) должно быть равно Х1. Алrоритм вычисления частичной суммы выrлядит следующим обра зом. Пусть дана последовательность (Xi) (i == 1, 2, ..., п). Сумму первых п ее членов будем называть пй 'Частu'Чнлt1 СУММОЙ и обо значать 5n. Итак, по определению, имеем n 5n == Хl + Х2 + . . . + Х n == L Xi, i=1 откуда при i == 1 получим 51 == Х1, при i == 2 получим 52 == Х1 + Х2 == == 51 + Х2, при i == 3 получим 5з == Х1 + Х2 + Х3 == 52 + Х3 и т. д., Ha конец, при i == п получим 5n == Х1 + Х2 + . " + Х n == 5n1 + Хn' Таким образом, для вычисления iй частичной суммы имеем следующую рекуррентную формулу: 5 i == 5i1 +Xi (i == 1,2, ..., п), rдe 50 == О. Представим алrоритм вычисления значения полинома. Используя вложенную форму полинома Р ( ) n + n1 + + ,",n ni n Х == аох а1 Х . . . а n == L..,i=O ai X , в соответствии с которой Рn(Х) == ((... (аОХ + а1)Х + а2)Х +... + an1)X + а n , получим рекуррентную формулу для вычисления значения полино ма в точке Х: Yi == Yi1X + ai (i == 1, 2, ..., п), rде Уо == ао. Алrоритм нахождения остатка от деления т на п: остаток при деле 
81 нии найдем по формуле т  [mjn]n. Для вычисления TaKoro OCTaT ка в Паскале предусмотрена операция т mod п, в Си  операция т % п, а в Фортране  встроенная функция mod (т, п). Упражнения Составьте проrраммы циклических алrоритмов. Считайте, что все входные параметры (переменные и массивы) заданы. 1. На плоскости даны точки Pi(Xi, Yi) (i == 1, 2, . . . , п). Найдите при надлежащую третьему квадранту точку, максимально удаленную от начала координат; п == 13. 2. Сформируйте массив из значений полинома Лаrrера (Lagger): Lo(x) == 1, Ll(X) == xl, Ln(x) == (x2n+1)Ln1(x)(n1)2Ln2(x); n == 16, х == 0.5. 3. Вычислите сумму всех членов последовательности (Xi) (i == 1, 2, . . . , п) за исключением членов, кратных т, k или [; п == 15. 4. Дан вектор а == (ai) (i == 1,2, ..., п). Получите вектор Ь == (b i ) (i == 1,2, ..., п), первые элементы KOToporo являются отрицатель ными элементами вектора а, затем в Ь следуют нулевые элементы вектора а и последние элементы Ь  положительные элементы ис ходноrо вектора; п == 13. 5. Вычислите средние арифметическое А(аl,а2,... ,а n ), rеометриче ское G( аl, а2, . . ., а n ), rармоническое Н( аl, а2,. . . , а n ) и квадратиче ское Q(al, а2,,'" а n ) членов последовательности (Xi) (i == 1, 2, ..., т) за исключением членов, кратных k; т == 21 (см. упражнение 67 части IIп. 6. Вычислите элементы векторов а == (ai) и Ь == (b i ) (i == 1, 2, ..., п), если аl == 1000, Ь 1 == 1, а; == (ail + bi1)j2, Ь ; == J ail b il (i == 2,3, ..., п); п == 16. 7. Для уменьшения влияния случайных ошибок производится сrла живание экспериментальных данных. При этом элементы BeKTO ра а == (ai) (i == 1, 2, . . . , п) пересчитываются по формуле а; == == (ail + а; + ai+l)j3 (i == 2,3, ..., п  1). Найдите минимальный и максимальный элементы исходноrо и преобразованноrо векторов и их порядковые номера; п == 13. 
82 8. Объедините два вектора а== (ai) и Ь == (b i ) (i == 1, 2, . . . , n) в один: al, b 1 , а2, Ь 2 , ..., а n , Ь n ; n == 9. Найдите наибольший элемент HOBoro вектора и ero номер. 9. Дана последовательность А == (ai) mах(аl + а n , а2 + anl, аз + an2, ...); (i == 1, 2, ..., n). Получите n == 16 или n == 17. 10. Известен возраст rруппы людей, состоящей из n человек: У == (Yi) (i == 1,2, ..., n). Выясните средний возраст rруппы и процент людей, возраст которых лежит в пределах от k до т лет; n == 16. 11. В целочисленном массиве А == (Щ) (k == 1, 2, . . . , n) подсчитай те наибольшее количество одинаковых, идущих подряд элементов; n == 13. 12. Вычислите площадь полиrона (мноrоуrольника), заданноrо KO ординатами вершин Pi(Xi,Yi) (i==l, 2, ..., n); n == 28. 13. Две стороны и уrол между ними нескольких треуrольников явля ются элементами массивов А == (ai), в == (b i ) И r == C,i) (i == 1, 2, ..., n). Выберите из этой коллекции треуrольник с наимень шей площадью и вычислите ero высоту, проведенную к стороне ai (i==l,2,...,n); n==11. 14. Вычислите ]((k) == 7r/(2b n + 1 ), О :::; k < 1, используя следующий алrоритм: ао == 1, Ь о == VТ=k, ai+l == (ai + b i ) /2, b i + 1 == у' aibi (i == О, 1, ..., n). Найдите А+l == (ai+l  b i + 1 )2 /4; n == 99, k == 0.5. 15. Дан полином степени n: Рп(х) == L:o aixni. Сформируйте вектор Ь из коэффициентов полинома Qnl(X) == L:i':Ol bixnil, полученноrо в результате дифференцирования Рn (х); n == 13. 16. Найдите k  наименьшее число элементов, которые нужно BЫ кинуть из последовательности щ, а2, ..., а n , чтобы осталась возра стающая последовательность [35]; n == 13. 17. Подсчитайте количество различных элементов, встречающихся в массиве А == (ai) (i == 1, 2, . . . , n). Повторяющиеся элементы учи тывайте один раз; n == 16. 18. Полином Рn(х) == аохn + alXnl +... + а n , ао i- О Ус Е R можно представить в виде Рn(Х) == (х  c)(boxnl + blXn2 +... + bnl) + R, rде коэффициенты b k определяются по схеме ropHepa (Horner): b k == == Cbkl + ak, Ь о == ао, Ь N == R (k == 1, 2, ..., n). Получите вектор Ь == (b k ) (1;; == 1,2, ..., n);] Р7(х)==х72х6+3х5х4хЗ+3х22х+1; 
83 c==l. 19. Отделите корни полинома Рn(Х), используя теорему о кольце, в котором находятся корни алrебраическоrо уравнения aOXn+a1Xn1 + +... + а n == о: r  Iхl  R, r == lanl/(A + lanl), R == 1 + В / laol, rдe А == max(laol,la11,. . . ,lan11), В == max(l a 11,l a 21,. . . ,Ianl), ао =1 о, а n =1 о; х ==  + iry; ] Р4(Х) == х 4 + 4х 3  7х 2  22х + 24. 20. Пронормируйте вектор а == (ai) (i == 1, 2, . . . , п) по ero нормам: II a l1 1 == тах lail, II a ll 2 == 2::7=1 lail, II a ll 3 == ) 2::7=ll a iI 2 ; b i == ai/llalll' t Ci == ai/ IIa112, d i == ai/ IIall3 (i == 1,2, ..., п); п == 10. 21. Отделите положительные корни алrебраическоrо уравнения аохn + a1Xn1 + . . . + а n == О, ао =1 о, используя теорему Макло рена (Maclaurin): х+ < 1 + \!В/ао , ао > О. Здесь а т (т  1)  первый из отрицательных коэффициентов уравнения (если TaKO ro коэффициента нет, отсутствуют и положительные корни), В  наибольший из модулей отрицательных коэффициентов уравнения; ] х 4 +4х 3  7х 2  22х+ 24 == О. 22. Даны два вектора а1  а2  ...  а n и Ь 1  Ь 2  '"  Ь т . Образуйте вектор с из данных векторов а и Ь при условии, что Сl  С2  . . .  с n + т ; п == 16, т == 17. 23. Вычислите целые корни уравнения х n + a1Xn1 + . . . + а n == О с целыми коэффициентами (а n =1 О). Эти корни следует искать cpe ди всевозможных делителей свободноrо члена а n ; ] х 4 + 4х 3  7x2 22x + 24 == О. 24. Дано число а Е N. Выясните, а (а > 1)  простое или составное. Образуйте массив из ero кратных делителей. 25. Дан вектор Х == (Xt') (i == 1, 2, ..., п). Найдите длину т самой длинной "пилообразной (зубьями вверх)" последовательности иду щих подряд чисел: Xj+1 < Xj+2 > Xj+3 < ... > Xj+m; п == 15. 26. Дан вектор а == (ai) (i == 1,2, ..., п). Все ero элементы, не paB ные нулю, перепишите, сохраняя их порядок, в начало вектора, а нулевые элементы  в конец (вспомоrательный вектор запрещен); п == 13. 27. Вектор Ь == (b k ) (k== 1,2, ..., п) состоит из нулей, единиц и ДBO ек. Переставьте элементы вектора так, чтобы в ero начале распола 
84 rались единицы, затем нули и, наконец, двойки (вспомоrательный вектор запрещен); n == 13. 28. Даны целочисленный вектор а == (а j) (j == 1, 2, . . . , n) и число k. Найдите такое множество элементов Щ!, ai2' ... , ai m (1  II < < . . . < i m  n), что ai! + ai 2 + . . . + ai m == 3k; n == 14. 29. Число k задано массивом двоичных цифр ао, аl, . . . , an1: k  == an1 х 2n1 + an2 Х 2n2 + . . . + аl х 2 + ао, ['де ai == О или ai == 1 (i == о, 1, ..., n  1). Получите массив двоичных цифр числа k + 1. Переведите k + 1 в десятичную систему счисления. 30. Найдите пять "случайных" целых чисел из промежутка [1; 36] (Tk == {7r + llTkl}' То Е (о; 1), n Е N) или шесть  из проме жутка [1;45] (Tk == {(7r  2 + Tk1)2}, То Е (о; 1), n Е N). Формула для получения "случайноrо" целоrо числа в диапазоне [а; Ь] такова: [(Ь  a)Tk + а + 0.5]. Найдите минимальное и максимальное из пяти и шести чисел. Итеративный цикл Цикл данноrо типа очень распространен. Он  составная часть алrо ритмов последовательных приближений, алrоритмов обработки бес конечных последовательностей, рядов, произведений, непрерывных дробей и т. д. Для ero описания подходят любые команды повторе ния. rлавная проблема, которая при этом возникает,  окончание итеративноrо цикла. Очевидно, что каждый проrраммист хотя бы однажды написал проrрамму, которая стала невольной реализацией бесконечноrо цикла (т. е. вела себя подобно известному из фольк лора rерою: "У попа была собака. Он ее любил. Она съела. .. " и т. д.). Как выйти из замкнутоrо Kpyra? rде rарантия, что для опре деленноrо набора данных цикл завершится после HeKoToporo числа итераций? Эта проблема неразрешима в общем случае. В каждой конкретной ситуации решить ее удается. В вычислительных задачах будем поступать так: заменим цикл с неизвестным числом повторений циклом с известным числом, для чеrо введем в рассмотрение некоторую целочисленную переменную i, зависящую, быть может, от переменных алrоритма и являющуюся счетчиком цикла, ero параметром. Пусть значение счетчика меняет 
85 ся от единицы с шаrом, равным единице, до HeKoToporo предельноrо значения i max . Подберем это число. Оно должно быть не слишком малым и не слишком большим. В учебных задачах i max равно дe сяткам, сотням, а в прикладных, практических  сотням, тысячам. Таким образом, ответ на вопрос, как представить алrоритм, в KO тором MHoro итеративных шаrов, единствен: в таких алrоритмах не может быть большоrо числа шаrов. Тоrда, если в роли i max брать небольшие целые числа (десятки, сотни, тысячи), то всеrда полу чим информацию: процесс итераций прерван либо при соблюдении условия (некоторая величина стала малой; получен правдоподобный результат; ero можно использовать), либо при истинном HepaBeH стве i > i max (за i max шаrов процесс итераций не сошелся; получен неверный результат, но ero следует обязательно вывести на экран или на принтер, чтобы "по отпечаткам пальцев" судить опричинах "катастрофы", происшедшей в теле цикла: слишком малы значения i max и/или поrрешности с (и при этом результат может бытьтаки правдоподобным), есть смысловые ошибки в подrотовке цикла и/или в рабочих формулах и т. д. И т. п.). Такой подход делает алrоритм (а значит, и соответствующую проrрамму) надежным, универсаль ным и мобильным (надежности алrоритмов надо уделять перво степенное внимание; один из "законов" проrраммирования rласит: "Лучше никакой проrраммы, чем ненадежная" [16]). При описании итеративных циклов будем использовать 1\:Оманду no вторения для (см. рис. 3.4) в следующих двух надежных вариантах: ДЛЯ i от 1 ДО i max шаr 1 выполнять если условие то иди к мет1Са конецесли серия конеццикл обработать аварийную ситуацию / * i > i max * / м,ет1Са и для i от 1 ДО i max шаr 1 выполнять серия если условие то ИДИ к мет1Са конецесли конеццикл обработать аварийную ситуацию / * i > i max * / мет1Са 
8{) Как видим, первый вариант представляет итеративныи 'ЦU1СЛ с npe дусловuем, а второй  с nостусловuем. Заметим, что специаль ный выход из тела цикла здесь выполнен командой перехода, т. е. это как раз тот случай, коrда "использование фразы из четырех букв типа иди к чрезвычайно полезно даже в высшем обществе" (команда прервать здесь не подойдет, ибо она передает управление преемнику составной команды). Итак, в нашем распоряжении есть четыре составные команды (команды "цепочка", "ветвление", "выбор" и "повторение") и две про стые (команды перехода и прерывания). Эти комбинируемые по He обходимости средства дают нам "механический конструктор", позво ляющий описать вычислительный процес произвольной сложности, сохраняя отчетливое видение структуры процесса в целом и каждоrо ero фраrмента в отдельности. Теперь рассмотрим примеры реализации итеративных циклов. Об щим в них будет использование рекуррентных формул и тщатель ная подrотовка циклов, в частности, их чистка. Она делает любой аЛrоритм ясным, надежным и эффективным. Отметим, что в ре1СУР- рентнои формуле и n == Лn,иn1)' n Е N, ио == а индексы имеют друrую природу, чем индексы элементов массива. Здесь n, n  1 и О являются номерами приближений (фиксатора ми "момента жизни" значений переменной и) и тоrда для ссылки на и n , иn1, ио следует выбирать неиндексированные имена. Дpy rими словами, для представления в итеративном алrоритме. членов последовательности (и n ) не требуется объявление массива u(n тах ] (неизвестна длина этоrо массива, так как неизвестно число итера- ций). Такой подход в конечном итоrе приводит к экономии ресурсов компьютера (резервируемой памяти и времени исполнения). Бесконечная последовательность Вычислим с точностью с: универсальную постоянную 7r, последова- тельно приближая ее полупериметрами рn правильных мноrоуrоль ников, вписанных в окружность единичноrо радиуса. Подсчитаем чи сло итеративных шаrов, при котором первый раз выполнится Hepa венство рп  pn1 < с; n Е N. Пусть с == 1015. 
87 Приступим К решению. Вы знаете, что 7["  трансцендентное число, приближенно равное 3.14 (если потребуется более точное значение, то ero можно найти в справочнике или в математическом пакетеj в настоящее время число 7[" вычислено с фантастической точностью  более двух миллионов знаков). Мы же вовсе не "изза любви к 7["" бу дем решать сформулированную выше задачу. На примере ее решения выясним, как строится бесконечный процесс, сходящийся к искомо му ответу, и с какими "подводными рифами можно столкнуться" при реализации этоrо процесса на компьютере. Итак, разработаем алrоритм вычисления числа 7[", основанный, Ha пример, на формуле удвоения. Начнем с какоrонибудь простоrо правильноrо мноrоуrольника, скажем, с шестиуrольника. Впишем ero в единичную окружность. Половина длины такой окружности равна 7[". Пусть ао  половина стороны шестиуrольника, а РО  ero полупериметр. Будем удваивать количество сторон вписанных мноrоуrольников. Обозначим половину стороны двенадцатиуrоль ника через al, двадцатичетырехуrольника  через а2 и т. Д., а их полупериметры  соответственно через Pl, Р2, ... . Очевидно, что ро == 6ао, Рl == 12аl == 6 х 2al, Р2 == 24а2 == 6 х 22а2, . . . . Значения Ро, Pl, Р2,..'  последовательные приближения числа 7[", причем lim Рn == 7[". noo Так как последовательность (Рn) оrраничена сверху, условие OKOH чания цикла приближений запишем в виде неравенства Рn  pnl < с. Теперь выведем формулу, связывающую половины сторон anl и а n двух вписанных мноrоуrольников. Пусть АС  сторона вписанноrо мноrоуrольника (рис. 3.6) с числом сторон qnl == 6 х 2n1, а АВ и ВС  стороны мноrоуrольника с удвоенным числом сторон qn == = 6 х 2 n . в о Рис. 3.6. Стороны вписанных в окружность мноrоуrольников Применим теорему Пифаrора последовательно к треуrольникам О DC и В DC. Получим рекуррентное соотношение 
88 а n == J (l  J 1 a;1)/2, n Е N, ао == 0.5. Используя ero, найдем Рn == qnan, rде qn == 2qn1, qo == 6, Ро == 3. Приведенные формулы дают возможность подсчитывать число 7r с любой точностью с. Приступим К проектированию проrраммы. В декларативной части алrоритма объявим необходимые переменные и зададим начальные значения ао == 0.5, qo == 6 и Ро == 3. Эти значения постоянны; они опре деляются видом исходноrо мноrоуrольника. Исполняемую часть Ha чнем с ввода с и Птах' Именно эти величины в алrоритме являются переменными исходными данными. После вывода заrоловка задачи и эхопроверки опишем итеративный цикл (с постусловием) по пере менной n, принимающей значения от единицы с шаrом, равным 1, до HeKoToporo целоrо числа Птах (paBHoro, например, 100). Внутри ци клической части вычислим значения а n , qn, Рn И проверим условие окончания "бесконечноrо процесса" PnPnl <с. Если оно выполнит ся, предусмотрим выход из ЦИКЛа и вывод результатов; в противном случае (условие Рn  Pnl < сложно) заменим значение Pnl значе нием Рn И сделаем новый виток. Заметим, что в случае сходимости итеративноrо процесса выход из цикла будет сделан при истинном неравенстве Рn  Pnl < с, а не по условию n > Птах, так как Hepa венство Рn  Pn1 < с должно выполниться за несколько десятков шаrов и n при этом не успеет превзой1'и значение Птах' Тем не менее предусмотрим обработку следующей ситуации: если выход из цикла будет совершен по условию n > Птах, выведем сообщение об ошиб ке и "ошибочные" результаты. Такой подход rарантирует алrоритму надежность. Для решения поставленной задачи достаточно двух шаrов детализа ции. Заметим, вопервых, что переменным qo, qnl И qn, переменным ао, anl и а n и, наконец, переменным Ро и Pnl можно соответственно отвести одни и те же области памяти q, а и Pn1; BOBTOpЫX, для xpa нения последовательных приближений числа 7r не нужно объявлять массив, так как на каждом итеративном шаrе требуются только два приближения Pnl И рn' Далее псевдокодом представлен только BTO рой шаr детализации, так как первый имеет такой же вид, как и в предыдущих задачах (объявить переменные, подrотовить "сырье", 
89 получить и вывести "продукцию"): алrоритм 7r ДВТОЧН Е, а  0.5, q  6, Pпl  3, Рп цел птах, п начало ввести Е, птах вывести заrоловки, Е, птах для п о т 1 ДО птах ша r 1 ВЫПОЛНЯТЬ а  J (1  у' 1  а 2 ) /2 q  2ч Рп  ча если Рп  pпl < Е ТО иди к .метка конецесли PH1  Рп конеццикл вывести сообщение об ошибке меттщ вывести заrоловки, Рп, Тl конец /* алr 7r */ Контрольное число в этой задаче 7r == :3.141,59265:3.589793. Для oцeH ки компьютерноrо времени можно взять Е == 10.з, 10Б, 10T и т. д. АрrУ!\1ента!\ш аЛI'оритма являются числа Е == 101Б и птах == 100. Pe зультаты работы проrраМ!\1Ы представим в виде: /* к выводу 7r *1 /* по п, т. е. по Е */ u================================ uЧИСЛОuПИ. uuuuИсходныеuданные: ueps=1.0e15 unumax=uuul00 u uuuuOTBeT: uПИ=Ц.ЦЦЦЦЦЦЦЦЦЦЦЦЦЦЦuuuuП=ЦЦЦЦЦЦ u================================ ;1адиt\! ё Иl\!Я Eps. a' IIl\lЯ А, q  ЮЛЯ Q, Pп1  имя Рп1, Рп  имя Рп. птах . имя ЛТта.т и, наконец, п  имя лr. Составить ПрОI'рам "1У по ра'зработаННО"l' ранее алrоритму н(' представляет большоrо труда. ПервоЙ была написана, отлаж('на и тестирована Паскаль. 
90 проrрамма. Получился следующий ответ: 11" == 3.141592654321215; чи сло итераций n == 10 [66]. Этот результат неудовлетворительный. По теря точности объясняется оrраниченностью разр ядной сетки CYM  матора. Координаты ошибки  команда а  V (1  V 1  а 2 ) /2. Здесь подстереrли нас "волчьи ямы" окруrления: произошло пропа дание значащих цифр при вычитании близких величин. Поправим дело. В формуле а n == V (1  ) 1  a;1 ) /2 перенесем иррациональность в знаменатель. Получим новую peKYP рентную формулу а n == an1/ V 2 (1 + ) (1  an1)(1 + an1))' После корректировки проrраммы за 18 итераций был получен xopo ший результат: 11" == 3.141592653589790. Задача вычисления 11", несмотря на свою простоту, лишний раз ПОk тверждает правило, что проrраммирование  и.скусство получения нужных ответов от компьютера. Рассмотрим еще пример бесr.;оне'Чно11 последовательности. В 1202 ['. итальянский математик Фибоначчи сформулировал и решил следу ющую задачу [23]: каждый месяц пара кроликов дает приплод  двух кроликов (самца и самку), которые через два месяца дают HO вый приплод. Найти число кроликов в конце ['ода, если в начале ero была одна новорожденная пара. Ответом в этой задаче являет ся число 377. Мы же выясним, через сколько месяцев количество кроликов будет больше заданноrо числа а; а  3, а Е N? Решение задачи заключается в следующем. Пусть 1n обозначает чи сло пар кроликов через n месяцев (при отсчете от начала ['ода). В начале ,ода была одна пара кроликов (10 == 1), а через месяц  две (11 == 2). После второ,о месяца новая самка приносит пару KpO ликов, следовательно 12 == 10 + 11. Рассуждая аналоrично, получим, что число кроликов после n месяцев можно подсчитать по peKYP рентной формуле j == 1n 1 + In2, 12 == 2, 3, . . . , 10 == 1, 11 == 2. Она определяет бесr.;оне'Чную nоследоватеЛЬНОсrпЬ 'Целых 'Чисел, HO 
91 сящую имя Фибона'Ч'Чи. Любой ее элемент равен сумме двух непо средственно предшествующих элементов. Представим эти рассуждения средствами алrоритмическоrо языка. Предложим следующий порядок действий. После объявления, зада ния и вывода исходных данных выясним, принадлежит ли а области определения, т. е. выполняется ли условие а  3. Если оно соблюда ется, приступим к вычислению членов последовательности Фибонач чи. Исходя из ее определения в подrотовке цикла положим 10 == 1 и 11 == 2. Для подсчета номера первоrо фибоначчиевоrо числа, больше ro а, выполним цикл по цело численной переменной n, принимающей значения 2, 3, ... , Птах, rде, например, константа Птах равна 44 (Ta кое значение Птах рекомендуется для типа данных longint Паскаля, long  Си++ и integer  Фортрана; Птах == 45 для типа unsigned long Си++ (см. nодразд. "Пелое 'Число" разд. "[(онстанта" 2ла БЫ 5); фибоначчиевы числа быстро возрастают: 142 == 701408733, 143 == 1134903170, 144 == 1836311903 и 145 == 2971215073). В начале цикла находим 1n, а потом проверяем условие 1n > а. Коrда оно первый раз выполнится, выведем значения n, 1n и совершим сnе'Ци алъныu выход из цикла; в противном случае (условие 1n > а ложно) заменим значения 1n2 и 1n1 соответственно значениями 1n1 и 1n. При истинном неравенстве n  Птах цикл повторим. Если ни одно значение 1n не превзойдет а, выполним нормалъныu выход из цикла, выведем сообщение' Все 1n :::; а' и концевую фразу' Всё...'. Если условие а  3 не соблюдается, то сообщим об ошибке в задании а (' а < 3') и выведем фразу' Всё...'. Заметим, что в этой задаче, как и в предыдущей, не следует резер вировать массив для значений 1n, так как, вопервых, неизвестна ero длина, и, BOBTOpЫX, на каждом шаrе проверки нужны только три последовательных числа: 1n2, 1n1 и 1n. Назовем их в проекте алrоритма соответственно 10, 11 и 1. При разработке проекта были сделаны два шаrа детализации. Далее в записи псевдокодом пред ставлен только второй шаr: алrоритм Фибона'Ч'Чи конст цел Птах f---- 44 цел а, 10, Л, n, 1 начало ввести а 
92 вывести заrоловок задачи, значение а и заrоловок выходных данных если а ;? 3 то 10 +------ 1 11 +------ 2 для n от 2 до Птах шаr 1 выполнять 1 +------ 10 + 11 если 1 > а то вывести n, 1 иди к .метка конецесли /* ео 1 > а */ 10 +------ !I .fI +------ 1 конеццикл /* по n */ вывести сообщение ' Все 1n  а.' иначе вывести сообщение об ошибке' а < 3.' конецесли /* ео а ;? 3 */ .метка вывести концевую фразу' Всё...' конец /* ео алr Фuбо'ttа'Ч:ЧU */ Спланируем тестирование проrраммы. Сначала при а = 101 ВЫПОk ним проверку ее работы в нормальных условиях. В экстремальных условиях rраничные испытания проведем для а=3, а=1836311902 и а = 1836311903. В исключительных ситуациях положим а = 2. Теперь предложим "картинку" выходных данных. Она может иметь вид u=================== uЧислаuФибоначчи. uuuuИсходныеuданные: u a =uuuuuuu 101  u uuuuOTBeT: un=ЦЦ uf=цццццццццц uBceu. . . u=================== 
93 Перед кодированием алrоритма выберем имена: дадим Птах имя Nтax, а  имя А, 10, Л и 1  соответственно имена РО, Р1, F и, наконец, n назовем N. Результаты работы проrраммы таковы: при а == 101 найдено n == 10 и ЛО == 144. Бесконечное произведение Рассмотрим задачу обработки бесконечноrо произведения: вычи слим rиперболический косинус 00 chx == П (1 + х 2 /((2n  1)71)2)2), n=l используя условие окончания циклическоrо процесса х 2 /((2n  1)71)2)2 < Е, И подсчитаем, при каком значении n первый раз выполнится это неравенство. Пусть Е == 104 И Х == 0.39. Решение таково. Математической формулировкой данной задачи бу дет: найти произведение 00 Р== П иn(х), n=l rдe ип(х) == 1 + х 2 /((2п  1)7r/2)2; циклический процесс прервать, как только выполнится неравенство х 2 /((2п  1)71)2)2 < [. Сначала выведем рекуррентное соотношение. Обозначим ne частич ное произведение через Рn' Полаrая n == 1, 2, . .. и РО == 1, последо вательно найдем, что P 1 == Ul (х) == РО Х Ul (х), Р 2 == Ul(X) Х И2(Х) == P 1 Х И2(Х), Р п == Ul(X) Х И2(Х) Х .,. Х иn(х) == Pnl Х иn(х), Итак, рекуррентная формула для накопления частичных произве дений имеет вид Р п == Pnl Х иn(х), n Е N, rде РО == 1. Теперь приступим к проектированию алrоритма. После объявления 
94 переменных, задания исходных значений, вывода заrоловков и эхо проверки осуществим подrотовку и чистку цикла, положив COOTBeT ственно РО  1 и t  х 2 . Затем орrанизуем цикл по переменной n, принимающей значения 1, 2 и т. д. до заведомо "большоrо" числа Птах, paBHoro, например, 100. В циклической части найдем значение дроби х 2 / ((2n  1)11"/2)2, присвоив ero вспомоrательной переменной n (n будет использоваться дважды  в рекуррентной формуле и при проверке неравенства), вычислим Рn И проверим условие OKOH чания цикла. Коrда неравенство n < е выполнится, выйдем из ци кла, проконтролируем вычисления с помощью стандартной функции языка проrраммирования и выведем результаты; в противном слу чае (условие n < Е: не соблюдается) повторим цикл вычислений и т. д. Приведем проект алrоритма, записанный псевдокодом, rде отражен последний (второй) шаr детализации: алrоритм Coshyp конст двточн 1'i /2  1.5707963267948966 двточн х, Е:, РО, t, n, Рn, Pn1, УКОНТР цел Птах, n начало ввести х, Е:, Птах вывести заrоловок задачи, Х, Е:, Птах И заrоловок выходных данных РО  1 t  х 2 для n от 1 до Птах шаr 1 выполнять n  t/((2n  1)11"/2)2 Рn  Pn1(1 + n) если n < Е: то иди К .метка /* к вычислению УКОНТР */ конецесли конеццикл /* по n, т. е. по Е: */ вывести сообщение об ошибке, Птах .метка УКОНТР  ch( х) вывести заrоловок результатов, n, Рn, УКОНТР конец /* алr Coshyp */ Отметим, что в этом алrоритме (при соответствующих исходных дaH 
95 ных) выход из цикла (специальный) будет произведен по условию п < С, так как для выполнения этоrо неравенства нужно сделать Bcero несколько десятков шаrов. Тем не менее в проекте предусмо трена обработка аварийной ситуации  выход из цикла (нормаль ный) при условии п > птах и вывод С09бщения об этом. Теперь спланируем проверку. При х == 0.39 значение rиперболическо ro косинуса, представленное в формате 'Ц.'lfЦ'lfЦ, равно 1.0770. Кроме Toro, проrрамму будем тестировать посредством стандартной функ ции языка проrраммирования (0.5* (ехр(х) +ехр( x))  в Паскале; cosh(x)  в Си++ и Фортране). Задачу решаем для следующих исходных данных: х == 0.39, с == 1O4 , Птах == 100. Пусть "картинка" выводных данных будет такой: u===================================== urиперболическийuкосинусuсоsh(х). uuuuИсходныеuданные: uх=О.З9uuuuерs=1.0еО4uuuuпumах=uuul00 u uuuuOTBeT: uп=ццццццuuuuсоsh(х)=ц.цццц uuuuuuсоsh(х)uконтр.=ц.цццц u===================================== Наконец, займемся кодированием. Начнем с выбора имен: назовем 1r/2, х, с, t, 6. п , Уконтр, птах и п соответственно Р2, Х, Eps, Т, D, Yctrl, Nтax и N. Поскольку по условию задачи не требуется запоминать частичные произведения Рn, п Е Zo, будем их текущие значения хранить в одной и той же области памяти с именем Р. Результаты выполнения проrраммы таковы: за 13 шаrов было най дено, что ch(0.39) == 1.0758; при этом контрольное значение косинуса получилось равным 1.0770. В заключение отметим следующее. Вопервых, в только что решен ной задаче цикл вычислений следует строить (это лучше) как ариф метический, rде предельное значение п можно найти из неравенства п < с; вот это значение: [(2Х/(пу'с) + 1)/2 + 0.5]. BOBTOpЫX, рекуррентную формулу Р п == Pnl Х ип(х) (п Е N, 
96 Ра == 1) можно использовать в друrих алrоритмах, например, при подсчете значений пфакториала. Так называется функция 1(п), для которой 1(0) == 1, 1(п + 1) == (п + 1)1(п), n Е Zo. При n Е N имеем п! == 1 х 2 х . . . х п. ФУ'/tкчи-я nдвoиHoи факториал определя ется как 1!1 == 1, п!! == 1 х 3  ... х (п  2) х n  при нечетном n и О!! == 1, 2!1 == 2, п11 == 2 х 4 х . . . х (п  2) х n  при четном. Так как факториальная функция часто является операндом в выражениях типа ДВТОЧН и ее значения быстро растут, то тип значения функции ДОЛЖеН быть ДВТОЧН, ДЛИНДВТОЧН или расширенныИ. Замечание При кодировании рассмотренных ранее циклических алrоритмов потребуются средства языков проrраммирования, о которых мож но прочитать в 2лаве 7. Упражнения Решите сформулированнные далее задачи (6 == 107 и 6 == 1015). He вязку в условии окончания повторений можно написать без знаков абсолютной величины, если выяснить поведение последовательных приближений (оrраниченность последовательности сверху/снизу). 31. Вычислит е Хт+l и Y(Xr+l), rдe y(x)==x3+x1000,Xr+l== == ij 1000  Х т , r Е Zo; Ха == 10, jXr+l  х т I  6 (*). При каком r первый раз выполнится неравенство (*)? 32. С помощью итеративной формулы для вычисления обратной Be личины У == l/х, Х =1- О, Уп+l == Yп(2XYп), n Е Zo, /ХУп+l  11  Е (*) вычислите 1/z2: z == 5.000621, Уа 0.03. При каком n первый раз выполнится неравенство (*)? 33. Вычислите Хт+l и g(Xm+l), rде g(x)==sinxxcosx, Хт+l == == xmg(xm)/g'(xo), т Е Zo; Ха == 4.7, 'Хт+l  х т !  Е (*). При каком т первый раз выполнится неравенство (*)? :34. По итеративной формуле вычисления обратной величины KBaд paTHoro корня у == l/fi, х > О, Уп +l == Уп(3  ху;)/2, 11 Е Zo, IXY;+l  11  [ (*) найдите 1/ J 1 + р2; Р == :3.001768, Уо == 0.3. При каком п первый раз выполнится неравенство (*)? :3.5. Вычислите Xk+l и 1(Xk+l)' rдe 1(х) == Х З  0.2:1:2  0.2х  1.2, 
97 ХН1 == Xk  f(xk)(b  xk)/(f(b)  f(Xk)), k Е Zo; Ха == 1, Ь == 1.5, 'ХН1  xkl  Е (*). При каком k первый раз выполнится HepaBeH ство (*)? 36. По итеративной формуле вычисления корня у ==.ух, Х  О , Уn+l == (3Уn + x/y)/4, n Е ZO, IY+1  Х!  Е (*) найдите  1 + r 2 ; r == 1.001234, Уа == 1.2. При каком n первый раз выполнится HepaBeH ство (*)? 37. Вычислите t p и <.p(t p ), [де <.p(t) == t  sin t  0.25, t p == sin tp1 + 0.25, рЕ N; t a == 1.2, 41tp  tp11  Е (*). При каком р первый раз выпол нится неравенство (*)? 38. По итеративной формуле Ньютона (Newton) для вычисления корня у == 1{1X, Х  О, Уn+1 == (9уn+х/у;)/10, n Е ZO, IY:'1  хl  Е (*) найдите \'1 1 + из; и == 2, Уа == 1.5. При каком n первый раз ВЫПОk НИТСЯ неравенство (*)? 39. Вычислите Zp+1 и <.p(Zp+1), [де <.p(z) == zЗzl, Zp+1 == 2 ij zp + l zp, рЕ Zo; Za == 1, IZp+l zpl  с (*). При каком р первый раз выпол нится неравенство (*)? 40. По итеративной формуле Лаrранжа (Lagrange) для вычисле ния корня У == {/Х, Х > О, Уn+l == yn(S/7  y/(7x)), n Е Zo, IY+l  Х!  Е (*) найдите V1 277009 + w 2 ; W == 15, Уа == 6. При каком п первый раз выполнится неравенство (*)? 41. Вычислите Х n и f(x n ), [де f(x) == х з + 5х 2  15х  7, х n == Xn1  f(xn1)/f'(xn1)  f"(Хn1)j2(Хn1)/(2f'З(Хn1))' n Е N; Ха == 2.4, Ix n  Xn11  Е (*). При каком n первый раз выполнится неравенство (* )? 42. Вычислите корень У == .ух, х > О, k Е N по формулам Лаrран жа (Lagrange) Уn+1 == уn(1 + l/k  y/(kx)) и Ньютона (Newton) Уn+! == ((k  1)уn + x/y1)/k, n Е Zo; Уа == (х + (k  1))/2, IY+1  xl  Е (*). При каком n первый раз выполнится HepaBeH СТВО (*)? Учтите, что х == 9025, k == 7. 43. Вычислите обратную величину корня У == 1/.ух, х > О, k Е N по формулам Лаrранжа (Lagr<inge) Уn+l == yn(k + 1  xy)/ k и Ньютона (Ne\vton) уn+! == ((I.;1)Yп+1/(xy1))/k, n Е Za; Уа == 2/(x+(k1)), 
98 'Y+1 х  11  € (*). При каком n первый раз выполнится неравенство (*)? x==11025,k==5. 44. Вычислите У ==.jX, х > О по формуле Уn+l == Уn(3  Y/ х )/2, n Е Zo, Уо == (х + 1)/2, IY+l  xl  € (*) и обратную величину l/х по формуле УНl == Yk(2  XYk), k Е Zo; О < ХУо < 2, IXYk+l  11  € (**). При каком n и k первый раз выполнятся неравенства (*) и (**) ? 45. Разложение а > О на х > О и а  х > О называется золотыlM се'ЧеtUем числа а, если х явл яется ср едним rеометрическим чисел а и а  х. Из равенства х == v a(a  х) имеем q == х/а == 0.5(V5  1). Вычи слите q по формуле : q == J 1 + j 1 + V 1 + у!1 +. . .  1; qпоследующее  qпредыдущее  € (*). На каком шаrе первый раз выполнится неравенство (*)? 46. Вычислите е  основание натуральных (неперовых, N apier) ло rарифмов: е == lim (1 + 1/n)n; е n +l  en€ (,,:). noo При каком n первый раз выполнится неравенство (*)? 47. Вычислите е  основание натуральных лоrарифмов: е == lim n/ Yi;J; е n +l  en€ (*). noo При каком n первый раз выполнится неравенство (*)? 48. Вычислите У == ln 2 по формуле: У == Ji(l/(n + 1) + 1/(n + 2) +... + 1/(2n)); Уn+l  Yn€ (*). При каком n первый раз выполнится неравенство (*)? 49. Вычислите р (р Е N) по формуле: р == 1 /Ji( (Р + 2 Р +... + np)/n p + 1 )  1; Рn+l  Pn€ (*). При каком n первый раз выполнится неравенство (*)? 50. Вычислите постоянную Эйлера (Euler): С == lim (1 + 1/2 + 1/3 +... + 1/n  ln n); СП  Cn+l€ (*). nOO При каком n первый раз выполнится неравенство (*)? 51. Вычислите постоянную Эйлера  Маскерони: ,== П е 1 / n /(1+1/n); 'n'n+l€ (*). n=1 При каком n первый раз выполнится неравенство (*)? 
99 52. Вычислите число 7r по формуле Валлиса (Wallis): 00 7r==2П4n2/(4n21); 7rn+17rn:::;;e (*). n=1 При каком n первый раз выполнится неравенство (*)? 53. Вычислите число 7r по формуле: 7r == 4 П (1  1/(2n + 1)2); 7r n  7r n +1 :::;; е (*). n=1 При каком n первый раз выполнится неравенство (*)? 54. Вычислите число 7r по формуле: 7r==6/(exkg2(1+2/k)(1)kXk); 17rk+17rkl:::;;e (*). При каком n первый раз выполнится неравенство (*)7 55. Вычисл ите число 7r по формуле: P nt1 == 2 n V 2  V4  P:!:j2 2n , Р 2 == 4V2, 7r  P n + 1 (n == 2, 3,. . . ); Рn+1  Рn:::;;е (*). При каком n первый раз выполнится неравенство (*)7 . 56. Вычислите число 7r по формуле: 7r == 2/ ((1  1/(22 Х 12)) Х (1  1/(22 Х 22)) Х (1  1/(22 Х 32))...); 17r n  7r n 11 :::;; е (*). При каком n первый раз выполнится неравенство (*)7 57. Вычислите константу 7r по формуле Мэшина (Machin): 7r == 16 f (1 )n1 / ((2n  1 )52n1)  4 f (1 )n1 / ((2n  1 )2392n1); n=1 n=1 16/((2n  1)52n1) :::;; е (*). При каком n первый раз выполнится неравенство (*)7 58. Вычислите число 7r по формуле: 7r= lim 2 n х ./ 2  . / 2 + V2 +... + V2 ; \7r n +1  7r n l:::;;e (*). nOO V V    n радикалов При каком n первый раз выполнится неравенство (*)? 59. Вычислите число 7r по формуле Виета (Vieta): 
100 2 1r== . Л l Л 11т   +  ... n....оо 2 2 2 2 1 1 + 2 2 1 1 + 2 2  + . .. +    +  fI 2 2 2 2У2 v n множителей В ней kй множитель содержит k радикалов; l1r n +1  1r n l C: (*). При каком n первый раз выполнится неравенство (*)? . 60. Вычислите число 1r, последовательно приближая ero полупери метрами описанных прав ильных мноrоуroльников. Подсчитайте KO личество итеративных шаrов, необходимых для нахождения 1r с точ ностью Е. Вложенный цикл До сих пор мы имели дело с nростъt.Ми (одинарными) циклами. Но циклы MorYT вкладываться друr в друrа. Такой сложный цикл Ha зывается "'ратным или составным, при этом любой окаймляющий цикл именуется внешним, а вложенные в Hero  внутренними. Правила орrанизации и работы кратных циклов аналоrичны прави лам для простых циклов. Кратные циклы описываются вложенными друr в друrа командами "повторение". Такие "слоеные" циклы надо строить особенно тщательно и аккуратно, что означает, в частности, следующее. Каждый из циклов должен начинаться с подrотовки (и с чистки). Войти в любой цикл можно только через ero заrоловок (через слова пока, ДJIЯ, ВЫПОJIНЯТЬ). Параметры внешнеrо и BHY TpeHHero циклов разные и изменяются не одновременно (при фикси рованном значении параметра внешнеrо цикла параметр BHYTpeHHe ro принимает поочередно свои значения). В кратном цикле каждый внутренний цикл является фраrментом рабо-ч,еi1 -ч,асти внешнеrо по отношению к исходному циклу. Ключевые слова конеЦЦИКJI вло жен ной команды "повторение" должны появиться в тексте алrорит Й " " ма раньше таких же слов охватывающе команды повторение, т. е., друrими словами, требуется, чтобы цели, реализуемые внутренним циклом, были достиrнуты не позже, чем цели внешнеrо цикла. На практике наиболее распространены простые циклы, а из KpaT 
101 ных  двукратные и троекратные. правильно орrанизованноrо a60ftH020 [под20тО61'Са 6нешне20 'ЦU1'Сла J для i от 1 до т шаr 1 выполнять [под20тО61'Са 6нутренне20 'ЦU1'Сла J ДЛЯ j от 1 до п шаr 1 выполнять 1'co.мaHды конеццикл [ 1'co.мaHды} конеццикл /* по i */ Здесь внешний цикл управляется счетчиком i, а внутренний  счет чиком j. Их начальные значения и шаrи изменения равны единицам, а конечные  соответственно т и п, что можно кратко представить так: i == l(т)l и j == l(п)l. Приведем пример HeKoToporo 'ЦU1'Сла для: /* по j */ Множество точек плоскости Проиллюстрируем сказанное на примере. Решим задачу нахожде ния rеометрическоrо места точек: на плоскости ХОУ отметим MHO жество точек, координаты которых удовлетворяют заданной системе неравенств (*). Составим проrрамму, которая выделенную область заполнит косыми чертами ("слэшами"), а остальную часть плоско сти  точками; Х == XO(Xk)X, У == YO(Yk)Y, Пусть Х == 1.5(1.5)O.1, у= 1.5(1.5)O.1. Решение заключается в следующем. Сначала представим множе ство точек плоскости, удовлетворяющих системе неравенств (*), на рис. З.7: х 2 + у2  1 ! ; (*) XO YX 
102 у 1 1 1 Рис. 3.7. Множество точек плоскости Назовем i max и jmax  количество точек по осям х и У COOTBeTCTBeH но, причем i max == [(Xk  Ха)/6х + 0.5] + 1, jmax == [(Yk  Уа)/6у + 0.5] + 1. Здесь значение любой из дробей может быть вычислено с HeДOCTaT ком. По этой причине к ним добавляется 0.5. Ось ординат расположим вертикально вдоль экрана дисплея (бу мажной ленты принтера), а сами ординаты У будем вычислять по формуле У == Yk  (j  1 )6у (j == 1, 2, ... , jmax). Ось абсцисс Ha правим слева направо по ширине ленты. Абсциссы Х будем находить так: Х == Ха + (i  1)6х (i == 1,2, ... ,i max ). Условие Ь попадания точки (Х, У) в выделенную область запишем лоrической формулой Ь == (х2 + у2  1) и ((Х  О и у;;3 О) или (Х;;3 О и У  х)). Теперь установим иерархию циклов, определив внешний и 'BHYTpeH ний циклы. Так как при построении изоrраммы будем двиrаться в направлении "сверху вниз" (этот путь проделаем за jmax шаrов), а на каждом шаrе "сверху вниз"  делать i max шаrов в направлении "слева направо", то орrанизуем арифметические циклы по двум пе ременным: внешний  по переменной У, или, что то же самое, по целочисленной переменной j == 1(jmax)1, а внутренний  по пере- менной Х, т. е. по цело численной переменной i == 1 (i max ) 1. Примем следующий порядок действий: сначала объявим перемен- ные, затем введем исходные данные, потом выведем заrоловок за- дачи, произведем эхопроверку Данных, выведем заroловок ответов и, наконец, подrотовим циклы, вычислив jmax И i max . Затем начнем цикл по }, rде выполним подroтовку BHYTpeHHero цикла, вычислив 
значения У и у2, И откроем цикл по переменной i, в начале KOTOpO ro найдем значение Х. Потом проанализируем условие Ь. Если оно соблюдается (точка попала в выделенную область), выведем симво лы 'u/'; в противном случае (условие ложно)  символы 'u.'. Ko rда i превзойдет свое конечное значение i max , будет rOToBa строка изоrраммы (она состоит из i max косых черт и (или) точек). COBep шим переход на новую строку (выведем управляющий символ новая строх:а: #13#10  в Паскале, \n  в Си и /  в Фортране) и при выполнении условия j  jmax повторим цикл по пере мен ной j, т. е. по количеству строк в изоrрамме. Проект алrоритма рисования изоrраммы в записи псевдокодом при веден ниже: алrоритм ИЗО2рамма вещ Ха, Xk, ДХ, Уа, Yk, Ду, У, у2, Х . . .. цел }mах, Zmax, }, Z начало ввести Ха, Xk, ДХ, Уа, Yk, Ду вывести заrоловок задачи, Ха, Xk, ДХ, Уа, Yk, Ду и заrоловок результатов jmax +----- [(Yk  Уа)/ Ду + 0.5] + 1 i max +----- [(Xk  Ха)/ ДХ + 0.5] + 1 для j от 1 до jmax шаr 1 выполнять У +----- Yk  (j  1)Ду у2 +----- У Х У для i от 1 до i max шаr 1 выполнять Х +-----xа+(i1)дХ если Ь /* ь  см. ранее */ то вывести' u/' иначе вывести' u . ' конецесли конеццикл вывести новая строх:а конеццикл вывести основание выводных данных конец 103 /* по i, т. е. по Х */ /* по j, т. е. по У *1 /* алr ИЗО2рамма */ 
104 Тестирование проrраммы выполним визуально  по выходным дaH ным. Должна получиться прямоуrольная таблица символов, COCTO ящая из jmax строк И i max столбцов. Ее выделенная часть (точки этой области удовлетворяют системе (*)) будет заполнена косыми чертами, а остальная  точками. Перейдем к записи проrраммы на языках проrраммирования. Ap rументами в этой задаче являются следующие числа: Ха ==  1.5, Xk == 1.5, X == 0.1, Уа == 1.5, Yk == 1.5, Y == 0.1. Верхнюю часть выводных данных представим в виде u================================================ uИзоrрамма. uuuuИсходныеuданные: uxO=1.5uuuuxk=ul.5uuuudx=uO.1 uyO=1.5uuuuyk=ul.5uuuudY=uO.1 u uuuuOTBeT: Подберем переменным имена: назовем Ха, xk, X, Уа, Yk, Y, У, у2, Х, jmax, i max , j и i соответственно ХО, Xk, Dx, УО, Yk, Dy, У, У2, Х, Jmax, Iтах, J и 1. Составим и выполним проrраммы. Результаты работы совпали с запланированными. Заметим, что алrоритм Изо сра.м.ма можно сделать несколько эффективнее по времени исполне ния. Для этоrо команду у2 +----- У Х У заменим командой у2 +----- 1  У х У, а условие (х 2 + у2  1)  условием (х2  у2). Замечание При кодировании кратных циклов необходимы средства языков проrраммирования, изложенные в zлаве 7. Упражнения На плоскости хОу отметьте штриховкой множество точек (х, у), координаты которых удовлетворяют следующим далее условиям. Пусть х == Xa(Xk)X, У == Ya(Yk)Y. Составьте проrрамму, KOTO рая штриховку заменит звездочками, а остальную часть плоскости закрасит точками (симв/строк массивы запрещены). В дополнение можно воспользоваться и средствами rрафическоrо пакета. Считай 
105 те все параметры в условиях задач заданными. Точки (х, У) лежат 3 : 61. между кривыми У == shx и У == chx, правее прямой х == 3/2 и левее прямой х == 3/2; 2 62. ниже кривой raycca У == eX , в верхней полуплоскости и в полосе Ixl  1/.;2; 63. между кривыми У == th х, У == cth х и в полосе 1/3  х  3; 64. выше параболы Нейля У == х 2 / 3 , выше кривой У == 21/x и не выше прямой У == у28; 65. между кривыми У == a COSX и У == х/ах, а > 1, О  х  a7r; 66. в той части плоскости, которая оrраничена эллипсом х 2 / а 2 + ty2/b 2 == 1 и находится выш е биссектрис Iro и IIro квадрантов; 67. ниже кривой У + у у2 + 1 == ах, а > 1, в полосе v'з"а  х  а и выше прямой У == v'з"а; аХ  а x 68. ниже кривой У == , а > 1 и в полосе .j2a  х  v'з"а; аХ + aX 69. ниже цепной линии У == а ch(x/a), а > о, выше прямой У == a/2 и между прямыми 'хl == а; 70. над параболой у2 == 2рх, правее оси ординат и не выше прямой у = а, а > о; 71. внутри криволинейноrо прямоуrольника, образованноrо rипербо .10Й х 2 /а 2  у2/Ь 2 == 1 и прямыми 'Уl == а; 72. вне квадрата 'хl + 'Уl == а, внутри квадрата 'хl + Iyl == ь, 1  а < Ь, не ниже биссектрис Iro и IIro квадрантов и ниже биссектрис IIIro и IVro квадрантов; 73. внутри "креста" Ilxl  IYII == 1, выше прямой У == 2 и не выше прямой У == 2; 74. внутри шестиуrольника 12у  11 + 12у + 11 + 41х! /v'з" == 4 и вне окружности радиуса 1/3 с центром 0(0, О); 75. внутри петли строфоиды (х + а )х2 + (х  а )у2 == о, а > о, правее этой кривой и левее прямой х == а/2; 3См. Бронштейн И. Н., Семендяев К. А. Справочник по математике для ин женеров и учащихся втузов.  М.: Наука, 1986.  544 с.; Выrодский М. Я. Справочник по высшей математике.  М.: Наука, 1972.  872 с. 
106 76. внутри петли Декартова листа х З + уЗ  3аху == о, а > о, между этой кривой и прямой х + у + а/2 == о; 77. в той части плоскости, которая оrраничена rипоциклоидой (астроидой) х 2 / З +у2/З == а 2 / З , а> О и находится в IoM и IIIeM KBaд рантах; 78. в части плоскости , оrрани ченной первой ветвью обыкновенной циклоиды acos((x+ vy (2ay))/a) == ay, а> о, не ниже оси абс цисс и правее оси ординат; 79. вне астроиды (х2+у2а2)З+27х2у2а2 == о, а > О и внутри окруж ности радиуса а + 1 с центром 0(0, о); 80. вне лемнискаты Бернулли (х 2 + у2)2 == а 2 (х 2  у2), а > О и внутри прямоуrольника Ixl  3а/2, Iyl  а; 81. ниже правой ветви трактрисы х == aln((a + у а 2  у2)/у)   y a2  у2, О < У  а и левее прямой х == V3а; 82. на трисектрисе у2(а+х) == хЗ(3ах), а > О толщиной 2<5; 'хl  2а, 'у'  а; 83. внутри улитки Паскаля (х 2 + у2  ах)2  [2(х 2 + у2) == о, О < а < l < 2а, исключая часть плоскости, оrраниченной биссек трисами Iro и IVro квадрантов; 84. внутри овала Кассини (х 2 + у2)2  2с 2 (х 2  у2) == а 4  с\ о < с < < а < J2c, исключая IIй и IVй квадранты; 85. внутри той части плоскости, которая оrраничена кардиоидой (х 2 + у2)(х 2 + у2  2ах)  а 2 у2 == о, а > О и находится в IoM и IIIeM квадрантах; 86. правее циссоиды Диоклеса х З + (х  а )у2 == о, а > О и левее пря мой х == а/ V3; 87. внутри конхоиды Никомеда (х  а)2(х 2 + у2)  [2х 2 == о, а > о, l == а и в полосе Iyl  [; 88. ниже верзьеры Марииrаэтаны Аньези (х 2 + а 2 )у  аЗ == о, а > О и выше биссектрис Iro и IIro квадрантов; 89. в левой петле лемнискаты Бернулли (х 2 + у2)2  2а 2 (х 2  у2) == о, а > О (но не принадлежащих IIму квадранту) и  в правой петле (но не принадлежащих IVMY квадранту); 
107 90. на "кресте" х 2 у2 == а 2 (х 2 + у2), а > О толщиной 28; Ixl  3а, Iyl  2а. Степенной ряд в практике проrраммирования встречаются задачи вычисления значений различных сумм, например, отрезков степенных РЯДОВ. С основными приемами решения таких задач познакомимся на сле дующем примере. Для значений х == xo(xk)h построим mаблu-цу з'Н,а 'Че'Н,ui1 фую\:'Цuu ошuбо-к; erf х == 2/yI1r f (1 )nх2n+l/( п! (2п + 1)); х < 3. n=О > Суммирование будем выполнять до тех пор, пока соблюдается усло вие lu n ( х)/ Sn( x)1 > е, rде и n ( х) == (1 )nх2n+l/( п! (2п+ 1))  общий член ряда; Sn ( х)  частичная сумма, отвечающая суммированию членов ряда до иn(х) включительно (Sn(X) == ио(х) + иl(Х) + . . . + иn(х )); е  наперед заданное малое число. Определим, при каком значении п первый раз выполнится неравенство lun(x)/Sn(x)1  е. Строка BЫ ходных данных должна. содержать номер х и значения х, n, erf х. Если будет выполняться условие х  3, ТО положим erf х == 1 и п == О. Пусть х == 0.1(1)0.1, а е == 105. Решение таково. Здесь сформулирована задача с двойным циклом: внешним  по количеству значений aprYMeHTa функции erf х (цикл по х с известным числом повторений) и внутренним  по перемен ной п (цикл по е с неизвестным числом повторений). С внешним ци клом все ясно: количество точек по переменной х, т. е. число строк в таблице, определим по формуле i max == [(Xk  xo)/h + 0.5] + 1. Теперь разберемся с внутренним, итеративным циклом. Построим математическую модель вычисления частичной суммы 5n(х)=х  х З /(1! х 3) + х 5 /(2! х 5) ... + (1)nx2n+l/(п! х (2п + 1)). При переходе от одноrо слаrаемоrо к друrому меняются номер, Be личина члена и частичная сумма, т. е. п, иn(х) И Sn(x)  перемен ные параметры BHYTpeHHero цикла. Для подсчета частичной суммы есть два пути. Первый из них предполаrает вычисление каждоrо члена ряда независимо. Тоrда, так как исходный ряд знакоперемен ный, для формирования нужноrо знака придется ввести переменную 
108 k ("кувыркающуюся единицу"), начальное значение которой равно единице, а последующие ее значения меняются по закону k  k. В формулу члена ряда еще входят степень х2n+l, пфакториал и He четное число 2п + 1. Вычисление каждоrо из этих компонентов в отдельности является циклическим алrоритмом; значит, любой из них требует подrотовки цикла; в нем появится несколько незави симых друr от друrа, но схожих команд; при 'хl  2 степени х2n+l быстро растут и еще быстрее увеличиваются значения факториаль ной функции. Пойдем друrим путем. С целью создания ясноrо, надежноrо и эф фективноrо алrоритма выразим очередной член ряда иn(х) через предыдущий член иnl(X)' Для этоro найдем их отношение: иn(х) иn 1 ( Х ) (1)n1( 1)x2n1x2 (п  1)1 (2п  1) (п  1)!п(2п + 1) (1)n1x2n1 откуда получим иn(х) == x2(2п  1)иn1(x)/(п(2п + 1)), иа(Х) == Х, Sn(x) == Snl(X) + иn(х), Sa(x) == х, п Е N. Так как частичная сумма Sn(x) может быть нулевой, условие OKOH чания суммирования запишем "в линию" lиn(х)1  с ISn(x)l, что только усилит надежность алrоритма. Приступим к построению алroритма. Спланируем следующий поря док действий. Сначала объявим переменные, потом зададим apry менты (введем исходные данные, выведем заrоловок задачи, скопи руем исходные данные и выведем заroловок таблицы) и подrото вимся к внешнему циклу (определим число строк i max и KOHCTaH ту С, равную 2/.Ji). Внешний цикл  это арифметический цикл по переменной i == 1(i max )1 (или, что то же самое, по переменной х). В начале циклической части найдем значение х == ха + (i  1)h и проанализируем условие х < 3. Если оно соблюдается, то займемся вычислением суммы ряда. Для этоro подrотовим внутренний, ите ративный цикл  вычислим x2 И присвоим иа(Х), Sa(x) начальные значения, равные х. Циклом по € будет управлять переменная п, значение которой изменяется от 1 с шаrом, равным 1, до HeKOTOpo ro выбранноrо пользователем числа птах (paBHoro, например, 100). 
109 Сразу проверим условие окончания цикла. Если значение отноше ния IUn(x)1 > с i5n(X)1 истинно, то подсчитаем величины 2n, иn(х) и 5n(х); в противном случае (отношение ложно) найдем приближен ное значение функции erf х, умножив частичную сумму 5n(х) на коэффициент с == 2/Vi, и покинем цикл, перейдя по .мет'/Се к выводу строки таблицы. Заметим, что выход из итеративноrо цикла будет произведен при истинном неравенстве lun(x)1  с 15n(x)l, так как для ero выполнения нужно сделать Bcero несколько десятков итератив ных шаrов (при малых по модулю значениях х ряд для erf х быстро сходится). Тем не менее предусмотрим обработку такой ситуации: если выход из цикла будет реализован при выполнении неравенства п > Птах (это возможно, в частности, если взять слишком малые значения с и/или Птах), ТО выведем сообщение об ошибке и прервем построение таблицы. Коrда соблюдается условие х  3, присвоим У == erf х единицу, а n  нуль и выведем строку таблицы. Если не вся таблица еще получе на, то продолжим ее построение; в противном случае (тело таблицы [отово) нарисуем основание таблицы и прекратим все действия. Запишем проект алrоритма псевдокодом (в нем члены ряда ио(х), иnl(X)' иn(х) кратко названы и, а частичным суммам 5о(х), 5n1(X), 5n(х) дано имя 5): алrоритм Erf конст вещ 7r r--- 3.141593 вещ Хо, Xk, h, С, с, х, t, и, 5, у цел Птах, i max , i, n, 2n начало ввести Хо, Xk, h, с, Птах вывести заrоловок задачи, Хо, Xk, h, с, Птах, заrоловок таблицы i max r--- [(Xk  xo)/h + 0.5] + 1 с r--- 2/Vi для i от 1 До i max шаr 1 выполнять Х r---xo+(il)h если Х < 3 то t r--- x2 U r--- Х 5 r--- Х для n от 1 до Птах шаr 1 выполнять 
110 еСJIИ lul > € 151 то 2n +----- n + n и +----- t(2n  1)и/(n(2n + 1)) 5 +----- 5+и иначе у+----- с5 иди к .метх:а конецеСJIИ конеЦЦИКJI вывести сообщение об ошибке, с5 стоп иначе у +----- 1 n +----- О конецеСJIИ .метх:а вывести элементы таблицы, i, х, n, у конеЦЦИКJI вывести основание выходных данных конец /*lu/51€*/ /* к выводу строки таблицы */ /* lu/51 > € */ /* по n, € */ /* n > Птах */ /* Х  3 */ /* Х < 3 */ /* по i, х */ /* алr Erf */ Спланируем тестирование алrоритма и проrраммы. В нормальных условиях проверку выполним при х == 1: должно получиться значе ние erf 1, равное 0.842. Для оценки компьютерноrо времени можно взять последовательно € == 101, 102, 10З, 104 и, наконец, 105. В экстремальных условиях rраничные испытания проведем для х==о, х == 3, х == 3  Б и х == 3 + Б, rде Б  допуск (малое число, например, 10З). При х == 4 значение функции равно еДинице, а n  нулю. Исходными данными в этой задаче являются числа Ха == 0.1, Xk == 1, h == 0.1, € == 105 И Птах == 100. Пусть выходные данные имеют вид u============================= uСтепеннойuрядuеrfuх. uuuuИсходныеuданные: uxO=O.10uuuuxk=1.00uuuuh=O.10 ueps=1.0e05uuuunmax=u100 u uuuuOTBeT: uuuuuuuuuТаблицаuеrfuх 
111 u+++++ uluuiuuluuuxuuuluunuuluuerfuul u+++++ uluu10uluu1.00uluцццuluо.842ul u+++++ u============================= Заметим, что таблицу надо начинать конструировать с какойнибудь строки (например, с последней) и лишь потом рисовать "шапку" и основание таблицы. fоризонтальные линии изображаем символами минуса, а вертикальные  символами 1. В точках пересечения и сопряжения линий, а также в уrлах таблицы разместим символы +. Приступим К кодированию. Выберем для переменных Хо, Xk, h, е, с, х, t, и, S, у, nтах, i max , i, n и 2n соответственно имена ха, Xk, Н, Eps, С, Х, Т, и, S, У, Nтax, lтах, 1, N и N2. Все три проrрам мы были выполнены на компьютере. Результаты проrона совпали с ожидаемыми. Заметим, вопервых, что время выполнения алrоритма Erf можно уменьшить, если объявить вещ v, убрать объявление целочисленной переменной 2n, в подrотовке цикла по n добавить команду v +----- Х, а в теле Toro же цикла команды 2n +----- n + n u +----- t(2n  1 )и/( n(2n + 1)) заменить командами v +----- tv/n u +----- v/(2n + 1). И, BOBTOpЫX, ряд для erf Х имеет радиус сходимости r == 00. Однако при Х > 1 ряд сходится медленно. Стеnен:пые ряДы  одно из средств вычисления значений функций. Если при этом используется компьютер, то далеко не безразлично, в каком виде записана формула, так как в практике вычислений Ma тематически эквивалентные выражения нередко неравноценны (по времени подсчета и точности результата). Поясним сказанное. Pac смотрим задачу нахождения наиболее удобных выражений для эле ментарных функций анализа. Возьмем простую, например, эксо ненциальную функцию е Х . Ее можно представить ряДом Tei1.1/,opa  Ма'К:.I/,орена: е Х == 1 + Х + Х 2 /2! + . . . + Х n / n! + . . . , I Х I < 00. Вычисления удобно вести, пользуясь следующими рекуррентными соотношениями: 
112 00 е Х == L Uk, Uk == XUklj k, 5k == 5k1 + Uk, k=O rде иО == 1, 50 == 1, k Е N. Коrда очередной вычисленный член ряда станет по модулю меньше допустимой поrрешности е (т. е. если выполнится неравенство /и n +l1 < е), то получим число 5n == == 2:k=O Xk jk!  приближенное значение е Х . При 'хl  1 степенной ряд СХОДИТСЯ быстро; в противном случае (Ixl> 1) ряд мало приrоден для вычислений, поэтому поступим так: представим х в виде суммы х == [х] + {х}. Тоrда получим е Х == е[Х]е{Х}. Первый множитель найдем последовательным умножением е[Х] == ,е х е х ... х  , если [х] > О, (если [х] == О, то е[Х] == 1)  [х] раз e[X]==lj(exex...xe), если [х]<О,    [x] раз а второй  с помощью степенноrо разложения е{Х} == f {x}kjk!. k=O Так как дробная часть удовлетворяет неравенству О  {х} < 1, ТО этот ряд СХОДИТСЯ быстро. Для нахождения значения е Х , Ixl < 1 лучше Bcero использовать no лuно.мuалъное nрuблuженuе е Х :::;::j 2:r=o ak xk (е == 2 х 107), rде аО == 0.9999998, аl == 1, а2 == 0.5000063, аз == 0.1666674, а4 == 0.041635, аs == 0.0083298, а6 == 0.0014393, а7 == 0.000204 или ра'Цuоналъное nрuблuженuе е Х :::;::j (Р(х) + Q(x))j(P(x)  Q(x)) (е == 109), rде Р(х) == 2:=0 а2k(хjз)2k, Q(x) == xj3 х 2:=0 b 2k (Xjз)2k, аО == 0.864864, а2 == 0.898128, а4 == 0.10206, а6 = 0.0020412, Ь О = 1.297296, Ь 2 == 0.37422, Ь 4 == 0.0183708, Ь 6 = 0.00010935. Простота обработки полиномов делает частым их использование. 
113 Решить задачу вычисления значений ФУНКЦИИ у == е Х можно еще и так. Возьмем первые четыре члена ряда. Имеем у  ((х/6 + 1/2)х + l)х + 1. При Ixl ( 0.01 ошибка вычисления меньше 1.7 х 1O7. Воспользу емся известным математическим приемом "сжатие  раст.яже пие". Сжатие состоит в последовательном уменьшении aprYMeHTa х вдвое. Поскольку е Х / 2 == Р, ТО в нашем случае сжатие COOTBeTCTBY ет MHoroKpaTHoMY извлечению квадратноrо корня. После использо вания приближенной формулы мы должны за то же самое число шаrов удвоения веруться к исходному значению переменной. Таким образом, схема вычисления е Х выrлядит так, как представлена на рис. 3.8. сжатие раст.яже1tие ха (> о) Уа == е ХО nKpaTHoe 1 извлечение корни nKpaTHoe r возведение в квадрат х n (( 0.01) ............... Уn == ((х n /6 + О.5)х n + 1)х n + 1 Рис. 3.8. Схема вычисления е Х Если ха < о, то вычисления проделаем с IXal, а затем учтем, что eX == 1/ е Х . При вычислении значений триrонометрических функций с помощью формул nриведе1tи.я: sin х == sin(x  27!"n) для 27!"n ( Ixl ( 27!"(n + 1), sin х ==  sin(x  7!") ДЛЯ 7!" ( IxJ ( 27!", sinx == sin(7!"  х) для 7!"/2 (Ixl (7!", sin х == cos(7!" /2  х) ДЛЯ 7!" /4 ( Ixl ( 7!" /2, sin х ==  sin( x) для х < О aprYMeHT х следует заключить в отрезке [о; 7!" /2], а затем, если х Е [7!" /4; 7!" /2], положить sin х == cos Z, cos х == sin z, rде z == 7!" /2  х. Замечание о средствах языков проrраммирования, необходимых для кодиро вания итеративных циклов, см. славу 7. 
114 Упражнения Для значений Х == xo(xk)h получите таблицу функции У == J(x). Таб лица должна содержать не более пяти столбцов с заroловками: i Xi ni Yi D.i Здесь i номер aprYMeHTa Xi (i == 1, 2, ..., i max ); Xi == ХО + (i 1 ) h aprYMeHT; ni номер итеративноro шаrа, при котором пер вый раз выполнится неравенство IUn(Xi)1 € ISn(Xi)l, rде Un(Xi) n й член ряда, Sn(Xi) частичная сумма, включая Un(Xi); D.i == == IYi YiKoHTPI поrрешность вычислений. Если Xi rt D(J), сообщи те об ошибке и прекратите построение таблицы. Значение D.i BЫBe дите в формате D.i : 8 в Паскале, %7.0Ie в Си и 1ре7.0 в Фортране. Пусть € == 1O 7 И € == 1O 15. Значения ХО, Xk, h заданы. 00 (x 1)2n+l 91. У == lnx ==, 2n o (2n + l)(х + 1)2n+l' 0< Х 1; 1 00 (х 1)n 1 92. У == 19 Х == l О 2: , Х 2 j n 1 n=l nх n 00 х n 9З.у==lп(х+2)==lп2+2:( 1)n 1 , 2<x 2; n=l n Х 2 n 94. У ==, .!. == f ( 1)n+l (х 3)n 1 , 3 < Х 4; Х n=l 3 n 1 00 xnlnnx 95. У == == 1 + 2: ( 1)n , ' о < Х 1; Х n=l п. 7r 00 ( 1)n+l 1 96. У == arctg Х == :f: 2 + 2: (2 1) 2n+l ' Iхl > 1; n=О n + Х 97. У == е Х == e 2 ( 1 + f (х +2)n ) , 'Х/ 1; n=l п! 1 1х2 1х2х5 98. У == 1 :f: Х == 1 :f: X x2 :1: х3 3 3х6 3х6х9 1х2х5х8хll 5 :f: Х ..., Ixl lj 3х6х9х12х15 1х2х5х8 4 Х :1: 3х6х9х12
115 х 00 2nl 99. у == !х == х + L (1)nl ( )' Х n ' Ixl:::; 1; е n=2 п  1 . х 00 x2nl 100. у == sin'2 == n/1)n+1 22n1(2n  1)! ' о:::; х:::; 2; 00 22nl 101. у == sin 2 х == L (1)nl x2n Ixl :::; 1; n=l (2п)!' 7r 00 ( 7r ) 2n2 (х  2)2n2 102. у == sin x == L (1 )n+1  , 2 < х :::; 3; 4 n=l 4 (2п  2)! 00 (x7r/2)2n1 103. у == cosx == n/1)n (2п  1)! ' Ixl:::; 1; 1 00 (2х )2n 104. у == cos 2 Х == 1 +  2  (1)n (2 )" Ixl:::; 1; nl п . . 1 00 4nl ( 7r ) 2n1 105. у == cos 2 Х == '2 + n/1)n (2п  1)! х "4 ' Ixl:::; 1; 00 2 2n 106. у == cos2x == 1 + n/1)n (2п)! х 2n , Ixl:::; 1; 00 24nЗ 107. у == sin 2 2x == 4 L (1)n+lx2n, Ix!:::; 1; n=l (2п)! 00 4nl 108. у == cosx х chx == L(l)n+l x4(n1), Ixl:::; 1; n=l (4п  4)! 00 2п 109. у == xcosx  sinx == L (1)n х2n+1, /xl:::; 1; n=l (2п + 1)! 00 x2nl I 00 x2n2 110. у == th х == nl (2п  1 )! nl (2п  2)! ' Ixl:::; 1; 00 х 2n 1 00 х2n+l 111.y==ctgx==(1)n (2 ) , (1)n (2 1)" Ixl:::;l, x=tfO; nO п. no п + . 00 1x3x5x...x(2п1)xx2n+l 112. y==ln(x+ vx2+1 )==X+L(1)n 2 4 6 2 (2 1) ,lxl<l; n=l Х Х х...х пх п+ 
116 1 00 (2п  1)!! 113. у == vт+x == 1 + Е (1)n ( )" х n , 1 < х::::;; 1; 1 + х n=1 2п .. х 2 00 ( 2п  1 ) " 114.Y== V 1+x2==1++E(1)n .. х2n+2, I x l::::;;l; 2 n=1 (2п )!! (2п + 2) 115 1 1 f (2п  1)!! 2n Ixl < 1; . у == V1  х 2 == + n=1 (2п )!! х , (  ) 00 1x3x5x...x(2п1) 1 116. y==ln x+vx21 ==ln(2x)E 6 2 2n ' х>l; n=1 2 х 4 х Х... Х п х 2п х . 2 00 (2п)!! х2n+2 11 7. у == аrсsш х == 2 Е ( ) " ' n=О 2п + 1 .. 2п + 2 J2 о  х  ; 2 ( ) 2 1 00 (п  1)! 118. у == arcsin 2 х ==  Е (2х )2n, 2 n=1 (2п)!   7r 00 (2п  1)!! 2n+l 119.yarccosxx Е ( ) " ( ) Х, 2 n=1 2п.. 2п + 1 х 00 (2п)!! ( х2 ) n 120. у == arctgx == 2 Е (2 1) " 1 2 ' 1 + х n=О п + .. + х J2 о  х  ; 2 'хl < 1; О  х  1. rрафик функции Выполнена работа и ее результаты представлены колонками чисел. Можно придать им наrлядный вид  построить rрафик или rи cTorpaMMY. Напишем проrрамму, которая "руками компьютера" для значений х == xO(Xk)h рисует rрафик функции у == ЛХ). Решение заключается в следующем. Пусть ЛХ) == 5(х  2)/х 2 . Бу дем строить наиболее характерную часть rрафика, поэтому найдем область определения функции D(J), ее нули, экстремумы и область значений W(J) (или E j ). Так как х =1 о, то D(J) == (oo; О) u (о; (0). Функция ЛХ) == 5(х  2)/х 2  общеrо вида, непериодическая. Ее нуль: х == 2. fрафик функции (рис. 3.9) ось ординат не пересекает. 
117 у 1 2 О 2 \ 4 6 x2 y=5 х 2 Рис. 3.9. rрафик функции Промежутки знакопостоянства функции: Лх) > О Vx Е (2; 00) и Лх) < О Vx Е (oo; о) u (о; 2). Критические точки: х == О и х == 4. Функция возрастает при х Е (о; 4] и убывает при х Е (oo; о) u [4; 00). Значение х == 4  точка максимума, причем тахЛх) == Л4) == 5/8. D Наибольшее значение функции sup Лх) == Л4) == 5/8. Тоrда W(f) == D == (oo; 5/8]. Значение х == 6  точка переrиба. Прямая у == О  rоризонтальная асимптота, а прямая х == О  вертикальная. Так как напромежутке [1.75;6.75] функция Лх) == 5(x2)/x2 имеет MHoro характерных точек (нуль, зкстремум и точку переrиба), то выберем Ха == 1.75, Xk == 6.75 и h == 0.25. Координаты точек (абсциссы и ординаты) будем хранить в массивах Х и У соответственно. По формуле n == [(xkxa)/h+O.5]+1 подсчита ем количество точек. При Ха == 1.75, Xk == 6.75 и h == 0.25 значение n (длина массивов Х и У) равно 21. Ось абсцисс направим вертикально (на принтере  вдоль бумажной ленты). Масштаб по зтой оси сле- дует выбрать так, чтобы шаr h == Xj  Xil изменения aprYMeHTa был кратен расстоянию между соседними строками. Ось ординат распо- ложим rоризонтально. При выборе масштаба по оси Оу надо знать амплитуду колебаний функции на заданном отрезке [Ха; Xk], для че- ro придется искать (с точностью до шаrа h) наибольшее (sup Лх)) и наименьшее (inf f( х)) значения f( х). Цену t одной позиции по оси Оу определим по формуле t == (supf(x)  inff(x))/(l  5), rдe 1  число позиций строки, предназначенных для значений ординат (l не может превосходить числа позиций в строке зкрана или принтера; на практике диапазон изменения 1 таков: [40; 256]). В позициях, соответствующих координатам Xi и Yi, будем выводить 
118 строку из пробелов u, длина которой k== [(YiinfJ(x))/t+O.5] "рав- на" значению Yi, и какойнибудь знак (например, точку или звездоч ку). Можно дополнительно предусмотреть вывод таблицы значений функции, а на rрафике каждую координату снабжать номером стро- ки таблицы или, друrое решение, на оси координат нанести масштаб- ные шкалы. Прежде чем переходить к разработке алrоритма, познакомимся с новой конструкцией алrоритмическоrо языка  операторной функ- цией. В исполняемой части алrоритма встретится команда присваи- вания У +------- 5( х  2) f х 2 . Обобщим ее, записав в виде . вещ J(вещ х) +------- 5(х  2)fx 2 И переместив в декларативную часть. Теперь эта синтаксическая единица будет называться onepamop1toi1 фУ1t'К:'Цuеi1 алrоритма с име- нем f, фор-малъ1tы-м пара-метро-м (короче, пара-метро-м) х и те- ло-м 5(х  2)fx 2 . Чтобы определить значение ординаты, в исполня- емой части следует сделать вызов ФУ1t'К:'ЦUU (написать обраще1tuе 'к: фУ1t'К:'Цuu). Найденное значение можно присвоить какой-нибудь пе- ременной, например, так: У +------- J(x). Здесь в команде присваивания х является фа'К:тu'Чес'К:u-м пара-метро-м (или просто, арсу-мепто-м). Слово" фактический" подчеркивает, что функции передается теку- щее, фактическое значение х. Обобщим введенные понятия. Операторная функция  это простей- ший вспомоrательный, подчиненный алrоритм. Ero место  вну- три (внешнеrо) алrоритма, в декларативной части. Обб,я,вле1tuе такой B1tympe1t1tei1 фУ1t'К:'ЦUU имеет вид тип f( munl Vl, тип2 V2, . . ., тип n v n ) +------- а т. е. состоит из имени функции f (лучше мнемоническоrо), списка формальных параметров Vl, V2, ..., V N И тела функции (выражения а). Тип и muni (i == 1, 2, ..., п) устанавливают соответственно тип значения функции и типы параметров: компл, вещ, двточн, цел, лоr, симв, строк и т. д. Для последовательно идущих параметров одинаковоrо типа можно только один раз указать общий тип. Пара- метры  это пустые, фиктивные переменные. Они служат дЛЯ TOr:O, чтобы показать те действия, которые надо произвести над aprYMeH- тами с целью нахождения значения функции. Слово" формальный" подчеркивает, что функция решает задачу в общем виде. Пара- 
119 метры локализуются в выражении а и не имеют никакоrо отношения к точно таким же переменным исполняемой части. В теле функции, кроме параметров, можно использовать константы, вызовы друrих функций и любые переменные, известные в точке вызова данной функции. Такие переменные называются 2лобаЛЪ1tЫМU. К примеру, если надо подсчитать значение 1СвадратпО20 трехчле1tа в точке х, то объявление операторной функции может быть следующим: вещ Р2(вещ х) +----- (ах + Ь)х + с Здесь Р2  имя функции; х  параметр; коэффициенты трехчлена а, Ь, с  r лобальные переменные (их имена в процессе выполнения алrоритма постоянны, а значения MorYT меняться). Чтобы активизировать объявление функции, в исполняемой части следует сделать въtзов фУ1t1С'ЦUU !(иl, и2, ..., и n ) rде aprYMeHTbI иl, и2, ..., и n  выражения (nервU'Ч1tЪtе  числа без знака (например, Р2(0.1234567)), переменные (P2(t)), элементы массива (P 2 (Xi)), вызовы друrих функций (P2(sina), P 2 (F(Xi))), BЫ ражения в скобках (P2((0.1))); составпые  формулы (P2(0.1), Р2 (и + v) ) ) . Что дает новая конструкция? Если в алrоритме в разных ero фраr ментах исполняемой части производятся вычисления по rромозд кой формуле, то пишите объявление соответствующей операторной функции. Она (так же, как, например, команда "повторение") сэко номит вам время, бумаrу и пасту (и, кроме Toro, место в памя ти компьютера). Правда, рассмотренный ранее пример тривиален, но решением ero сделан первый шаr в реализации принципа рабо ты "разделяй и властвуй", используемоrо при разработке больших проектов. Друrие подчиненные алrоритмы будут рассмотрены далее (см. 2лаву 4). Итак, разработаем алrоритм построения rрафика. Дадим алrорит му имя rрафu1С. в начале ero объявим скалярные объекты (KOHCTaH ту lim +----- 100 и простые переменные), составные объекты (массивы X[lim], Y[/im]) и операторную функцию ЛХ). Затем определим apry менты алrоритма (Ха, Xk, h, 1), выведем заrоловок задачи, выполним эхопроверку данных и выведем заrоловок таблицы. Потом займемся формированием таблицы, для чеrо сначала подсчитаем число точек 
120 п и присвоим переменным sup и inf начальные (фиктивные) зна чения. Для построения таблицы откроем цикл по цел переменной i == l(п)l. Внутри ero найдем координаты Xi, Yi, выведем строки таблицы (значения i, Xi, Yi) и определим текущие наибольшее и наи меньшее значения функции. После закрытия этоrо вспомоrательноrо цикла найдем цену деления, выведем ее вместе с супремумом sup, инфимумом inf и заrоловком rрафика. Далее рисуем rрафик: снова орrанизуем цикл по переменной i == 1 (n) 1, выведем ее значение (i  номер iй строки таблицы, номер iй координаты), k пробелов и звез дочку. И, наконец, после построения rрафика напечатаем основание выходных данных. Используя алrоритмическую нотацию, приведем текст алrоритма построения rрафика: алrоритм rрафu1С конст цел lim t------- 100 цел 1, п, i, k, j вещ Ха, Xk, h, sup, inf, и, v, t вещ массив X[lim], Y[lim] вещ f(вещ х) t------- 5(х  2)/х2 начало ввести Ха, Xk, h, 1 вывести заrоловок задачи, Ха, Xk, h, 1, заrоловок таблицы п t------- [(Xk  xa)/h + 0.5] + 1 sup t------- 1038 inf t------- 1038 для i от 1 до п шаr 1 выполнять u t-------xa+(il)h vf(u) Xi t------- U Yi t------- V вывести z, и, v если sup < v то sup  v конецесли если inf > v то inf  v конецесли конеццикл t  (supinJ)/(l  5) вывести sup, inf, t, заrоловок rрафика для i от 1 до п шаr 1 выполнять k  [(YiinJ)/t + 0.5] вывести i, 'u' при j == l(k)l, '*' конеццикл /* вывода таблицы */ /* вывода rрафика */ 
121 вывести основание выходных данных конец /* ал rрафu1С */ Здесь в теле первоrо цикла индексированные переменные Xj и Yj используются более одноrо раза, поэтому с целью экономии KOM пьютерноrо времени они заменены простыми переменными COOTBeT ственно u и v. Теперь спланируем тестирование и внешнее представление данных. Проверку алrориТма (и проrраммы) выполним при Х == 2,4, 6. Долж ны получиться числа 1(2)==0,1(4)==0.625 и 1(6)==0.(5). Исходные данные в этой задаче таковы: Ха == 1.75, Xk == 6.75, h == 0.25, 1 == 80. Выводной набор данных будет иметь следующий вид: u============================================== uТаблицаuиurраФИКuфункцииuу=5Сх2)/х**2. uuuuИсходныеuданные: uxO=u1.750e+OOuuuuxk=u6.750e+OOuuuuh=u2.500e01 uЧислоuпозицийuвuстрокеuтерминалaul=u80 u uuuuOTBeT: uuuuТаблицаuу=5Сх2)/х**2 uuiuuuuuxuuuuuuuuuufCx) uu 2 uuuu 2 . OOuuuuuuuu. 000 uusup=uu.625uuuuuuuinf=u.408 uuЦенаuпозицииuпоuосиuОуuестьuu1.З78е02 uuuuuuuuuuuuuuuurрафикuу=5Сх2)/х**2 uu 2 uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu* u============================================== Назовем константу lim, переменные 1, n, i, k, j, Ха, Xk, h, sup, inf, и, v, t, массивы Х, У и функцию f соответственно именами Lim, L, N, 1, К, J, ХО, Xk, Н, Вир, Iпf, и, V, т, Х, у и Р. Проrраммы алrоритма rрафu1С были успешно выполнены. HeДOCTa ток выводимоrо rрафика  В несоответствии масштабов по осям KO ординат (например, по оси ОХ он определяется расстоянием между строками). В заключение опишем алrоритм ТистО2ра,М,,М,а. rистоrрамма  один из видов rрафическоrо представления экспериментальных данных. 
122 Строится она так. Диапазон изменения исследуемой величины дe лится на несколько равных отрезков .6.1, .6.2, ..., .6. k . Затем под считывается количество наблюдений mi, приходящихся на каждый iй интервал (i == 1,2, ..., k), и определяется относительная частота h i == тi/n попадания в интервал, rде n  общее количество наблюде ний. Над .6. i рисуют прямоуrольник высотой h i (i == 1, 2, .. ., k). По лучившийся ступенчатый rрафик и называется 2ucт02paMMoi1 вЪt бор-,..u. Замечание При построении rрафика применялись средства языков проrрам мирования, приведенные в 2лавах 7 u 8. Упражнения Найдите область определения функции D(J), ее нули, экстремумы и множество значений W(J). "Руками компьютера" постройте rpa фик функции. Нарисуйте и разметьте оси координат. В дополнение можно воспользоваться и средствами rрафическоrо пакета (см. 2ла ву 1 О ) . 121. у == х 2 + Ixl; 122. у==(х 2  1)/(х 2 + 1); 123. у==lхЗ+хJ; 124. у == х з  зх 2 + 2; 125. у==х З  х 2  Х + 1; 126. у == х 4  2х2 + 2; 127. у == x4 + 4х 2 ; 128. у== 1/(1 + Ixl); 129. у == х з  3х; 130. у== (х 2 + х + 1)/(х 2  х + 1); 131. у == 1/(1 + х 2 ); 132. y==VX/(VX + 1); 133. у== ух 2 + 1  у х 2  1; 134. у == у х 2 + х + 1  у х 2  Х + 1 j 135. у == 2х2ЗХ+2; 136. y==2xlxl; 137. у == 21x2; 138. у == 2COS X j 139. у==х/2Х; 140. у==1пlпх; 141. у==1п(х  у х 2  1); 142. y==4(sin 4 (x/2) + cos 4 (x/2)); 143. y==sinx + cosx; 144. у== IsinxJ + sin Ixl; 
123 145. y==2sinx х Icosxl; 146. y==sinx + Isinxl; 147. у == 1 j (З + 2 cos х); 148. у==(1 + соsх)j(З  sinx); 149. у==х х sinx; 150. у == sin х 2 . 
124 r лава 4 Подчиненные алrоритмы Всем нам коrдато пришлось столкнуться с трудной проблемой и задаться вопросом: с чеrо начать? Один из обычных подходов, име нуемый .методо.м "сверху вниз", "от обще20 'к: 'ч,астно.му', состоит в сведении сформулированной задачи к последовательности более простых подзадач, леrче поддающихся обработке в отдельности, чем целиком исходная проблема, Коrда разбиение выполнено, для реше ния каждой подзадачи надо разработать соответствующий вспомоrа тельный алrоритм. Может статься, что такой алrоритм уже создан KeMTO раньше (вспомните свойство массовости алrоритмов). Вместе взятые вспомоrательные алroритмы дадут решение сформулирован ной задачи. Функциональная схема Разбиение задачи на подзадачи, т. е. выделение лоrических слоев,  дело неПростое. Ero надо закончить, как только любой из вспо моrательных алrоритмов будет выполнять только одну функцию. Эта функция должна быть выражена кратким предложением, BpO де: "Отсортировать массив по неубыванию элементов", "Построить дважды четный маrический квадрат", "Декодировать сообщение, за шифрованное кодом Морзе" и т. д. Правило "один алrоритм  одна 
125 функция"  ключ к разработке хорошеrо проекта, так как проще понять большую задачу по частям, создать общий алrоритм, верифи цировать ero, составить по нему проrрамму, "оживить", отладить и тестировать ее. Разделение работы на лоrические части  это обыч ный способ управления сложной ситуацией; Размер любоrо вспомоrательноrо алrоритма должен быть оrрани чен. В записи псевдокодом он не может превосходить, наверное, по лусотни команд. Если это не так, то скорее Bcero данный алrоритм можно еще расслоить, выделить из Hero какиенибудь подфункции. Разбиение позволяет отделить и факторизовать переменные, осла бить влияние возможных ошибок вследствие их изоляции в rрани цах каждоrо алrоритма, уменьшить число путей и создать блаrопри ятные возможности для модификации алrоритма. Вспомоrательный алrоритм  это способ сокращения, лаконичной записи Bcero проек та решения задачи (сравните с припевом в песне, который пишется полностью только один раз). Вместе взятые (выделенные) алrоритмы образуют систему, управле ние которой должен взять на себя алrоритмдиспетчер. Ero назы вают 2ла6'/tъtМ (или 20ло6'/tыl),, а все остальные  nод'Чu'/tе'/t'/tъtМu. Функции rоловноrо алrоритма предельно просты: задать исходные данные, активизировать по мере необходимости друrие алrоритмы и использовать результаты их работы, например, передать подчинен ным алrоритмам текущие, промежуточные результаты или вывести ответы задачи на экран, принтер или в файл. После Toro как выделены лоrические фраrменты и очерчены функ ции алrоритмов, следует построить схему иерархии (подчинения), отображающую уровни и взаимосвязь, взаимодействие алrоритмов. Эта схема в отличие от операционной схемы (т. е. блоксхемы) не показывает лоrику принятия решений, а иллюстрирует лишь под чиненность алrоритмов. Она концентрирует внимание на выявлении Toro, что надо сделать (а операционная схема  как это сделать). Поэтому схему иерархии называют еще фу'/t'Х:ЦUО'/tаЛЪ'/tо11 схемо11. При построении этой схемы нужно начинать с вершины и идти ВНиз. В вершине иерархии, на первом ее уровне должен находиться rолов ной алrоритм, упраВ{IЯЮЩИЙ работой остальных. А таких алrорит мов может быть несколько тысяч (например, американский Проект управления посадкой на Луну состоял примерно из 400 алrоритмов 
126 модулей, а операционная система 05 IBM 370 содержит более 3000). Посредством имени, называемоrо именем аЛ20рuтМа, подчиненный алrоритм может активизироваться rоловным, либо какимнибудь из подчиненных алrоритмов. Алrоритм, обращающийся к друrому, Ha зывается вызывающuм, а алrоритм, активизированный какимлибо друrим,  вызываемым. Любой вызываемый алrоритм может обра титься (если это надо по сценарию) к алrоритму, находящемуся на более низком уровне иерархии. Подчиненный алrоритм должен иметь один вход и один выход, так как чем больше алrоритм замкнут, независим (чем больше "упрятана информация"), тем леrче сделать всю работу. Алrоритм в процессе cBoero исполнения преобразует исходные величины в pe зультирующие данные. Он должен быть подобен математической функции, что, в частности, означает: для алrоритма надо задать цель и определить множество допустимых входных значений (это формальные параметрызначения), множество возможных BЫXOД ных величин (параметрырезультаты), возможные собственные (ло кальные, внутренние) объекты и возможные побочные (волновые) эффекты, причем к побочным эффе1Стам относятся выход параме тров за область допустимых значений, изменение значений параме тров, в частности, получение результатов и/или вывод данных. Если эти пять моментов соответствующим образом отражены в каждом алrоритме, то тем самым сделан важный шаr в разработке хорошеrо проекта. Итак, nодчuненный аЛ20рuтм есть элемент функциональ ной схемы, целиком реализующий одну самостоятельную подзадачу. Параметры алrоритма  это 11 окна" во внешний мир. Через них алrоритм получает исходные данные и отдает свои результаты (алrоритм уместно сравнить с цехом или фабрикой: совокупность параметров  это проходная; через нее в одном направлении (внутрь) поступает сырье (параметрызначения) и, может быть, инструкции (имена алrоритмов), а в противоположном  продук ция (параметрырезультаты)). Рассмотрим nример разработ1СU ФУН1С'Цuоналъной схемы. Сформули руем такую задачу: найти центр тяжести С (хс, Ус) однородной плос кой криво й у == f( x), х Е [а; Ь] по фор мулам хс == J x J l + (у,)2 dx/l, ус == J y J l + (у,)2 dx/l, а а 
127 rде 1 == j ) 1 + (у,)2 dx. Значения интеrралов, входящих в выражения а для хс, Ус и 1, вычислим с заданной точностью с по квадратурной формуле Ральстона. Решение этой задачи таково. Строим функциональную схему. Пе редача управления между алrоритмами в ней будет выполняться по rоризонтальным и вертикальным линиям. Такое "вертикальное управление" должно совершаться по следующим правилам: О вызываемый алrоритм возвращает управление своему вызываю щему алrоритму; (J любой алrоритм может обратиться к друroму, расположенному в схеме иерархии ниже, но вызывающий алrоритм не должен aK тивизировать алrоритм cBoero или более BbIcoKoro уровня; О алrоритм низшеrо уровня не принимает решений за алrоритмы высшеrо уровня; основные решения принимаются на высшем уровне иерархии, и делает это, как правило, rоловной алrоритм; (J общие данные между алrоритмами, по возможности, передаются через списки формальных параметров, а не через общую память; это усиливает независимость алrоритмов друr от друrа, а значит, повышает их надежность, универсальность, модифицируемость и переносимость (транспортабельность, мобильность). Вернемся к сформулированной задаче. Прежде Bcero выделим ca мую общую функцию: I Вычислить центр тяжести I а затем  алrоритмы, необходимые для детализации этой функции: [оловной алrоритм Метод Ральстона На данном шаrе проектирования не нужно думать о том, как реали зует свою функцию каждый алrоритм: например, "Метод Ральстона" временно следует рассматривать как "черный ящик"  устройство, в котором внешнему наблюдателю доступны лишь входные и BЫ ходные величины, а внутреннее строение устройства и процессы, в 
128 нем протекающие, неизвестны. Цель этоrо алrоритма  найти зна Ь чение интеrрала 1 == f J( х ) dx с точностью €. Для этоro надо за а дать пределы интеrрирования а и Ь, поrрешность €, начальное число разбиений потрезка интеrрирования, указать имя инструкции для вычисления значений ординат (имя подынтеrральной функции J) и получить результат (значение интеrрала 1). На "Метод Ральстона" можно ссылаться, ничеrо не зная пока о ero "устройстве". Наконец, алrоритм "Метод Ральстона" будет управлять тремя под чиненными алrоритмами, вычисляющими значения подынтеrраль ных функций. Получаем окончательную функциональную схему, Ka ждый прямоуrольник в которой представляет отдельный алrоритм (рис. 4.1). rоловной алrоритм Метод Ральстона Вычислить x V 1 + (у,)2 Вычислить Y V 1 + (у,)2 Вычислить V 1 + (у,)2 Рис. 4.1. Схема решения задачи нахождения центра тяжести кривой Теперь спланируем порядок разработки и тестирования алrорит мов. Здесь возможны, по крайней мере, три подхода: оnерацuо1t1tыi1, uepapxu"iec'/\,ui1 и '/\,о.мбu1tuрова1t1tыi1. На этом шаrе особенно важно хорошее знание интерфейса (связей между алrоритмами). П ри опе рационном подходе алrоритмы разрабатываются в порядке их ис полнения, например: 1. ''rоловной алrоритм". 2. "Метод Ральст она". 3. "Вычислить V 1 + (у,)2 " . 4. "Вычислить x V1 + (у,)2 ". 5. "Вычислить Y V 1 + (у,)2 ". Таким образом, при такой методике раньше создаются алrоритмы, 
129 порождающие данные для последующих алrоритмов, поэтому мини мизируются трудности, связанные с зависимостью по данным. При иерархическом (поуровневом) подходе сначала проектируются все алrоритмы одноrо уровня, после чеrо создаются алrоритмы, pac положенные уровнем ниже и т. д. Такой подход не выявляет поряд ка разработки алrоритмов в пределах одноrо уровня. Этот порядок можно установить удобством тестирования проекта или можно при нять традиционный порядок слева направо, например: 1. 'Толовной алrоритм". 2. "Метод Ральстона". 3. "Вычислить X V 1 + (у,)2 ". 4. "Вычислить Y V1 + (у,) 2". 5. "Вычислить V 1 + (у,)2 ". Слепое следование иерархическому подходу может привести к TPYД ностям, вызванным зависимостью по данным. Операционный и иерархический подходы объединяются в комбини рованном. Заметим, что плохо спроектированные проrраммы нередки. Для Ha именования их даже введен специальный термин: "клудж" (от анrл. kludge)  система, представляющая собой набор плохо совместимых друr с друrом частей, образующих жалкое целое [12]. Вместе с порядком разработки можно спланировать и тестирование. Контролировать надо и проектные спецификации (сведения о том, как должна функционировать создаваемая система), и конкретные алrоритмы, и интерфейс. Спецификации следует проверять на пол ноту и точность. Для каждоrо алrоритма нужно ПОДrотовить тесты. Они должны быть максимально приближены к реальной обстановке. Здесь можно использовать и данные, полученные в результате спе циальных руч ных, "п рикидочных" расчетов: например, если взять у(х) == Х, то v 1 + (у,)2 == J2. Тоrда при х Е [1; 2] найдем, что 1 == J2 :::::: 1.414213562373095 и Хс == Ус == 3/2. Так как большинство алrоритмов получают данные от друrих ал rоритмов системы, порождают и возвращают обратно результаты, ТО проверке подлежат и связи между вспомоrательными алrоритма 
130 ми. Для каждоrо из них надо составить таблицу параметров и про контролировать параметры и aprYMeHTbI на соответствие структуры данных, типа, количества и порядка следования. Все это делается до начала кодирования (вспомните: "что посеешь, то и пожнешь" или "хорошее начало полдела откачало"). Алrоритмфункция и алrоритмпроцедура Подчиненный алrоритм  продукт декомпозиции общеrо алrорит ма решения задачи. Цель подчиненноrо алrоритма  получив параметрызначения и обработав данные, выдать результаты под задачи. Если алrоритм дает одно результирующее значение (оно ис пользуется в точке вызова в выражении), то такой алrоритм может быть а.ll20рuтмомфун","'Цuеi1 (короче, фун","'Цuеi1). Коrда же алrоритм выдаеТ MHoro значений (в частности, одно или пусто), такой алrо ритм должен быть a.ll20pитMOMnpo'Цeдypoи (кратко, nро'Цедурой). В языках проrраммирования подчиненные алrоритмы (функции и процедуры) называются nодnРО2раммами. Мы уже познакомились с оnераторной Фун","'Цuеi1  алrоритмом, описанным или, иначе rоворя, объявленным одним предложением. Средство это не такое сильное, но полезное. Например, для Haxo ждениЯ остатка от деления двух целых чисел можно предложить следующее объявление операторной функции Modulo: цел Моdulо(цел т, n) f----- m  [т/n] х n Теперь, чтобы найти сумму k остатков от деления 13 на i и j + 1  на 1, надо в исполняемой части алrоритма, содержащеrо указанное объ явление, написать команду присваивания, левая часть которой со- стоит из переменной k, а правая  из двух вызовов функции Modulo, соединенных знаком плюс: k f----- Modulo(13, i) + Modulo(j + 1, l) Напомним, что, если несколько формальных параметров имеют об щий тип, соответствующее ключевое слово можно указать один раз (т. е. вместо цел т, цел n рекомендуется писать короче цел т, n). Фун","'Цuя есть обобщение операторной функции, так как алrоритм- функция  это состоящий из нескольких предложений отдельный, 
131 независимый алrоритм, обращение к которому возможно из любоrо друrоrо алrоритма. Обо,я,вленuе алzорuт-ма в общем случае имеет вид: алrоритм [тиn} u-м,я, (( сnисо.,.. nара-метров)} ?нач сnисо.,.. зншченuо/ {Рез сnисо.,.. резулътатов} заzолово'/'i: алzорuт-ма {сnе'Цuфu'/'i:ШЦUU и-мен алzорuт-мов} ft.OHCT сnисо.,.. '/'i:OHCmaHm} [обо,я,вленuе внутренних данн'ых} f>бщиii сnисо.,.. общuх данн'ых} начало '/'i:oMa нды конец тело алzорuт-ма Оно состоит из двух частей: заzолов'/'i:а и тела. С заrоловка начина ется запись любоrо алrоритма. Первое предложение заrоловка co держит ключевое слово алrоритм (можно алr) и U-м,я, алrоритма, перед которым указывается тиn результата функции (компл, вещ и т. д.). Имя выбирается так, чтобы ясно было, решение какой задачи описывает данный алrоритм. За именем следует сnисо.,.. фор-маЛЪН'blХ nара-метров. В любом списке ero элементы перечисляются через за пятую. Эле-менто-м CnUC'/'i:a nара-метров может быть имя переменной Vj с указанием типа (т. е. тuщ Vi), имя массива с указанием типа и rраницами измерений, причем в роли rраниц допускаются как KOH станты, так и переменные (mUnj массив vj[zранu'ц'ыl uз-мереНU'lL]), имя процедуры /k (алr /k(( сnисо.,.. nара-метров)}) и/или имя функ ции // (алr тuщ //(( сnисо.,.. nара-метров)}) (i,j, k, 1 Е N; i =1 j, k =1 1). Все имена параметров должны быть смысловыми. Второе и третье предложения заrоловка образуют COBO'/'i:YnHocmb cne ЦUфU'/'i:а'Цui1 зна'Ченui1 и резулътатов: параметры, являющиеся ис ходными данными для алrоритма, размещаются после ключевоrо слова знач (сокращение от значение), а выходные, ответные дaH ные перечисляются за словом рез (от результат). Так как побоч 
132 ный эффект бывает необходим, то некоторые параметры MorYT по явиться в обоих списках (в теле алrоритма такие параметры будут написаны, в частности, в левой части команд присваивания). Если же эффект нежелателен, надо защититься от Hero, образовав копии параметров и выполнив над ними необходимые действия (подчинен ный алrоритм должен работать в соответствии с правилом "не ты вычислял, ни тебе изменять"). За заroловком алrоритма находится ero тело. Оно состоит из СПе цификаций имен алrоритмов, объявлений констант, внутренних (ло кальных) объектов, общих данных и команд. Внутренние данные  это вспомоrательные величины (переменные, массивы и т. д.), Приме няемые в теле алrоритма в роли промежуточных объектов. Здесь же в объявлении им можно присвоить начальные значения. Внутренние данные (вместе с параметрамизначениями) локализуются в теле и не имеют никакоrо отношения к объектам друrоrо алrоритма с точно такими же именами. Область существования и действия внутренних величин оrраничена словами начало и конец. Вне области они не известны. При повторных вызовах Toro же алrоритма, как и при первой активизации, значения внутренних объектов не определены. Заметим, что списки параметров и их спецификации, а так же все объявления MorYT отсутствовать. Если списка параметров нет, COOT ветствующий алrоритм называется аЛ20рит-мо-м без (формальных) nара-метров. Данные в ero тело попадут, возможно, через общую память. Объявления в алrоритме заканчиваются объявлением общ их (2ЛО бальных) внешних) вели'Ч,ин  данных, принадлежащих разным ал rоритмам (именно тем, в которых написаны соответствующие объ явления). В списке общих величин через запятую можно указать имена переменных, массивов и/или объявления массивов. Таким образом, обмен данными между алrоритмами может совершаться не только через списки параметров, но и при помощи списков общих данных. Такие rлобальные величины иноrда просто необходимы, например, при решении задач с параметрами (вычислении интеrра лов, решении уравнений и систем уравнений), в задачах трансляции, информационнопоисковых задачах и т. п. Но использование списка общих величин усиливает взаимозависимость алrоритмов дру! от друrа, ослабляет их универсальность и переносимость. Результатом 
133 кодирования таких алrоритмов MorYT быть ВSпроrраммы (см. Пре дисловие), поэтому применять общую память (без большой надобно сти) не рекомендуется ("вступайте в ряды ПБОП  партии борьбы с общими переменными"). Все объявления образуют дех;ларатив'/tую 'Часть алrоритма. KOMaH ды  испол'/tяемая 'Часть. Они указывают, как решать подзадачу. Чтобы завершить работу алrоритма, тело алrоритма должно coдep жать хотя бы одну х;оманду возврата управления к точке вызова данноrо алrоритма (команду возвратиться), а для функции  еще и команду присваивания имени функции значения результирующе [о выражения, т. е. команду вида имя +---- выраже'/tие. И заканчива ется алrоритм ключевым словом конец, справа от KOToporo можно разместить комментарий, информирующий, конец KaKoro алrоритма наступил (чтобы сделать алrоритм более удобочитаемым, peKOMeH дуется комментировать все концевые фразы). . Приведем примеры алrоритмов. Вот объявление функции Mod, BЫ числяющей остаток от деления т на п: алrоритм цел Моd(цел т, п) знач т, п начало Mod +---- т  [т/п] х п возв ратиться конец А это пример вызова только что объявленной обращением к функции Modulo) k +---- Mod(13, i) + Mod(j + 1,1) /* алr Mod */ функции (сравните с Объявление процедуры моп, определяющей остаток от деления т на п, может быть таким: алrоритм МОD(цел т, п, Mod) знач т, п рез Mod начало Mod +---- т  [т/п] х п возв ратиться конец /* алr моп */ Снова вычислим значение k. Для этоrо посредством команд вызова процедуры 
134 вызвать моп(13, i, k 1 ) вызвать мопи + 1,1, k z ) обратимся сначала к процедуре MOD, rде k 1 и k z  ответные apry менты, а затем напишем команду присваивания k  k 1 + k z Команда вызова процедуры имеет вид: вызвать имя [( сп исо'Х: аР2умептов)} а вызова функции  вид: имя [( сnисо'Х: аР2умептов)} AprYMeHToM может быть первичное выражение (константа без зна ка, переменная, элемент массива, вызов.функции, выражение в скоб ках), составное выражение и/или имя алrоритма. В последнем слу чае в вызывающем алrоритме перед списком констант надо привести спецификации имен алrоритмов: для процедур  вида алr имя 1 , имяz, . . ., имя n а для функций  вида алr тиn1 иМЯ1, munz иМЯ2, ..., тиn n имя n Напомним, что aprYMeHTbI и параметры должны быть соrласованы (см. примеры выше: обратите внимание на идентичность структуры данных, типа, количества и порядка следования связанных apry ментов и параметров ). Приведем еще пример. Заrоловок процедуры численноrо интеrрирования Ralston может быть таким: алrоритм Ralston (ве щ а, Ь, Е., цел n, алr вещ f(вещ х), вещ 1) знач а, Ь, Е., п рез 1 Для тестирования процедуры при вычислении длины кривой 1 сле дует написать команду вызова вида вызвать Ralston(1.0, 2.0, 1O6, 10, f, l) rде f(x) == у'2, а в вызывающем алrоритме (в данном случае, очевид но, в rоловном)  привести спецификацию алr вещ f Общий тип функций можно указать один раз. Так как вместо параметра подставляется либо значение, либо адрес области памяти, то различают два способа замены параметров [14]. 
135 LJ А prYMeHT является выражением (первичным или составным), значение KOToporo подсчитывается в точке вызова, передается в вызываемый алrоритм и подставляется вместо соответствующе ro формальноrо параметра. Такой способ называется noдcтaHoв x:oi1 зна'Ч-ения. Ero следует предпочесть, если параметр предста вляет собой знач. Передача по значению защищает aprYMeHT от возможноrо изменения (от побочноrо эффекта), так как параметр значение локализуется в теле (вызываемоrо) алrоритма. Итак, этот способ допускает передачу данных только в вызываемый алrоритм. LJ AprYMeHT является простой переменной или переменной с индек сами (тоrда перед вызовом вычисляются индексы), а COOTBeT ствующий формальный параметр специфицирован как рез. При вызове алrоритма параметрпеременная замещается фактиче ской переменной и тоrда любые изменения в значении парамет ра отражаются на aprYMeHTe. Такой способ называется noдcтa HOBX:Oi1 nepeMeHHoi1 или nереда'Ч-еi1 по ссЪtлх:е, по адресу (в тело алrоритма передается указатель на область памяти, зарезерви рованной для aprYMeHTa в вызывающем алrоритме). Ero следует предпочесть, вопервых, для получения результатов работы ал rоритма и, BOBTOpЫX, для составных данных (массивов, записей, файлов и друrих структур данных, занимающих MHoro места в памяти компьютера) с целью экономии времени и памяти, необ ходимых для копирования данных при передаче по значению. Итак, передача по ссылке позволяет "переносить данные" как в вызываемый, так и в вызывающий алrоритм. В заключение укажем отличия алrоритмафункции от алrоритма процедуры (табл. 4.1). Таблица 4.1. Отличия алrоритмаФункции от алrоритмапроцедуры Функция П роцедура Вычисляет, как правило, одно значение Вычисляет, как правило, MHO ro значений 
136 Таблица 4.1 (окончание) Функция П роцедура в заrоловке указывается тип имени функции (т. е. тип ее значения) В списке параметров, как правило, нет параметров результатов Имени функцииназнача ется результат Обращение с помощью вызова функции Нельзя объявлять тип имени процедуры Списки параметроврезульта тов, как правило, не пусты Ответы назначаются парамет рамрезультатам Обращение посредством KOMaH ды вызова Общий вывод: процедура есть обобщение функции. Двумерный массив Объектами обработки некоторых алrоритмов нередко являются пря моуrольные таблицы данных, называемые иначе двумерными Mac сивами. Примером TaKoro массива может быть таблица Пифаrора  квадратная таблица А из 10 строк и 10 столбцов, каждый элемент которой определяется формулой aij = i х j (i, j = 1, 2, . . ., 10). По ложение элемента aij в таблице задается двойным индексом: пер вый (i) обозначает номер строки элемента, а второй (j)  номер ero столбца, на пересечении которых стоит элемент (нумерация строк производится сверху вниз, а столбцов  слева направо). К ДBYMep ным массивам относятся также таблицы соревнований, коэффици енты систем уравнений, шахматные доски, таблицы распределения температур HeKoToporo тела и т. д. Реже на практике встречаются массивы, содержащие три и более измерений. Объявление двумерных массивов пишется аналоrично одномерным, но для прямоуrольной таблицы надо указать rраницы изменения ин дексов как по rоризонтали, так и по вертикали. Например, объявим таблицу А квадратов натуральных чисел от 10 до 99, состоящую из 
137 9 строк и 10 столбцов. Вот это объявление: цел массив А[l : 9, О : 9] Если нижняя rраница индекса равна еДИНИце, ее в объявлении мож но не указывать. Матрица Матричное исчисление иrрает большую роль при решении при кладных задач. Оно положено в основу математическоrо аппарата квантовой и статистической механики и физики, радиоэлектроники, теории колебаний, rде фундаментальное значение имеют xapaKTe ристические уравнения, собственные числа и векторы. К задачам линейной алrебры сводятся мноrие алrоритмы обработки данных, минимизации линейных форм, а также задачи теории упруrости и пластичности. Если т х п выражений расставлены в прямоуrольной таблице А из т строк и п столбцов, то rоворят о .матри'4е размера т х п. Bы ражения aij (i == 1, 2, . . . , т; j == 1, 2, . . . , п) называются эле.мен та.ми .матри'4Ы. К ним относятся, как правило, числа, но иноrда и друrие математические объекты, например, векторы, полщюмы, дифференциалы и даже матрицы. Матрицу размера 1 х п называ ют вeKтopcтpOKoи, а матрицу размера т х 1  векторстолб'40.м. Скаляр можно рассматривать как матрицу размера 1 х 1. Матрицы А == (aik) (i == 1,2, .", т; k == 1,2, ..., п) и В == (b kj ) (k== 1, 2, ..., п; j == 1, 2, ..., 1) являются С'4еnленны.мu, так как число столбцов первой матрицы равно числу строк второй.. Для таких объ ектов определена операция умножения: nроuзведенuе АВ .матри'4 А и В есть матрица С == (Cij) (i == 1,2, ..., т; j == 1, 2, ...,1), rдe Cij == I:=1 aikbkj, т. е. элемент, стоящий в iй строке и jM столбце матрицы произведения, получается в результате скалярноrо произ- ведения iй векторстроки матрицы А на j-й вектор-столбец матри цЫ В. Решим задачу вычисления матрицы С. Пусть элементы матриц сомножителей есть числа типа вещ. Разработаем алrоритм так, что бы он служил для перемножения нескольких пар матриц произволь ных размеров. Для этоrо отделим операции ввода/вывода матриц от процесса умножения. Тоrда функциональная схема будет состоять 
138 из двух алrоритмов  rоловноrо с именем Проuзведенuе .матриц и подчиненноrо  с именем Mult (от multiply  умножить) (рис. 4.2). I rоловной алrоритм I I алr Mult (ве щ массив A[lim,lim], B[lim,lim], цел lim, т, n, 1, вещ массив C[lim,limJ) Рис. 4.2. Функциональная схема вычисления матрицы С Функции rоловноrо алrоритма обычны: задать исходные матрицы А и В, активизировать алrоритм Mult и вывести результаты  матри цу С. Функция алrоритмапроцедуры Mult также ясна: зная "сырье" (вещественные матрицу А размера т х n и матрицу В размера n х 1), а также максимальные и верхние rраницы индексов (целые пере менные lim, т, n, 1), выдать результат (вещественную матрицу С размера т х 1). Пусть дано т == п == 1 == 3. Приведем Проект rоловноrо алrоритма: алrоритм Проuзведенuе .матри'Ц алr Mult /* C[l : т, 1 : 1] == A[l: т, 1: n] х B[l: n, 1: 1] */ конст цел lim f----- 30 цел т, n, 1, i, j, k вещ массив A[lim, lim], B[lim, lim], C[lim, lim] начало вывести подсказки для ввода т, n, 1, А, В ввести т, n, 1 и массивы А, В вывести заrоловок задачи, значения т, п, 1 и массивы А, В вызвать Mult(A, В, lim, т, п, 1, С) вывести заrоловок выходных данных и массив С конец /* rоловноrо алr */ Заметим, вопервых, что этот алrоритм состоит только из команд "цепочка", и, BOBTOpЫX, он обрабатывает составные объекты, зна чит, начальные значения т, n, 1 и матрицы А, В лучше задать в базе данных (с.м. разд. "Фаi1л" zлавы 9). Так как решаемая задача проста, то достаточно одноrо шаrа дeTa лизации. Сказанное касается и подчиненноrо алrоритма Mult. Для нахождения элементов Cij нужно выполнить тройной арифметиче 
139 ский цикл: внешний  по переменной i от 1 с шаrом, равным 1, до т включительно; следующий, вложенный в первый,  по переменной j = 1 (1) 1 и еще один, вложенный внутрь BToporo,  по переменной k = l(п)l. В последнем цикле будем накапливать сумму произведе ний aikbkj. Построим сразу эффективный алrоритм умножения матриц. В дaH ной задаче это нетрудно сделать. Назовем х:рuтuчесх:оi1 областъю фраrмент алrоритма, на работу KOToporo требуется большая часть времени исполнителя. Такой областью в нашем случае является внутренний цикл по переменной k (ero команды будут выполняться m х 1 хп раз), поэтому именно ero надо тщательно проектировать (Ha личие во внутреннем цикле" лишнеrо" действия может заметно YBe личить общее время выполнения Bcero алrоритма). Здесь перемен ные i и j имеют постоянные значения (не зависят от параметра k), следовательно использование элемента массива Cij при накаплива нии суммы требует дополнительных ресурсов, необходимых дЛЯ BЫ числения индексов z и ), поэтому индексированную переменную Cij заменим простой переменной 8 (СМ. разд. "П овторен,ие" 2лавы 13). Приведем текст алrоритма Mult: "- алrоритм Мult(ве щ массив A[liт,liт), B[liт,liт), цел liт, т, n, 1, вещ массив C[liт,liт)) знач А, В, liт,т, п, 1 рез С /* С[l : т, 1 : 1] == А[l : т, 1 : n) х В[l : n, 1 : 1] */ целi,j,k веЩ8 начало для i от 1 до т шаr 1 выполнять для j от 1 до 1 шаr 1 выполнять 8+------0 для k от 1 До n шаr 1 выполнять 8 +------ 8 + aikbkj конеццикл /* по k */ Cij +------ 8 конеццикл конеццикл возвратиться конец /* по j */ /* по i */ /* алr М ult */ 
140 Рассмотрим подробнее этот алrоритм. В нем три связанные команды повторения. Исполняется он так. Сначала параметру i назначается значение 1, а затем начинает работать цикл по переменной j (пара метру j присваивается значение 1). Первая ero команда  "обнуле ние" суммы 8 (8 +------ о). Потом включается в работу цикл по пере менной k. Именно в этом цикле (пока k не превосходит значение п) вычисляется сумма произведений ааЬн. Коrда цикл по k выполнит ся п раз, совершится нормальный выход из тела этоrо цикла в цикл по параметру j. Здесь элементу Сll назначается значение 8 (Cij +------ 8) И проверяется условие выполнения цикла по j и::;; 1). Если оно co блюдается, значение j увеличивается на единицу и при i, равном значению 1, и j, равном 2, снова реализуется цикл по переменной k== l(п)l, в результате чеrо будет найдено значение C12 и т. д. Коrда цикл по j "прокрутится" 1 раз, заполнится первая строка матрицы С, после чеrо значение i увеличивается на единицу и станет paB ным двойке, параметр j примет значение 1, снова работает цикл по переменной k, формируется вторая строка матрицы С и т. д. Теперь спланируем тестирование. Проверку алrоритма в нормаль ных условиях работы выполним для матриц о 2 ) А== 5 8 и (: 2 ) В== 2 2 Должна получиться матрица С 12 18) С == 15 30 45 . 24 48 72 В экстремальных условиях rраничные испытания проведем при т == п == 1 == 1,30. Заметим, что перемножение двух матриц размера пхп  процес порядка п З (пишут О(п З )). Практически это означает, что число шаrов и время работы алrоритма Mult пропорциональны кубу п. Выходные данные в этой задаче будут иметь вид 
141 u============================================ uПроизведениеuматрицuС=АВ. uuuuИсходныеuданные: um=u3uun=u3uu1=u3 uМатрицаuА[m,nJ: uuuuuuuu1.00000uuuuuuuu2.00000uuuuuuuu3.00000 uuuuuuuu4.00000uuuuuuuu5.00000uuuuuuuu6.00000 uuuuuuuu7.00000uuuuuuuu8.00000uuuuuuuu9.00000 uМатрицаuВ[n,lJ: uuuuuuuu1.00000uuuuuuuu2.00000uuuuuuuu3.00000 uuuuuuuu1.00000uuuuuuuu2.00000uuuuuuuu3.00000 uuuuuuuu1.00000uuuuuuuu2.00000uuuuuuuu3.00000  u uuuuOTBeT: uМатрицаuС [m ,1] : uuuuuuuu6.00000uuuuuuuu12.0000uuuuuuuu18.0000 uuuuuuuu15.0000uuuuuuuu30.0000uuuuuuuu45.0000 uuuuuuuu24.0000uuuuuuuu48.0000uuuuuuuu72.0000 u============================================ Наконец, перейдем к этапу кодирования. Сначала подберем имена. Назовем А, В, lim, т, n, 1, С, i, j, k и s соответственно А, В, Lim, М, N, L, С, 1, J, J{ и S. Алrоритм вычисления С == АВ был за писан тремя языками. Испытания проrрамм закончились успешно. Отметим, что в Паскале и Си нет массивовых операторов передачи данных, поэтому можно использовать следующие аЛ20рuт.м:ы ввода/ вывода матри'Ц: /* алr Getmatr( вещ массив A[lim, lim], знач lim, т, n рез А цел 1, ) начало для i от 1 до m шаr 1 выполнять для j от 1 до n шаr 1 выполнять ввести aij конеццикл конеццикл */ цел lim, т, n) /* A[l :т, 1 :n] */ /* ввода строки */ /* ввода матрицы */ 
142 возвратиться конец /* алr Getmatr */ *1 /* алr PuCmatr( вещ массив A[lim, lim], знач А, lim, т, п цел Z, J начало вывести нова,я стро'/\:а для i от 1 ДО т шаr 1 выполнять для j от 1 до п шаr 1 выполнять I I вывести uu, aij цел lim, т, п) /* A[l :т, 1 :п] *1 конеццикл вывести нова,я стро'/\:а конеццикл возвратиться конец /* /* вывода строки */ /* вывода матрицы */ /* алr Putmatr */ */ Маrическиii квадрат Теперь познакомимся сневычислительным алrоритмом. Между BЫ числительным иневычислительным алrоритмами нет резкой rрани. Запись невычислительноrо алrоритма требует, как правило, прос тых средств. К примеру, решим следующую задачу: построим маrи ческий квадрат нечетноrо порядка п. Ма2u'Чес'/\:u.м '/\:вадрато.м назы вают совокупность чисел, так расположенных в квадратной таблице, что суммы чисел любой строки, любоrо столбца и диаrоналей равны друr друrу. Если квадрат порядка п составлен из последовательно сти целых чисел от 1 до п 2 , то каждая такая сумма равна (n 2 +1)n/2. Один из квадратов при п == 3 имеет вид, показанный на рис. 4.3. 4 3 8 9 5 1 2 7 6 Рис. 4.3. Маrический квадрат при n = 3 
143 Маrические квадраты были известны еще до новой эры в Китае, а в Европе они появились лишь в начале ХУ столетия. Маrическими их называют потому, что в те далекие времена некоторым числам и их сочетаниям приписывались определенные свойства (серебря ные пластинки с выrравированными маrическими квадратами носи ли как амулеты, предохраняющие от болезней и поветрий). Итак, построим маrический квадрат нечетноrо порядка n. Сформу лированная задача труднее любой ранее рассмотренной. "С наскоку" ее решить, наверное, не удастся. Первой сложностью будет разбие ние всей задачи на подзадачи  проектирование методом "сверху вниз". Следующий шаr  управление сложностью в rраницах каж дой подзадачи методами CTPYKTypHoro проrраммирования [10, 12, 14, 15,23,36,41,66]. Структурный подход хорошо соrласуется с методом пошаrовой дeTa лизации. Очевидно, что в данной задаче не удастся обойтись одним двумя шаrами детализации. И прежде чем приступать к проектиро ванию, уточним принципы самой детализации. Пошаzова.я деталu зацu.я  это процесс разложения функции алrоритма на подфунк ции в соответствии с внутренней лоrикой алrоритма, это процесс, при котором путем MHoroKpaTHoro анализа алrоритма выявляются все более подробные детали. Пошаrовая детализация  творческий процесс. Она способствует разработке правильных и хорошо CTPYK турированных алrоритмов. Но для этоrо нужно придерживаться He скольких общuх nринциnов уто'Чненu.я ЛОZUХ;U алzорuтма [66]: LJ Не спешите заняться мелочами. На одном шаrе детализации дe лайте небольшие расширения и в первую очередь выделяйте наи более важные моменты. LJ Не торопитесь. Задавайте себе вопросы. Тщательно анализируй те принимаемые решения. С каждым расширением обычно свя заны очевидные и не совсем очевидные решения. Они MorYT отли чаться набором и количеством используемых команд и/или леr костью восприятия. Окончательное решение принимайте только после тщательноrо сравнения вариантов. Не при меняйте слож ные приемы там, rде можно использовать простые. Никаких трю ков и заумных решений. Думайте. Думайте и проектируйте ясно. Как правило, "простой", леrкочитаемый вариант проекта бы стрее приводит к нужным результатам. 
144 C:J Будьте rOToBbI отменить ранее принятые решения. Исправления и изменения обходятся HaMHoro дороже после Toro, как алrо ритм закодирован. Помните, что улучшение качества любоrо ro TOBoro продукта  дело крайне тяжелое. C:J Уделяйте достаточное внимание данным. Термин "данное" здесь относится к входным, промежуточным и выходным данным, при чем входные  это исходные данные и параметрызначения, про межуточные  это счетчики, рабочие (вспомоrательные) пере менные и массивы и т. п., определенные внутри алrоритма, BЫ ходные  это результаты работы алrоритмов и всей задачи. До начала процесса детализации составьте список данных и опреде лите их характеристики. Затем для каждоrо элемента данных отдельно решите, rде он применяется (пересылается, накапли вается или участвует в вычислениях, в проверках), rде и коrда ему нужно присвоить, может быть, начальное значение, rде это значение изменяется, восстанавливается и т. д. Вернемся к сформулированной ранее задаче. Существует несколь ко методов построения маrических квадратов [66]. Один из них, .мe тод "Ю20востоi', применяется для конструирования квадратов He четноrо порядка. Название  I'uMY методу дает общий план построе ния квадрата: заполнение клеток начинают с правой клетки средней строки, а очередное чис jlv всида заносится в клетку, расположен ную юrовосточнее от только что заполненной. При реализации Ta Koro подхода возможны 'Четыре особых слу-ч,а.я. 1. Смещение на юrовосток приводит в уже заполненную клетку. В такой ситуации из последней заполненной клетки перейдем в co седнюю клетку слева. 2. Смещение на юrовосток приводит к выходу из квадрата впра во. Тоrда перейдем в клетку, находящуюся в той же строке, что и "запредельная", но в первом столбце. 3. Смещение на юrовосток приводит к выходу из квадрата вниз. В этом случае перейдем в клетку, расположенную в том же столбце, что и "запредельная", но в первой строке. 4. Смещение на юrовосток приводит к выходу из квадрата впра во и вниз. Тоrда выполним в любой последовательности переходы соrласно пунктам 2 и 3. 
145 Теперь применим изложенную методику к построению квадрата TpeTbero порядка (см. рис. 4.3). Впишем единицу в третью клетку средней строки квадрата и сместимся на юrовосток. На рис. 4.4, а направление перехода отмечено сплошной стрелкой. Ее острие YKa зывает место остановки. Ш :'>1,; . ,3, ':,5:нА;' ,t?iA а б 6 2 Рис. 4.4. Схема заполнения маrическоrо квадрата Так как здесь возник особый случай 2, то совершим переход в Ha правлении штриховой стрелки и занесем в очередную клетку двой КУ. Новый шаr на юrовосток приводит к особому случаю 3, по этому тройку запишем во вторую клетку первой строки квадрата (рис. 4.4,6). Сделаем очередной шаr. Он приводит к особому слу чаю 1, поэтому четверку занесем в первую клетку первой строки (рис. 4.4,6). Очередные два перехода совершим соrласно общему плану. Третий шаr приводит к особому случаю 4 (рис. 4.4, 2). В co ответствии с указаниями пп. 2 и 3 перейдем в первую клетку пер вой строки, что создаст особый случай 1, так как эта клетка уже занята. Тоrда вернемся в третью клетку третьей строки, а из нее переместимся в соседнюю слева клетку. Поиск клеток для размеще ния двух оставшихся чисел (восьмерки и девятки) создаст последо- вательно особые случаи 3 и 2. Выполним рекомендации пп. 3 и 2. Таким образом, маrический квадрат нечетноrо порядка построен. Теперь займемся разработкой алrоритма. Он должен обеспечить ввод порядка квадрата n, контроль значения n, построение KBaд рата при нечетном значении n, вывод квадрата и вывод сообщения об ошибке при n < 1 или четном значении n. Ввод n и вывод маrическоrо квадрата выполнит rоловной алrоритм. Дадим ему имя Ма2u'Чесх;ui1 'Х:6адрат. Здесь же определим константу lim  максимальный по рядок квадрата, что позволит сделать подчиненный алrоритм уни версальным. Построение квадрата совершит подчиненный алrоритм, который назовем Magic. 
146 Решим теперь, какому алrоритму поручить контроль значения n и вывод информации об аварийной ситуации. Функциональное назна чение подчиненноrо алrоритма  формирование квадрата при дo пустимом значении n, а назначение rоловноrо алrоритма  общее управление работой, в том числе и заказ на построение квадрата. Лоrика управления в rоловном алrоритме будет яснее, если ero про ектировать по схеме "ввод n  заказ", т. е. если перенести контроль значения n в подчиненный алrоритм. При неверном значении n под чиненный алrоритм должен известить заказчика, т. е. rоловной ал rоритм, о невозможности выполнить работу. Так как алrоритм низшеrо уровня не может принимать решений за алrоритмы более высоких уровней, то подчиненный алrоритм всеrда независимо от Toro, что произошло при ero исполнении, должен пе редать управление к точке вызова, т. е. в конечном итоrе в rоловной алrоритм. Последний, если есть ошибка, выдаст сообщение об aBa рийной ситуации, которое будет информацией для автора алrорит мов и возможных пользователей. Итак, пришли к следующему pac пределению функций между алrоритмами: Маzu'ЧеС1Сui1 1Свадрат  ввод n, обращение к подчиненному алrоритму, вывод квадрата, BЫ вод сообщения об ошибке; Magic  контроль n, фиксация ошибки в значении n или построение квадрата. Теперь определим интерфейс, т. е. установим информационную связь между алrоритмами. rоловной алrоритм должен передать под чиненному значения lim и n, а подчиненный  вернуть либо Ma rический квадрат, либо информацию о невозможности ero построе ния. Для размещения квадрата нужна память  таблица, состоящая из lim строк и lim столбцов. Этот прямоуrольный массив размера lim х lim обозначим через А. ДЛЯ представления ошибки выберем цe лочисленную переменную (дадим ей имя error), принимающую лишь два значения, причем одно из них, например, единица, будет COOT ветствовать успешному завершению работы подчиненноrо алrорит ма, а второе, равное нулю,  информировать об ошибке в значении n. Итак, формальными параметрами алrоритма Magic будут: lim  макСимальный порядок квадрата, n  фактический порядок, А  имя массива, представляющеrо квадрат, и переменная error  фик сатор ошибки в значении n (флажок) (рис. 4.5). 
Ма2u'Ч,ескul1 квадрат 147 алr Magic (цел lim, n, цел массив A[lim,lim], цел еттот) Рис. 4.5. Функциональная схема построения квадрата Теперь приступим к проектированию алrоритмов. Применим опе рационный подход. Проектирование начнем с rоловноrо алrоритма. Шаrи детализации ero работы MorYT быть такими: алrоритм Ма2u'Ческul1 квадрат алr. Magic объявить данные { объявить lim, n, еттот и квадрат А начало ввести n вывести заrоловок задачи, n построить квадрат { конет цел lim +----- ЗЗ цел n, еттот цел маССИJJ A[lim,lim] {вызвать Magic(lim, n, А, еттот) если n ошибочно если еттот== О то вывести сообщение вывести об ошибке результат иначе вывести квадрат А конецесли конец то вывести '*** error: неверно задан поря док квадрата. Magic.' иначе вывести квадрат А конецесли /* rоловноrо алrоритма */ Для описания. работы rоловноrо алrоритма достаточно ДBYXTpex шаrов детализации. Это характерно для таких алrоритмов, так как они обычно выполняют диспетчерские функции. Для вывода маrи ческоrо квадрата можно привлечь алrоритм PиtmatT, представлен ный в разд. "Двумерныl1 Массив" данноl1 2лавы. Тоrда команду вывести квадрат А следует заменить командой 
148 вызвать PuCmatr(A, lim, n, n) Спроектируем теперь подчиненный алrоритм. Вероятно, ДBYXTpex шаrов детализации алrоритма Magic будет недостаточно. Не станем спешить, а сконцентрируем внимание на самом существенном. Не будем стремиться к уменьшению числа шаrов. Первые два шаrа дe тализации очевидны: алrоритм Magic (цел lim, n, цел массив A[lim,lim], цел еттот) знач lim, n рез А, еттот объявить вспомоrательные величины начало проверить значение n построить квадрат конец если n == (n 72) х пили n < 1 то присвоить еттот ноль возвратиться к точке вызова алrоритма Magic иначе присвоить еттот единицу конецесли подrотовить цикл пока очередное число:::;; n 2 выполнять перейти на юrо восток контролировать номер строки контролировать номер столбца проверить содержимое клетки поместить в клетку текущее число увеличить очередное число на единицу Конеццикл /* алr Magic */ Поясним сделанные шаrи. При построении квадрата, кроме парамет ров, наверняка понадобятся вспомоrательные переменные, поэтому предусмотрим их объявление. Количество и типы этих величин пока неизвестны. На втором шаrе детализации уточним, как будем KOH тролировать значение n. Ошибочными являются четные n или зна чения, меньшие единицы. Так как четное число нацело делится на двойку, а удвоенное частное равно исходному значению, то условие 
149 проверки n будет таким: n == (n ...;-- 2) х пили n < 1. Здесь операция +, определенная для цел операндов, означает "делить нацело" (в Паскале она обозначается div, а в Си и Фортране  символом /). Рассмотрим теперь подробнее действия, названные "построить квадрат". Здесь нужно занести единицу в правую клетку среднеrо ряда и начать циклическую часть алrоритма: сместиться на юrо восток; контролировать и корректировать номера строк и столбцов; проверять, является ли клетка свободной; возвращаться обратно и смещаться влево; заносить в клетку очередное число и т. д. Объеди ним первые два шаrа детализации в один и сделаем новый, третий шаr. В результате получим: алrоритм Magic (цел lim, n, цел массив A[lim,lim], цел error) знач lim, n рез А, error объявить вспомоrательные величины начало если n == (n"';-- 2) х пили n < 1 то присвоить errOr ноль возвратиться к точке вызо ва алrоритма Magic иначе присвоить error единицу конеЦесли подrотовить цикл пока очередное число  n 2 BЫ полнять перейти на юrовосток контролировать номера строк { цел k объявить друrие величины если n == (n"';-- 2) х пили n < 1 то error +---- О возвратиться иначе error +---- 1 конецесли поместить в клетку начальную единицу присвоить k двойку подrотовить друrие величины {пока k  n 2 выполнять {сместиться вниз и вправо если выход вправо то перейти в первый столбец конецесли 
150 контролировать номера столбцов проверить содержимое клетки поместить в клетку текущее число увеличить очередное число на единицу если выход вlIиз то перейти в первую строку конецесли если клетка занята то вернуться обратно сместиться влево Конецесли { поместить в очередную клетку текущее значение k { заменить значение k на значе ние k + 1 Конеццикл возв ратиться конец /* алr Magic */ Приступать к этапу кодирования еще рано, ибо детализация не вез де доведена до уровня вычислений по формулам или проверки BЫ полнения неравенств. Действительно, как, например, реализовать операцию "поместить в клетку начальную единицу"? Так как KBaд рат  это прямоуrольная таблица с именем А, то запись в нее числа означает изменение значения HeKoToporo ее элемента. Для Выделе ния элемента нужно указать номер строки i и номер столбца j, на пересечении которых этот элемент находится. Итак, на новом шаrе детализации объявим и вычислим координаты клетки i и j. Тоrда в циклической части алrоритма конкретизируются мноrие действия: алrоритм Magic (цел lim, n, цел массив A[lim,lim], цел error) знач lim, n рез А, error цел k объявить друrие величины начало { цел Z, J объявить друrие величины 
если n==(n--;..-2)хn или n<1 то еттот +----- О возвратиться иначе еттот +----- 1 конецесли поместить в клетку началь ную единицу присвоить k двойку подrотовить друrие величины пока k:::;; n 2 выполнять сместиться вниз и вправо если выход вправо то перейти в первый столбец конецесли если выход вниз то перейти в первую строку конецесли если клетка занята то вернуться обратно сместиться влево конецесли поместить в очередную клет ку текущее значение k 151 если n mod 2 == О или n < 1 то еттот +----- О возвратиться иначе еттот +----- 1 конецесли {aij +----- 1 {см. 1tUJfCe за20ловох; цuх;ла для { присвоить i значение (n + 1) /2 присвоить J значение n подrотовить друrие величины { для k от 2 до n 2 шаr 1 BЫ полнять { увеличить i. на единицу увеличить J на единицу если j > n то присвоить J единицу конецесли если i > n то присвоить z единицу конецесли ? {присвоить aij значение k 
152 заменить значение k на зна чение k + 1 {см. выше за.илово1С 'ЦU1Сла для конеццикл /* по k */ возвратиться конец /* алr Magic */ Поясним два улучшения в алrоритме: первое связано с проверкой четности n (в силу равенства нулю остатка от деления четноrо числа на двойку она теперь представлена в более понятном виде n mod 2 == О), а второе  с заменой команды пока командой для (в случае арифметическоrо цикла с параметром последняя команда лаконичнее и естественнее пока). Спроектируем теперь проверку условия "клетка занята" и действий "вернуться обратно" и "сместиться влево". При построении KBaдpa та вручную, на листе бумаrи, всякая незаполненная клетка пуста. Это не означает вовсе, что элемент массива А, соответствующий He заполненной клетке, равен нулю. Так как разрабатываемый проект будет в конечном итоrе записан языком проrраммирования, а COOT ветствующая проrрамма выполнена на компьютере, то, учитывая, что отводимая массиву память при трансляции, как правило, пред варительно не "очищается" (например, не "обнуляется"), предложе ние "подrотовить друrие величины" расшифруем как "поместить в А нули", а фразу "клетка занята" заменим неравенством aij =1= О. Уточним теперь операции возврата обратно и смещения влево. Так как переход на юrовосток совершается увеличением значений i и . . . J на единицу, то возврат осуществим вычитанием единицы из z и J. ДЛЯ перехода влево уменьшим значение j еще на единицу. Получим такую команду: если aij =1= о то уменьшить z на единицу уменьшить j на двойку конецесли Но не будем торопиться, а тщательно проанализируем принимае мое решение. Приведет ли оно к цели? Не всеrда. Результат будет ошибочен, если после смещения проводилась корректировка HOMe ров строки и столбца, после которой "вернуться обратно" вычита нием единицы уже невозможно. Тоrда отбросим это решение. Пра 
153 вильным вариантом возврата будет присваивание переменным i и j значений, которые они имели до шаrа на юrовосток. Учтем еще, что само смещение и последующие коррекции изменяют значения Z и j. Для восстановления этих значений объявим вспомоrательные . . переменные Zcopy и )сору, которым перед смещением назначим COOT ветственно значения i и j. Теперь при смещении и корректировках будут меняться значения i и j, а их копии i copy и jcopy останутся неизменными. Итак, действия "вернуться обратно" и "сместиться влево" можно выполнить, полаrая i равным i copy , а j равным jcopy  1. С учетом всех уточнений получим новый вариант подчиненноrо ал rоритма: алrоритм Magic (цел lim, n, цел массив A[lim,lim], цел error) знач lim, n рез А, error цел k, i, j объявить друrие величины {цел i copy , jcopy начало если n mod 2 == О или n < 1 то error  О возвратиться иначе error  1 конецесли подrотовить друrие величины aij  1 присвоить i значение (n + 1) /2 присвоить ) значение n для k от 2 до n 2 шаr 1 BЫ полнять образовать копию i образовать копию j увеличить Z на единицу увеличить ) на единицу {поместить в А ну ли {i  (n+1)/2 {j  n {icopy  i {jcOpy  j {ii+1. {j  j + 1 
154 если J > n то если j > n то j  1 присвоить J единицу конецесли если i > n то присвоить Z единицу конецесли если aij =1= о то конецесли если i > n то i  1 конецесли если aij =1= о то заменить Z на Zcopy заменить j на jCOpy  1 конецесли присвоить aij значение k z  Zcopy j  jcopy  1 конецесли {aij  k / * формирования квадрата * / конеццикл . возвратиться конец /* алr Magic */ Проект rOToB. Расшифруем в нем фразу "поместить в А нули": для i от 1 до n шаr 1 выполнять для j от 1 до n шаr 1 выполнять aij  О конеццикл /* по j */ конеццикл /* по i */ А свободен ли проект от ошибок? Вроде бы, да  ведь столько сил, внимания было затрачено на ero создание. Да и решаемая задача не так уж сложна. Однако истинный профессионал не должен ниче ro принимать на веру. Проектировщик  живой человек. Он может ошибаться, и правильный "с первоrо раза" проект  скорее исклю чение, чем правило, во всех случаях, кроме тривиальных. Для ответа на вопрос о наличии ошибок можно выполнить ручную прокрутку И тестирование. Начнем с прокрутки. Положим n = 3. fоловной алrоритм верен, а подчиненный содержит ошибку. Ее най ти нетрудно. Координаты ошибки  команда при сваи вани я aij  1. 
155 Здесь не определены индексы элемента массива. Эту команду нуж но разместить после команд i f-------- (n + 1) /2 и j f-------- n. Больше ошибок нет (правда, проrраммисты в таком случае rоворят, что последняя обнаруженная ошибка есть предпоследняя). Приведем окончательный проект алrоритма Magic: алrоритм Magic (цел lim, n, цел массив A[lim,lim], цел error) знач lim, n рез А, error цел k, i, j, i copy , jcopy начало если n mod 2 == О или n < 1 то error f-------- О возвратиться иначе error f-------- 1 конецесли для i от 1 До n шаr 1 выполнять для j от 1 до n шаr 1 выполнять aij f-------- О конеццикЛ конеццикл /* "очистки" квадрата */ if--------(n+l)/2 Jf--------n aij f-------- 1 для k от 2 до n 2 шаr 1 выполнять . . . . Zcopy f-------- Z Jcopy f-------- J if--------i+l jf--------j+l если j > n то j f-------- 1 конецесЛИ если i > n то i f-------- 1 конецесли если aij -j. О то Z f-------- Zcopy j f-------- jCOpy  1 конецесЛИ а" f-------- k '1 конеццикл / * формирования квадрата * / возв ратиться конец /* алr Magic */ Предусмотрим тестирование. В нормальных условиях возьмем n == 5. 
156 Должны получиться следующие результаты: u============================== uМаrическийuквадрат. uuuuИсходныеuданные: u n =5 u UUUUOTBeT. uМаrическийuквадратuА[n,n] : uuuulluuuul0uuuuu4uuuu2Зuuuu17 uuuu18uuuu12uuuuu6uuuuu5uuuu24 uuuu25uuuu19uuuulЗuuuuu7uuuuul uuuuu2uuuu21uuuu20uuuu14uuuuu8 uuuuu9uuuuuЗuuuu22uuuu16uuuu15 u============================== В экстремальных условиях при проверке rраничных объемов данных /положим n == 1, 33, а в исключительных ситуациях выберем значения n == 2, О и 2. В последних случаях результатом работы будет вывод сообщения об ошибке в задании n. Теперь приступим к завершающей части решения  кодированию алrоритмов. Выберем следующие имена переменных: для lim  Lim, для n  N, дЛЯ А  А, дЛЯ error  Error, для k  К, дЛЯ i  1, для j  J, дЛЯ i copy  Icopy и, наконец, для jCOpy  Jcopy. Составленные проrраммы были успешно выполнены на компьютере. Замечание Обработка матриц и вспомоrательные алroритмы требуют средств кодирования, изложенных в zлавах 7 u 8. Упражнения Решите приведенные ниже задачи, выделив rоловной и подчинен ные алroритмы (процедуры). Входные данные (при необходимости) выберите самостоятельно. Замечание Алrоритмы должны быть надежны, леrкочитаемы, эффективны и универсальны. Рекомендуемые этапы решения: формулировка за 
157 дачи; алrоритмизация (выбор метода решения), построение MaTe матической модели; проектирование (функциональная схема, про ект алrоритмов); планирование тестирования; "картинка" BЫBOД ных данных; кодирование (список имен и обозначений, проrрам ма); выполнение проrраммы на компьютере, анализ результатов и составление отчета. 1. Получите матрицу С == (Cik) (i, k == 1, 2, ..., п), элементы которой суть минимальные значения из соответствующих значений элемен тов матрицА==(аik) и B==(b ik ) (i,k==l, 2, ..., п); п==4. 2. В каждом нечетном столбце матрицы А == (aik) (i == 1,2,..., т; k == 1,2,..., п) подсчитайте количество элементов, принадлежащих промежутку (1r e ; e 7r ]; т == 4, п == 5. 3. Матрица А == (aij) (i, j == 1, 2, . . . , п) получена в результате измере ний. Если элементы, симметричные относительно rлавной диаrона ли, равны по модулю, то матрица А является либо сu.м.метрu'Ч,ес-к;оi1 (элементы равны), либо ососu.м.метрu'Ч,ес-к;оi1 (элементы имеют про тивоположные знаки). Выясните вид матрицы А; п == 5, Б == 103. 4. Сформируйте вектор Ь из цел элементов матрицы А размера п х п, лежащих правее диаrоналей и принадлежащих промежутку [т; k]; п == 5. 5. Получите вектор Х == (Xi) (i == 1,2, ..., п), элементы KOToporo co ответственно равны квадратам сумм элементов диаrоналей матрицы А размера п х п; п == 5. 6. Сформируйте вектор из средних арифметических элементов, являющихся нечетными числами четных строк матрицы А == (aij) (i == 1,2, ..., т; j == 1, 2, ..., п); т == 8, п == 3. 7. Пронормируйте матрицу А == (aij) (i,j == 1,2, ..., п) по ее Tpe тьей норм е, т. е. получи те матрицу В == (b ij ), rдe b ij == а 1 "j/IIАll з , IIAlIз == V "L':=.l "Lj=l laijl2; п == 5. 8. Матрица А == (aik) (i == 1,2, ..., т; k == 1,2, ..., п) содержит два одинаковых элемента. Найдите эти элементы и их индексы (ника кой элемент матрицы не должен сравниваться сам с собой); т == 4, п == 5. 9. Квадратную матрицу В размера т х т образуйте из чисел от 1 до т 2 , расположив их по спирали. Обход начните с левоrо BepxHero 
158 уrла в направлении по часовой стрелке; т == 6. 10. Получите вектор Х == (Xi) (i == 1,2, ..., п), элементы KOToporo равны элементам побочной диаrонали матрицы А == (aij) (i, j == == 1, 2, ..., п), преобразованной предварительно следующим обра зом: в начале каждой строки матрицы находятся положительные элементы, затем следуют нули, а в конце  отрицательные элемен ты; п == 5. 11. Вычислите k!, rде k  количество нулевых элементов в четных столбцах матрицы А размера т х п; т == 3, п == 8. 12. Найдите rлавный (наибольший по модулю) элемент матрицы А == (aij) (i,j == 1,2, ..., п), ero индексы и поделите матрицу А на этот элемент; п == 5. 13. Найдите максимальный элемент среди отрицательных элемен тов, расположенных левее диаrоналей матрицы А размера п х п, и определите ero индексы; п == 5. 14. В матрице A==(aij) (i==1, 2, ..., т; j==1, 2, ..., п) найдите наи меньшее число Ь, обладающее следующим свойством: хотя бы в ok ной строке матрицы все элементы не превосходят Ь; т == 4, п == 6. 15. Найдите сумму элементов четных строк матрицы А == (aij) (i == 1,2, ..., т; j == 1,2, ..., п), в которых на rлавной диаrонали расположены числа, кратные k; т == 6, п == 6, k == 13. 16. В матрице А == (aik) (i == 1,2, ..., т; k == 1,2, ..., п) найдите наибольший элемент Ь, обладающий СЛедующим свойством: в лю бом столбце матрицы есть элемент, не меньший Ь по модулю; т == 4, п == 6. 17. Проверьте, является ли матрица А размера т х т маrическим квадратом; т == 5. 18. Пронормируйте матрицу А == (aij) (i,j == 1, 2, ..., п) по ее пер вой норме, т. е. получите матрицу В == (b ij ), rдe b ij == aij / 11 А 111' IIAlIl == Ш!1Х Lj'=l laijl (i == 1,2, ..., п); п == 5. t 19. В матрице А размера п х п замените нулями все элементы, Ha ходящиеся ниже диаrоналей; п == 5. 20. Матрица А размера п х п называется сu.м.меmрu'Чес'К:оi1, если транспонированная матрица А т равна исходной А (заменив в А 
159 строки соответственно столбцами, получим матрицу А Т ). Выясни те вид матрицы А; п == 5. 21. Получите таблицу Пифаrора (Pythagor)  матрицу A==(aij), rде aij == i х j (i, j == О, 1, . . ., п). Протранспонируйте ее (замените строки соответственно столбцами и наоборот). Найдите следы матриц А и А Т (следом матрицы А называется число Tr(A), равное сумме эле ментов rлавной диаrонали); п == 9. 22. Матрица A==(aik) (i,k==l, 2, ..., п) называется орmО201tаЛ'Ь1tоl1, если АА Т == А Т А == Е, r д е ( А о 1  .  .. 0 1 т ) р . анспонированная матрица А, Е  единичная матрица Выясните вид матрицы А; n == 5. 23. Из матрицы А == (aij) (i,j == 1,2, ..., п) получите вектор, co стоящий из средних квадратических значений элементов нечетных столбцов исходной матрицы; п == 5. 24. В матрице А == (aij) (i == 1,2, . . ., п; j == 1,2,3,4) элементы каждой строки представляют собой длины сторон четырехуrольника, впи caHHoro в окружность. Найдите четырехуrольник наименьшей пло щади; п == 5. 25. Пронормируйте матрицу А == (aik) (i, k == 1, 2, ..., п) по ее BTO рой норме, т. е. получите матрицу В == (b ik ), rдe b ik == aik/IIAI12' IIAII2 == mt x 2::7=1 laikl (k== 1, 2, ..., п); п == 5. 26. В матрице А == (aij) (i,j == 1,2, ..., т) элементы, лежащие выше и ниже диаrоналей, замените единицами, а отрицательные элемен ты, расположенные левее и правее диаrоналей,  нулями; m == 5. 27. В матрице А == (aik) (i == 1,2, ..., т; k== 1,2, ..., п) найдите cтpo ку, сумма элементов которой максимальна. В ней разыщите мини мальный элемент. Подсчитайте произведение элементов Toro столб ца матрицы, которому принадлежит этот элемент; m == 6, п == 4. 28. В матрице А == (ai}) (i,j == 1,2, ..., п) каждый элемент равен единице, двойке, тройке или четверке. Подсчитайте количество че тверок aij, ai,j+1, ai+1,j, ai+1,j+1, в каждой из которых все элементы различны; п == 6. 29. Матрица А == (aik) (i, k == 1, 2, ..., п) состоит из целочисленных 
160 элементов. Получите вектор Ь == (b i ) (i == 1,2, ..., п), каждый эле мент KOToporo есть количество различных чисел в строках матрицы А; п == 5. 30. Сформируйте матрицу А размера п х п из чисел от п 2 до 1, pac положив их по спирали. Обход начните с правоrо нижнеrо уrла в направлении против часовой стрелки; п == 5. Цепная дробь Пусть ао, al, ..., а n , ..., Ь о , b 1 , ..., Ь n , ...  две последователь ности, элементы которых суть действительные (или комплексные) числа или функции одной (или нескольких) переменных. Выраже ние вида ао + Ь 2 аl + Ь З а2 + аз +... Ь 1 Ь 1 Ь 2 Ь З ==ao+ аl + а2 + аз + называется 'Цепной или непрерывной дробью, отвечающей заданным последовательностям ak (k==O, 1, ...) и b k (k==1, 2, ...). При этом дроби Ь 1 ао+ , аl .. -, ао + Ь 2 аl + Ь N а2 + . . . +  а n Ь 1 Ь 1 ао + Ь 2 ' аl +  а2 именуются соответственно первой, второй, ..., п й подходящей дробью для данной бесконечной дроби. Их обозначение  P1/Ql, P 2 /Q2, .. ., Pn/Qn. Если существует конечный предел А подходящей дроби Pn/Qn при п -------+ 00, то цепная дробь сходится. Число А при нимают за значение цепной дроби. Для числителей и знаменателей подходящих дробей нетрудно вывести рекуррентные формулы Рn ==, anPnl + ЬnPn2, Qn == anQnl + bnQn2, п Е N, rде РО == ао, Pl == 1, Qo == 1 и Ql == О. При работе на компьюте ре пю подходящую дробь удобно находить посредством следующей последовательности действий: 
161 Cl == Ь n / а n , c2==bn1/dl, d 1 == anl + Cl, d 2 == an2 + С2, Ck == bnk+l / dkl, d k == ank + Ck, (*) Сп == b 1 / dn 1 , d n == ао + Сп == Pn/Qn. Указанные формулы леrко проrраммируются. Цепные дроби обладают мноrими замечательными свойствами [63, 64]. В частности, разложения некоторых функций в цепные дроби сходятся быстрее, чем соответствующие разложения в степенные ряды, и поэтому дроби весьма полезны в приложениях (в теории колебаний, в теории упруrости, в электротехнике и т. п.). При этом за приближенное значение сходящейся цепной дроби берут подходя щую дробь Pn/Qn. Применим аппарат цепных дробей в задаче вычисления экспонен ты [66]: для значений /хl  709.7827 и п == l(п к )1 вычислим е Х , исполь зуя разложение показательной функции в цепную дробь: е Х == (у + х)/(у  х), х 2 х 2 х 2 rде у == 2 +    6 + 10 + 14 + х 2 + 4п + 2 + Пусть х == 1, п к == 7. Решение таково. Чтобы лучше представить необходимые действия, запишем цепную дробь в развернутом виде х 2 у=2+ х 2 6+ х 2 10 + 2 х 14 +... + 4п + 2 + . . . Не будем использовать формулы (*). Проще вычисление пй ПОk ходящей дроби выполнять посредством арифметическоrо цикла, "идуще20 снизу вверх". Для двух последовательных звеньев подхо дящей дроби нетрудно написать рекуррентную формулу, позволяю щую найти ke звено через предыдущее, (k 1 )e. В данной задаче 
162 справедливо следующее рекуррентное соотношение: Y4k2(X) == 4k  2 + X 2 /Y4k+2(X) (k==n, n  1, ..., 1), rдe 4k  2Ik=n== 4n  2, Y4k+2(X) Ik=n== 4n + 2. Теперь построим функциональную схему. Она будет состоять из двух алrоритмов  rоловноrо с именем Cfrac (от continuous fraction  непрерывная дробь) и подчиненноrо с именем Ехроn (от exponential  экспоненциальный). В rоловном алrоритме после объ явления переменных, задания значений х, n к и эхопроверки ис ходных данных орrанизуем цикл перебора целочисленных значений n == 1(nк)1. В теле цикла обратимся к Ехроn, выведем результаты (в виде таблицы из двух колонок, содержащих текущие значения n и е Х ), а затем посредством стандартной функции языка проrрамми рования проконтролируем вычисления. В подчиненном алrоритме, который спроектируем как функцию с двумя параметрами (алrо ритм двточн Ехроn (двточн х, цел n)), после объявления BHYTpeH них переменных выясним, принадлежит ли значение х области опре деления этой функции. Если х Е D и при этом х =1- о, то подrотовим цикл по переменной k == n(1)( 1), а затем внутри Hero найдем зна чения У и е Х . При нулевом aprYMeHTe ответом будет единица. Если х rj:. D, то выведем сообщение об ошибке в значении х и завершим работу. Тем самым окажется, что алrоритм Ехроn, находящийся на втором уровне иерархии, принимает "rлобальное" решение за алrо ритм более BbIcoKoro уровня. Разрешим ему это сделать, так как Ехроn  алrоритм MaccoBoro пользования, вычисляющий значение элементарной функции анализа. Обозначим через Уприбл  значение подходящей дроби. В этой задаче в силу ее простоты достаточно двух проходов для каждоrо алrорит ма. Стадии детализации rоловноrо алrоритма таковы: алrоритм Cfrac алr двточн Ехроn объявить переменные начало { двточн Х, Уприбл цел n к , n 
задать данные вычислить и вывести значение е Х 163 { ввести значения х и п к вывести заrоловок задачи х, п к и заrоловок результатов для п от 1 ДО п к шаr 1 выполнять Уприбл f-o---Expon(x, п) вывести значения п и Уприбл конеццикл /* по п *1 контролировать зна { вывести заrоловок и значение ех р( х ) чение е Х конец /* rоловноrо алrоритма */ При детализации работы подчиненноrо алrоритма сделаны следую щие два шаrа: цел п) алrоритм двточн Ехроn (ДВТОЧЦ х, знач х, п цел k объявить друrие пере менные начало выяснить величину х подrотовить цикл под счета дроби вычислить значение экспоненты { двточн t, У цел п4, т если Ix\  709.7827 то если х i= о то { t f-o--- Х Х Х п4 f-o--- 4 х п т f-o--- п4  2 у f-o--- п4 + 2 для k от п ДО 1 шаr  1 выпол нять у f-o--- т + t/y т f-o---т4 конеццикл /* по k *1 Ехроn f-o--- (у + х)/(у  х) возвратиться 
164 вычислить е О иначе Ехроn +----- 1 возвратиться конецесли иначе вывести сообщение об ошибке /* х Е D *1 обработать аварийную ситуацию стоп конецесли /* х rt. D */ конец /* алr Ехроn *1 Теперь спланируем тестирование. Испытания в нормальных услови ях проведем при х == 1 (е == 2.718281828459045 . . .), в экстремальных  при х == О, х == ::1:709.7827 =f Б, rде Б  малая величина, и в исключи тельных ситуациях  при Jxl == 1000. Подrотовим данные. Исходные числа  значения переменных х == 1 и n к == 7. "Картинка" выводных данных может быть такой: u==================================== uЦепнаяuдробьuдляuэкспонентыuехр. uuuuИсходныеuданные: uX=ul.000000000000000e+OOuuuuNK=uuu7 u uuuuOTBeT: uuuNuuuuuuExpon(x) uuu7uu2.718281828459045 uuuuuuuuexp(x)uKOHTP, uuuuuu2.718281828459045 u==================================== Наконец приступим к написанию проrрамм. Подберем переменным имена: назовем х, Уприбл, n к , n, k, t, У, n4, т соответственно Х, Yappr, Nk, N, К, Т, У, N 4 и М. П porpaMMbI были успешно выполнены на компьютере. В заключение отметим, что цепные дроби можно "сворачивать" не только в направлении снизу вверх, но и сверху вниз, что будет чрез вычайно полезно в вычислениях с точностью € (тоrда экономится 
165 время вычислений, так как от этапа к этапу добавляется по одному звену). В нашем случае имеем подходящие дроби (см. последова тельность действий (*)) РО == 2 Р 1 == 2 х 2 == 12+х2 Qo ' Ql + 6 6 Р 2  2  120+ 12х2 Q2  + x2 60+х 2 ,... 6+ 10 и следующие рекуррентные формулы: P k == (4k + 2) х Pkl + х 2 Х Pk2, rде РО == 2, Pl == 1, Qk == (4k + 2) х Qkl + х 2 Х Qk2, rде Qo == 1, Ql == о. Обозначим 4k+2 коротко т, P k  р, Pkl И РО  r, Pk2 и Pl  S, Qk  q, Qkl И Qo  и, Qk2 И Ql  V, х 2  t. Получим моди фицированный алrоритм вычисления экспоненты, который назовем Exponent: алrоритм ДВТОЧН Exponent (ДВТОЧН х, цел n) знач х, n цел т, k ДВТОЧН r, s, и, v, t, р, q, У начало если Jxl  709.7827 то если х =1= о то m f--------6 r f--------2 Sf--------1 Uf--------1 Vf--------O t f-------- х 2 для k от 1 ДО n шаr 1 выполнять р f--------mxr+txs qf--------mxu+txv s f--------r rf--------p Vf--------U Uf--------q m f--------m+4 конеццикл /* по k */ у f-------- p/q Ехроn f-------- (у + х)/(у  х) возвратиться иначе Ехроn f-------- 1 возвратиться 
166 конецесли иначе вывести сообщение об ошибке стоп конецесли конец Замечание Средства языков, необходимые при проrраммировании цепных дробей, изложены в 2лаве 8. Алrоритм преобразования десятичноro числа Х в цепную дробь: BЫ делите целую Часть Х, а затем  целые части Xi == l/(Xil  [Xil]) (i==1,2,...,n). . /* Х Е D *1 /* Х rt D */ /* алr Exponent *1 Упражнения Следующие далее числа представьте в виде цепных дробей. Исполь зуйте подчиненный алrоритм. 31. 0.785398163397 36. 22/7 41. (J5+1)/2 32. 1.57079632679 37. J2 42. arcsin 0.5 33. 3.14159265359 38. v3 43. arccos 0.5 34. 6.28318530718 39. tg 1 44. arctg 1 35. 0.577215664902 40. ln2 45. ехр 1 Упражнения Для значений Х == Xo(xK)h постройте таблицу функции. KOHTpO лируйте D(J) и результат. Удержите 21 звено (направление "снизу вверх"); с точностью € == 1015 (направление "сверху вниз"). Исполь зуйте подчиненный алrоритм (см. замечание к упр. 1 зо ранее в этой rлаве). 111 1 46.q== , q==(J51)/2. 1+1+1+1+... 47. Формула Броункера (Brouncker): 4 12 32 52 (2n  1)2 7r= 1+2+2+2+...+ 2+ 
167 4 12 22 п 2 48. 7r ==    1 + 3 + 5 + ... + 2п + 1 + ... 49. Формула Рамануджана (Ramanujan):  00 1 1 1 2 3 4 V "2 == kl (2k  1)!! + 1 + 1 + 1 + 1 + 1 + .... xl xl xl xl 50. vx == 1 +     х  О. 2 + 2 + 2 + 2+ 1 2х х 2 х 2 51. ехрх ==  2 ' 'х!  88.72. 1  + х + 6 + ... + 2(2п + 1) + ... х х х х х 52. ехрх == 1 +     , Ixl  88.72. 1  2 + 3  ...  2 + 2п + 1  ... 1 х х х х х 53.expx==  , Ixl88.72. 1  1 + 2  3 + ... + 2  2п + 1 + ... 1 х х пх 54. ехрх ==  1 2 ' !хl  88.72. 1 +x +x...п+1+x... 1 1 + х х х 2 4х 2 п 2 х 2 55.ln== , I x l <l 2 1  х 1  3  5  ...  2п + 1  ... . 56. Формула Ламберта (Lambert): х х 2 х 2 х 2 7r tgx , Ixl.  1  3  5  .,.  2п + 1  ... 4 . х/ у 1  х 2 х 2 /(1  х 2 ) п 2 х 2 /(1  х 2 ) 57. аrсsш х == , Ixl < 1. 1 + 3 + . . . + 2п + 1 + у 1  х 2 1  х 2 п 2 (1  х 2 ) 58. arccos х == , Ixl  1, х =f О. х + 3х + '" + (2п + l)х + ... 59. Формула Ламберта (Lambert): х х 2 4х 2 п 2 х 2 arctgx== , Ixll. 1 + 3 + 5 + ... + 2п + 1 + ... х х 2 (2п  1)2х 2 60. arctgx== 2 () 2 ' Ixll. 1 + 3  х + ... + 2п + 1  2п  1 х + ... / 1 х х х х х 61.eX==1   , Ixl709.78. 1  1 + 2  3 + .,. + 2  2п + 1 + ... 
168 х х х 62.1n(x+ 1) == х+ 1  2  3(х+ 1)  пх пх х >  1.  2  (2п + 1)( х + 1)  ...' х х х пх пх х >  1. 63. ln( х + 1) == 1 + 2 + 3 + ... + 2 + 2п + 1 + ...' х х(х+1) п 2 х(х+1) , x>l. 64. ln(x + 1) == х+1  3х+2  ...  (2п+1)х+п+1  '" 2 Х Х пх l<x<l. 65.1n(x+1)== 1 + 2x+ ... + п+1пx+ ...' 2 п2х2 2х х 66.1n(x+1)==2+x  3(2+х) ...  (2п+1)(2+х)  ( 1 1 1 п п ) oo < х < О. 67. Ei(x) == е Х х  1  х  ..,  1  х  ... ' х 1 1 п п 68. li( х) == ln х  1  ln х  ...  1  ln х  х х х х О ::;; х ::;; 1; 69. J( х) == 1 + 3 + 5 + 7 + ... + 2п + 1 + ...' 2х х J( x2) 2  J( x2)+x2 . 2 cos х  2 ( 2 ) 2 ' s1П х== J2(x2)x2' f x x / х х 2 х 2 х 2 70. ctg х == 1 1  3  5  ...  2п + 1  ...' 7r V'1x2 1x2 п2px2) Ixl::;;l,x::j:O. 71.arcsinx==2" х+ 3х+ ... + (2п+1)х+ ...' 7r x/V1=X2 х 2 /(1 x2) п 2 х 2 /и x2) , 'хl < 1. 72. arccos х ==:2  1 + 3 + . . . + 2п+ 1 + x>l. , о < х < 1. Лх 2 )+х е 2Х == . Лх2)х 7r 'хl ::;; , х =1= О. 4 7r Х х 2 9х 2 73. arcctg х == 2"  1 + 3  х 2 + 5  3х2 + ... + ( 2п1 ) 2x2 , Ixl::;; 1. + 2п+1(2п1)x2+ ... 1 тх (1  т)х 74. (1 + х)т == 1  1 + тх + 2  (1  т)х + ... + 
169 п(пт)x + п + 1  (п  т)х + тх ( 1+т)х 75. (1 + х)т == 1 + 1  тх + 2  (1 + т)х + ... + п(п + т)х +п+1(п+т)x+ Ixl  1, т == 1/3. 'хl  1, т == 1/3. Арифметика Арифметика лежит в основе компьютерных наук. Изложению ал roритмов арифметики Д. Кнут в своей книrе "Искусство проrрам мирования для ЭВМ" (т. 2) отвел более полутысячи страниц. Здесь он анализирует алrоритмы выполнения четырех основных действий арифметики над различными данными (слишком малыми и слиш КОМ большими числами, дробями, полиномами, степенными ряда ми), обсуждает вопросы перевода чисел из одной системы счисления в друrую, разложения чисел на множители, вычисления полиномов и т. д. Решим задачу нахождения наибольшеrо общеrо делителя двух цe лых чисел а и Ь: gcd(a, Ь), или нод(а, Ь). Эта функция применяется в алrоритмах rенерации случайных чисел, при обработке длинных цe лых чисел (чисел типа длинцел ), быстром умножении целых чисел и т. д. Заодно познакомимся с новой формой описания алrоритмов и с тем, как использовать опубликованный алrоритм. Решение заключается в следующем. Наибольший общий делитель найдем с помощью алrоритма Евклида. В современной редакции он выrлядит так [31]: Алrоритм Е. (АЛ20рuт.м Евх:лuда.) По заданнЫМ числам и, v Е Zo этот алrоритм находит нод. (За.ме'Ч,анuе: нод произвольных целых чисел а и Ь можно, ввиду соотношений нод(О, О) == О, нод( а, Ь) == = нод(Ь,а), Hoд(a,b)==Hoд(a,b), нод(а,О)==!аl, получить, применяя алrоритм к u == 'аl и v== Ibl.) Еl. [v == О?] Если v == О, то исполнение алrоритма заканчивается; результатом работы будет и. 
170 Е2. [Взять u mod v.] Установить r +---- U mod v, u +---- v, V +---- r и воз вратиться к шаrу Еl. (В результате выполняемых на этом шаrе операций значение v уменьшается, а значение нод( и, v) остается без изменения.) I Приведенный образец описания алrоритма Евклида принадлежит Д. Кнуту. В этом способе представления алI'ОРИТМ снабжается опо знавательной буквой (например, буквой Е). Шаrи алrоритма обозна чаются этой же буквой, за которой указывается номер шаrа (напри мер, Еl, Е2). Каждый шаr начинается с фразы в квадратных скоб ках, кратко информирующей о содержании шаrа. За этой фразой следует словесное и символьное описание действий, которые нужно исполнить на данном шаrе. Возможны дополнительные сведения о шаrе  комментарий, т. е. текст, заключенный в круrлые скобки (Ha пример, последнее предложение на шаrе Е2). Здесь, как и раньше, символ +---- представляет операцию замены, символ =  операцию сравнения, а символ I  конец алrоритма. Проект проrраммы решения сформулированной выше задачи будет состоять из двух алrоритмов  rоловноrо с именем А rithmetic и под чиненноrо  функции Euclid. Распределение обязанностей между ними таково: ввод целых чисел а и Ь, заказ на вычисление нод(а, Ь) и вывод результата  эту работу проделает алrоритм Arithmetic; BЫ полнение заказа  это работа алrоритма Euclid. Ero параметры  длинные целые переменныезначения а и Ь. В rоловном алrоритме сначала объявим константы line и double line (они предназначены для вывода линии и двойной линии), перемен ные (длинцел а, Ь, gcd сим в ch, причем значением ch должен быть либо символ у, либо любой друrой символ, например, п) и выведем заrоловок задачи. Затем спланируем обработку вводноrо набора дaH ных неопределенной длины, для чеrо построим бесконечный цикл пока (см. разд. 11 Повторение" 2лавы 3). В ero теле выведем линию и подсказку, введем текущую пару значений а и Ь, найдем нод( а, Ь) и выведем результат. Потом ответим на вопрос: завершить работу (набрать у; от yes  да) или продолжить обработку очередной па ры а и Ь (набрать п; от по  нет). В заключение выведем двойную линию и концевую фразу 11 Все...". Проект rоловноrо алrоритма в записи псевдокодом rOToB: 
171 алrоритм А rithтetic алr длинцел Euclid конст line' , double line , ==============================================' длинцел а, Ь, gcd симв ch начало вывести double line, , uНод. uuАлrоритмuЕвклида.' пока истина выполнять вывести line, 'uuuuдлинцелuа,uЬ u == == ==>' ввести а, Ь gcd  Euclid(a, Ь) , ( '" Ь ' ) ' d вывести uнод , а, " , ==, ус , , uЗавершитьuработу: uuуuилиun' ввести ch если ch == 'у' то конеццикл вывести double line, 'uuuuBce... ' прервать конецесли /* ео обработки а и Ь */ конец /* ео. rолов алr *1 Теперь займемся подчиненным алrоритмом. Наличие алrоритма EB клида в форме Д. Кнута максимально упрощает процесс проектиро вания алrоритмафункции Euclid. В ней сначала объявим перемен ные (длинцел и, v, т), потом найдем модули параметровзначений (и  lal, v  Ibl) и откроем цикл, который будет выполняться, пока значение переменной v отлично от ну ля. В теле цикла работают три команды (т  u mod v, u  v, 1)  т). в концевой части алrоритма имени функции назначим результирующее значение и возвратим ero и управление в точку вызова. Приведем проект подчиненноrо алrоритма: алr длинцел Еuсlid(длинцел а, Ь) знач а, Ь длинцел и, v, r начало u  lal v  'ы 
172 пока v =1 О выполнять r f------- u mod v u f------- V V f------- r конеццикл /* ео подсчета нод */ Euclid f------- U возвратиться конец /* ео алr Euclid */ Для проверки правильности проекта и будущей проrраммы возьмем несколько пар чисел а и Ь и (вручную) подсчитаем их нод. Полу чим следующие контрольные точки: нод(51, 17) == 3, нод(17, 51) == 3, нод(51,51) == 51, нод(О, О) == О, нод( 51, О) = 51, нод(О, 51) == 51, нод(2, 214748З646) == 2. Прокрутка алrоритмов для тестовых дaH ных подтвердила правильность проекта. Коrда U и V равномерно распределены на отрезке [1; п], алrоритм Euclid выполняется при близительно за [16.021n п + 6.14] циклов. Теперь представим "картинку" выводных данных: u======================================== uНод.uuАлrоритмuЕвклида.  u uнод(uuuuuuuuu51,uuuuuuuuu17)=uuuuuuuuuu3  u u....................................... .  u uнод(uuuuuuuuuu2,2147483646)=uuuuuuuuuu2 u======================================== uuuu Bce . . . Перейдем к кодированию. Составим табличку переобозначений: име на line, double line, а, Ь, gcd, ch, и, и, r заменим соответственно име нами Оnе, Two, А, В, Gcd, Ch, и, V, Н. Проrраммы были успешно выполнены на компьютере. Результаты решения совпали с TeCTOBЫ ми данными. В заключение сделаем следующие замечания: C:J типу длинцел в Паскале соответствует тип longint, в Си  long и integer  в Фортране (см. 2лаву 5); C:J при компьютерной реализации проrраммы MorYT потребоваться 
173 команды очистить экран и задержать(п), [де п  число МИk лисекунд; О в алrоритме А rithmetic можно отказаться от символьной пере менной ch, но тоrда придется определить фу1t1С'ЦИЮ конец фаИ ла (eof  в Паскале и Фортране, СеоС  в Си), убрать объявле ние симв ch и команду ввести ch, условие ch == 'у' заменить на конец фаИла, а при завершении работы вместо набора чисел а и Ь нажать комбинацию клавиш (Ctrl)+(z). О В некоторых задачах, приведенных далее, потребуются: . алrоритм деления числа Х на число у с произвольной точно стью [19]. Он может быть таким: выделим и выведем целую часть дроби х/у, т. е. получим т == [x/yJ, положим хо == х, а затем используем рекуррентную формулу Xj == 10(Xj1  ту) и в цикле по пере мен ной i выводим значения т == (Xi/Y] (i==l, 2, ..., п). . алrоритм выделения zro разряда целоrо числа т: k == 10i\ d == [т/ k]  10[m/(10k)J. . алrоритм расшифровки цифр целоrо числа [60J. Последний рассмотрим на следующем примере: выясним, какую цифру обозначает каждая буква в выражении ох + ах еех Приступим к решению примера. Сначала напомним, что целое число можно представить в виде anan1 .., ао == а n 10 n + an110n1 + '" + а2102 + а}10 + ао, rдe ai (i==O, 1, ..., п)  цифры 0,1, ...,9 (а n #- О). Решаемая задача проста. Она относится к классу переборных задач. Так как о, а, е  начальные цифры чисел, то они будут прини мать значения 1(9)1, а цифра Х  значения 0(9)1. При этом имеем ох == о х 10 + х, ах == а х 10 + х, еех == е х 102 + е х 10 + х и должно выполняться равенство ох + ах == еех. Перебор цифр орrанизуем с помощью четырех вложенных циклов для. Общее количество вари 
174 антов перебора невелико. Оно равно 9 х 9 х 10 х 9 == 7290. Это число можно уменьшить: из условия задачи следует, что единственно воз можными значениями е должна быть единица, а х  ноль. Новое число вариантов равно 9 х 9 == 81. Алrоритм расшифровки цифр (назовем ero Decode) запишем в виде алrоритм Decode длинцел о, а, е, х начало е +---- 1 х +---- О для О от 1 до 9 шаr 1 выполнять для а от 1 до 9 шаr 1 выполнять если о+а == 11 то вывести' 0==', о,' а==', а,' е==', е,' х==', х конецесли конеццикл конеццикл вывести ' Все. " ' /* п о а */ /* по о *1 конец /* алr Decode */ Ответом задачи будут следующие 8 вариантов: о == 2(9)1, COOTBeT ственно а == 9(2)(  1); при этом все е == 1 и х == О. Упражнения 76. Напишите Проrрамму с процедурой Easter (или Passover), вычисляющей дату пасхальноrо воскресенья для заданноrо rода, предполаrая rод меньше, чем 100000. Ответ представьте в форме dd.тт.yyyyy, rдe dd  день, тт  месяц и ууууу  rод. Исполь зуйте алrоритм неаполитанскоrо астронома Алоизиуса Лилиуса и repMaHcKoro математика Кристофера Клавиуса, живших в ХУI Be ке. Католическая церковь применяет ero с 1582 rода [31]. Вот текст этоrо алrоритма: Алrоритм Р. (Дата пасхи.) Пусть У  rод, для KOToporo вычи сляется дата пасхи. Рl. [Золотое число.] G +---- (Ymod 19) + 1. (С  так называемое золотое 'Число в 19летнем цикле.) 
175 Р2. [Век.] С  lY/100j + 1. (Если У не кратен 100, то С  номер века; например, 1994  [од XXro века.) Р3. [Поправки.] Х  l3C/4j  12, Z  l(8C + 5)/25j  5. (По правка Х учитывает високосные [оды, такие, как 1900, коrда не прибавляется дополнительный день; Z  специальная по правка для синхронизации дня пасхи с лунной орбитой.) Р4. [Определить воскресенье.] D  l5Y/4J  Х  10. [В марте (( п) rnod 7)e будет воскресеньем.] Р5. [Эпакта.] Е  (l1G + 20 + z  Х) rnod 30. Если Е = 25 и золотое число G > 11 или если Е = 24, то Е следует YBe личить на 1. (Е  так называемая "эпакта"; она указывает дату, коrда наступает полнолуние.) Р6. [Найти полнолуние.] N  44E. Если N < 21, то N  N +30. (Считают, что пасха  это "первое воскресенье после перво [о полнолуния, наступившеrо не ранее 21 марта". На самом деле, изза возмущений лунной орбиты, это не совсем верно, но здесь речь идет о "календарной луне", а не о фактической луне. Ne марта является днем календарноrо полнолуния.) Р7. [Перейти к воскресенью.] N  N + 7  ((п + N) rnod 7). Р8. [Определить месяц.] Если N>31, то дата пасхи  (N31)e апреля; в противном случае искомой датой будет Ne марта.. 77. Решите "Задачу Иосифа" [31]. По Kpyry расположены п чело век. Начиная с kй позиции, считаем по Kpyry в напралении дви жения часовой стрелки и удаляем каждоrо тro человека. Коrда человек удален, Kpyr смыкается. Выведите порядок удаления. Ал rоритм Joseph должен быть эффективен (в частности, для больших n и т ); п = 24, k = 5 и т = 11. Примечание Решите сформулированные ниже задачи обработки целых данных, используя подчиненные алrоритмы (результат один  функцию, несколько выходных данных  процедуру). Подберите (при необ ходимости) исходные данные самостоятельно. 78. Найдите все простые (sirnple) числа, используя "решето Эрато сфена". В этом алrоритме начинают с 2 и из массива данных исклю чают все числа, кратные 2; затем также поступают с 3 и т. д. Послед нее простое число Pk удовлетворяет неравенству Pk  п; п  777. 
176 79. Подсчитайте "'Частоту" (frecuency) каждоrо делителя числа n. 80. Проверьте rипотезу rольдбаха (Goldbach) для чисел, не превос ходящих т: любое четное число можно представить в виде суммы двух простых чисел; т == 222. 81. парныlии (twin) nростыlии числами называются два простых чи сла, разность которых равна 2 (например, 3 и 5). Найдите k пар пар ных простых чисел; k == 13. 82. Совершенным (perfect) называется число, равное сумме своих делителей, включая 1. Найдите все совершенные числа, принадле жащие промежутку [а; Ь]; а == 3, Ь == 3333. 83. Число Мерсенна (Mersenne)  это простое число, представимое в виде 2P 1, rде р  также простое число. Разработайте эффективный алrоритм построения последовательности чисел Мерсенна; р:::; 31. 84. Найдите обратные целых чисел от 2 до 50 со 100 значащими цифрами. Можно, например, поступать так ([19]). Число 10 000 дe лят на n. Частное q даст первые четыре цифры результата. Затем остаток r умножают на 1 О 000 и получившееся число снова делят на n. Новое частное даст следующие четыре цифры результата и т. д. (например, при n == 21 имеем 1 х 10000/21 == 0476, r == 4; 4 х 10000/21 == 1904, r == 16 и т. д., откуда 1/21 == 0.04761904.. .). 85. Вычислите 100 первых десятичних разрядов числа е  1 + + L:k=!l/k!, n == 50 ([19]). 86. Вычислите 2 n ; n == 128 ([19, 60]). 87. Подсчитайте частичные суммы числовоrо ряда 7r == 44/3+4/5 4/7 +. . .:::1: 4/ (2k  1) 1=. . . . Результаты представьте рациональными дробями!; k == 555. 88. Число из k цифр называется 'Числом Армстронса (Armstrong), если сумма цифр, возведенных в kстепень, равна самому числу (на- пример, 153 == 13+53+33). Найдите все числа ApMcTpoHra, состоящие из 2, 3 и 4-х цифр. 89. Определите период десятичной дроби т/n, rде т и n  нату- ральные числа (например, периодом 23/18 будет 7, а если дробь ко- нечная, то ее период состоит из одной цифры о; см. [9]). lСМ. fporOHO П. Проrраммирование на языке Паскаль.  М.: Мир, 1982.  384 с. 
177 90. Найдите натуральные числа ml и nl, не имеющие общих делите лей, и такие, что ml/nl == т/n, rде m и n  заданные натуральные числа. 91. При заданном n Е N определите наименьшее число с, которое можно представить в виде суммы а n + Ь n , по крайней мере, двумя различными способами; (а, Ь) Е N. 92. Найдите все пары двузначных натуральных чисел m и n таких, что произведение m х n не изменится, если поменять местами цифры каждоrо из сомножителей. 93. Найдите все натуральные числа, не превосходящие n и делящи еея на каждую из своих цифр. 94. Натуральное число n можно представить в виде суммы ero сла raeMbIx, называемых разбие'Н,иями (break ир) (например, 3 можно за писать как 3,2 + 1 и 1 + 1 + 1; здесь количество разбиений Р(3) == 3). Для числа n найдите все разбиения и их количество Р(n). 95. Два числа называются дружестве'Н,'Н,ыми (friendly), если каждое из них равно сумме всех делителей друrоrо, кроме caMoro этоrо чи ела (например, 220 и 284  дружественные числа, ибо 1 + 2 + 4 + + 71 + 142 == 220 и 1 + 2 + 4 + 5 + 10 + 11 + 20 + 22 + 44 + 55 + 110 == 284). Найдите несколько дружественных чисел. 96. Сформируйте одномерный массив, элементы KOToporo  ше стизначные числа, не содержащие в своей записи двух одинаковых цифр. 97. Определите множество рациональных корней уравнения n . L aiXn1 == о, ai Е Z, ао =1- о, а n =1- о. i=O Эти корни следует искать среди чисел вида p/q, rдe р и q  всевоз- можные делители соответственно коэффициентов а n и аО и при этом выполнено условие t aipniqi == о; х == {х 14х4 + 8х З  зх 2  7х + 3 == о, х Е Q}. i=O 98. Определите несколько автоморФ'Н,ых 'Чисел  чисел, содержа щихся в последних разрядах их квадрата (например, 252 == 625). 99. Используя признак делимости на n, определите, делится ли m на n; n == 8, 11, 25. 
178 100. Найдите сумму kзначноrо числа m с числом n, полученным из первоrо перестановкой ero цифр в обратном порядке; k == 5,10. 101. Выведите в порядке возрастания первые k чисел, не имеющих простых делителей, кроме т, n и 1 (k == 44, m == 2, n == 3, 1 == 5; начало списка: 1, 2, 3, 4, 5, 6, 8, 9, 10, 12, ...). 102. Для заданных а, Ь, n Е N найдите все натуральные числа, не превосходящие n и представимые в виде суммы произвольноrо KO личества слаrаемых, каждое из которых есть а или Ь. 103. Найдите все натуральные числа, не превосходящие заданноrо значения n, десятцчная запись которых есть неубывающая или He -возрастающая последовательность цифр. 104. Определите, можно ли заданное натуральное число представить как сумму кубов трех натуральных чисел. 105. В заданной коллекции натуральных чисел замените все четные числа на такие четные числа, каждое из которых получается из ис ходноrо записью ero цифр в обратном порядке. 106. Среди простых чисел, не превосходящих n, найдите такие чис ла, в двоичной записи которых содержится максимальное количе ство единиц. 107. Студент Трехчлен задумал несколько натуральных чисел ml, т2, ..., т n . Профессор Матрица задал два вопроса и отrадал их. Сначала он попросил студента найти сумму чисел 51 == 2:k=1 mk, а затем, зная 51,  сумму 52 == 2:k=1 mk10(kl)p, rде Р  такое, что 51 < 1 ОР . Замечание Любое конечное количество натуральных чисел можно хранить в виде одноrо мноrозначноrо числа. Сортировка Сортировка  классическая задача проrраммирования. Она явля- ется составной частью процессов обработки данных. Под сортиров- кой понимают процесс размещения элементов некоторой коллек ции (массива, файла) в числовом или лексикоrрафическом порядке. 
179 Цель сортировки  облеrчить поиск некоторых элементов. У поря доченные объекты нужны везде, rде их приходится разыскивать  в справочноинформационных системах, автоматизированнных си стемах продажи билетов и службах проrноза поrоды, телефонных и налоrовых книrах, библиотеках (каталоrах, книrах, журналах  в оrлавлениях, библиоrрафии и предметных указателях), отделах кадров и складских помещениях и т. п. Коrда элементы отсортиро ваны, их не только леrче найти, но и проще обновить, включить, исключить или "слить" воедино, проще обнаружить пропущенные или равные, или непроверенные элементы и пр. Сортировки делятся на два класса: сортирО6'К:а масси606 и copти рО6'К:а (nоследО6ателън'ых) фаi1ЛО6. Их часто называют COOTBeTCTBeH но 6HyтpeHHei1 и 6нешнеi1 сортирО6'К:ами, потому что массивы, как правило, хранятся в оперативной памяти компьютера (друrими сло вами, во внутренней памяти: для нее характерен быстрый и произ вольный доступ), а файлы размещаются на жестком диске, винче стере (во внешней памяти: на устройстве с механическим передви жением). Рассмотрим внутреннюю сортировку. Алrоритмы сортировки изло жены в книrах [13, 51, 31, 37, 32, 2, 18]. Методы сортировки Mac сивов делятся на две rруппы: nрост'ые и сложн'ые. Первые, пря мые или "квадратичные" методы, упорядочивают массив "на том же месте"; они коротки, леrки для понимаНИЯj требуют О(п 2 ) cpaB нений ключей, rде п  число сортируемых элементов; при малых n (п < 20) работают быстрее сложных. Вторые, улучшенные или "лоrарифмические" методы, требуют не больше О( п log2 п) cpaBHe ний и рекомендуются для больших значений п. Рассмотрим пример: решим задачу сортировки массива А == (ai)i=l по невозрастанию ero элементов. Приступим к решению задачи. Будем экономить память, поэтому упорядочение выполним на месте массива А. Попробуем сэкономить и количество операций (что, очевидно, крайне важно). Итак, начнем сортировку. Будем действовать так. Сначала сравним значения эле ментов аl и а2 и, если окажется, что аl меньше а2, поменяем их местами. Далее поступим точно так же со вторым и третьим эле ментами, затем с третьим и четвертым и т. д. В результате пер Boro просмотра Bcero массива (прохода по массиву) в ero конце, в 
180 области памяти а n , окажется наименьшее число (rоворят, элемент "всплыл"). Если при просмотре массива имела место хотя бы одна перестановка элементов, то повторим просмотр сначала. Тоrда преk последнее место в массиве займет число, непосредственно следую щее за наименьшим элементом. Перед каждым просмотром значение n уменьшаем на единицу. Это сократит количество сравнений и пере сылок. Сортировка закончится, коrда очередной просмотр массива не требует ни одной перестановки, т. е. все пары элементов Mac сива А сравнены и, возможно, переставлены. Факт хотя бы одноrо обмена будем реrистрировать с помощью признакафлажка  вспо моrательной переменной fiag, которая становится равной истина в случае перестановки в какойлибо паре; в противном случае ее зна чение есть ЛОЖЬ. Заметим, что каждый проход по массиву прИВОДИТ к "всплытию" элемента ("пузырька") на соответствующий ero зна чению (весу) уровень. Предложенный способ сортировки называют пУЗ'ЫРЪ1СО6'ЫМ. Метод решения выбран. Теперь приступим к проектированию. CHa чала распределим работу между алrоритмами. В функциональной схеме их два: в вершине управленческой пираМИДЫ, как всеrда, Ha ходится rоловной алrоритм (дадим ему имя СортиРО6'К'.а), а в OCHO вании  подчиненный с именем Bubble (т. е. пузырек). rоловной алrоритм объявит исходный массив А и вспомоrательные перемен ные, задаст фактическую длину масива n и сам массив А, выведет заrоловки и выполнит эхопроверку исходных данных, сделает заказ на сортировку (вызовет алrоритм Bubble (А, n)) и пожнет плоды (по лучит упорядоченный массив А, выведет заrоловок к нему и массив А). Два шаrа детализации rоловноrо алrоритма даны ниже: алrоритм СортиРО6'К'.а алr Bubble объявить данные { конст ел lim +---- 10000 цел n, l вещ массив A[l: lim] начало задать данные { ввести n, массив А вывести заrоловок задачи, n, А {вызвать Bubble (А, n) сортировать массив 
181 { вывести заrоловок ВЫХОДНЫХ данных и отсортированный массив А /* rол алr */ вывести результат конец Задача подчиненноrо алrоритма ВuЬЫе  рассортировать поступив ший к нему на ВХОД массив А длины n. Для этоro сначала проверим, не состоит ли этот массив из одноrо элемента. При n = 1 задача cop тировки уже решена; при n > 1 массив придется сортировать. Два шаrа детализации алrоритма ВuЬЫе имеют вид: алr ВuЬЫе (вещ массив A[l: lim], т) знач А, т рез А объявить данные начало если n > 1 то подrотовить сортировку начать сортировку подrотовить "всплытие" начать "всплытие" сравнить и переставить конец "всплытия" конец сортировки конецесли возвратиться { цел n, i лоr flag вещ r {;; :: истина { пока flag выполнять { flag +------ ложь n +------ n  1 { для i от 1 до n шаr 1 выпол нять если ai < ai+l то r +------ ai ai +------ ai+l ai+l +------ r flag +------ истина конецеслИ /* перестановки */ { конеццикл /* по i */ { конеццикл /* пока flag */ /* если n > 1 */ 
182 конец /* алr ВиЬЫе */ Поясним этот алrоритм. Цикл сортировки двукратный: внешний BЫ ясняет, коrда следует закончить проходы по массиву; внутренний занят обменом элементов. В заrоловке внешнеrо цикла проверяется значение признакафлажка fiag. Если оно есть JIОЖЬ, то сортировка закончена и тоrда надо вернуться в вызывающий алroритм; в про тивном случае (значение fiag равно истина) флажку назначается значение JIОЖЬ и работает внутренний цикл. Именно он упорядочи вает элементы и, если перестановка элементов имела место, BOCCTa навливает значение fiag, равное истина. Приступим к планированию тестирования. Если массив А = (1, 3, 2, 3, О, 2, 1) исходный, то результатом решения задачи должен быть отсортированный массив А = (3,2, 1, О, 1, 2, 3). Массив А = (aj) (i = 1,2, ...,7) из равных элементов (например, из нулей или единиц)  вот экстремальные значения в rраничных испытани ях. Массивы А = (аl) и А = aj (i = 1,2, ..., 10000)  еще один вид экстремальных данных для проверки rраничных объемов данных. Теперь представим "картинку" выводных данных: u=============================================== uСортировкаu(поuневозрастанию)uметодомuпузыръка. uuuuИсходныеuданные. u N =uuu 7 uИсходныйuмассивuА[N] : uuuuuuul.000uuuuuuЗ.ОООuuuuuu2.000 uuuuuuuЗ.ОООuuuuuuuОuuuuuuuuuuu2.000 uuuuuu1.000 u uuuuOTBeT. uОтсортированныйuмассивuА[N] : uuuuuuuЗ.ОООuuuuuuu2.000uuuuuuul.000 uuuuuuuOuuuuuuuuuu1.000uuuuuu2.000 uuuuuuЗ.ООО u=============================================== uuuu Bce .. . Наконец, перейдем к кодированию. Переменным lim, n, i, т, fiag и r дадим соответственно имена Lim, N, 1, М, Flag и R. Составленные 
183 проrраммы были успешно выполнены. Оценим алrоритм ВиЬЫе. Число сравнений в нем равно п(п 1)/2, а минимальное, среднее и максимальное количество пересылок co ответственно есть о, 3п( п  1) /4 и 3п( п  1) /2. Последние два числа велики даже для средних значений п. По этой причине пузырько вый алrоритм  наихудший из всех простых алrоритмов сортировки [13]. Однако он лаконичен и ясен, нетребователен к дополнительной памяти, необходимой для хранения промежуточных значений, и xo рошо подходит для разъяснения принципов упорядочения. Задачи сортировки очень распространены. Больше 25% времени pa боты всех компьютеров приходится на реализацию этоrо процес са, что придает особое значение выбору эффективных алrорит мов при заданных п (один из "законов проrраммирования" rласит: "Не улучшайте плохой алrоритм. Ищите, разрабатывайте хорошие алrоритмы." [1,2,3,8,9,13,14, 15, 18, 19,21,26,31,32,35,37,41, 45,51,53, 57, 60, 63, 64]). Упражнения Решите задачу внутренней сортировки (см. замечание к упр. 1  30 ранее в этой rлаве). Примените изложенные в [13, 31, 37, 32] сорти ровки: 108. простыми (прямыми) включениями; 109. бинарными включениями (методом деления пополам); 110. простым (прямым) выбором; 111. методом пузырька (см. [13], сс. 86 и 102); 112. простым (прямым) обменом (шейкер  сортировку) j 113. Д. Шелла; 114. пирамидальную; 115. разделением (быструю сортировку  нерекурсивная версия). Сравните их эффективность (в секундах). Пусть число сортируемых элементов п меняется по закону rеометрической проrрессии: пl == 2, q == 2, п13 == 8192. Исходный массив: О упорядочен по неубыванию; 
184 D упорядочен по невозрастанию; D случаен. Результаты сравнения сведите в таблицу. Статистические испытания Теперь познакомимся с методикой компьютерных вычислений, OCHO ванной на использовании случайных величин. Такие величины при сутствуют во мноrих приложениях. Назовем, к примеру, задачи фи зики (проникновение частиц через вещество), механики (продолжи тельность безотказной работы механизма), баллистики (координаты летящеrо объекта), MaccoBoro обслуживания (количество заказчи ков в очереди), передачи сообщений (помехи и сбои в коммуникаци онных системах), кинетики химических реакций, а также процессы функционирования различных сложных систем (производственных, экономических, банковских, биолоrических, эколоrических, проrно за, иrровых и т. д.). Эти задачи часто сложны. Решение их обычными методами либо затруднено, либо просто невозможно. Если же при влечь случайные числа и построить вероятностную модель явления, то их удается решить. При моделировании с использованием случайных чисел обычно применяется .метод МонтеJ(арло (название связано с "царством случая"  с именем rорода в княжестве Монако, известноrо CBO ими иrорными домами) [31,53]. Это, наверное, самый экстраrавант- ный численный метод. Как это ни пародоксально, но совершенно случайное помоrает в подсчетах cTporo определенноrо. Так метод МонтеКарло полезен при вычислении размеров rеометрических фи ryp. К примеру, найдем площадь криволинейной трапеции  фиrу ры, оrраниченной rрафиком функции J(x) и прямыми х == а, х == Ь, у==О. Рассмотрим прямоуrольник с вершинами (а,о), (a,h), (b,h) и (Ь,О), rдe h == supf(x), х Е [а;Ь]. Площадь TaKoro прямоуrольника есть 5 == h(b  а). Площадь под кривой f(x) на отрезке [а; Ь] можно представить произведением 5 Pj, rде Р!  некоторый коэффициент. Метод MOHTe Карло позволяет оценить значение Р! путем reHepa- ции большоrо количества случайных точек внутри прямоуrольника и вычисления процентной доли тех из них, которые попали в область ниже кривой f(x). Таким образом, площадь трапеции приближенно 
185 равна h(ba)p/n, rдe р  число случайных точек под кривой, n  заданное число испытаний. Метод MOHTe Карло чрезвычайно полезен и при решении "MHoroMe рных задач", например, при вычислении объемов сложных тел F в евклидовом пространстве четырех и более измерений. Речь идет о телах неправильной формы, задаваемых, например, системами Hepa венств. Предположим, что F есть подмножество MHoroMepHoro еди ничноrо куба С. Случайным образом выберем в С большое число TO чек n, которые с одинаковой вероятностью MorYT оказаться в любой части С. Подсчитав число точек р, попавших в F (они удовлетворя ют системе неравенств, определяющей Р), получим оценку объема Р, равную р/n. Заметим, что выборка из 100000 точек обеспечит точность около 0.1 % (если только объем не слишком близок к HY лю или единице), но и такой точности бывает иноrда достаточно, ибо добиться большеrо друrими методами либо невозможно, либо очень и очень трудно. Более Toro, часто такой путь решения луч ше, чем какиенибудь формульные ухищрения. Действительно, если при использовании классических численных методов объем вычи слений растет с увеличением размерности задачи примерно как экс поненциальная функция размерности, то для метода МонтеКарло он возрастает лишь как линейная функция (к примеру, число опера ций, необходимых для вычисления mKpaTHoro интеrрала методом MOHTe Карло при m == 4 в два раза меньше, чем при использова нии кубатурных формул; при m == 6  уже в 200 раз меньше, а при т == 8  в 500000 раз). К роме Toro, метод "случайных попаданий" удобен при решении систем алrебраических уравнений BbIcoKoro по рядка, вычислении экстремумов и т. д. Теперь nОЛУ"iUМ "iuсла, относительно которых известно, что их по. явление заведомо СЛУ"iаi1но. Источником таких чисел MorYT быть специальный датчик (электронная приставка к компьютеру) или rсч  reHepaTop случайных чисел (это специальный алrоритм, ини циализируемый случайным значением (текущим системным BpeMe нем)). Один uз методов 2енерации состоит в следующем: случайные числа, равномерно распределенные на отрезке [о; 1], можно полу чить, отделив дробную часть значения HeKoToporo арифметическоrо выражения. Дадим для примера две формулы: rk == {mrkl}, rде т == 8! :i: 3, l  нечетное число и rk == {5rk1 + 0.1122334791}, k Е N. 
186 Выбор разных ro Е (о; 1) позволяет формировать различные после довательности случайных чисел. Точнее эти числа надо называть nсевдослу-ч-аil:нымu (х:вазuслу-ч-а'f11/,ЫМU), так как спустя некоторое KO личество циклов последовательности таких чисел повторяются. Ko личество неповторяющихся чисел находится в пределах от несколь ких десятков тысяч до сотни тысяч [31]. ДРУ20'f1 способ 2е1/,ера'Ции заключается в использовании встроенных языковых средств. Так Паскаль и Си имеют randomize  процедуру инициализации rсч, а Фортран  процедуру seed. В Паскале и Си rсч  это функции random и rand, а в Фортране  процедура random. Скажем о них подробнее (см. разд. 11 Ста 1/,дар т 1/, ые фу1/,Х:ЦUU" 2лавы 5). Паскаль: randomize; х :==random; т :==random(n); /* n, m : word; *1 /* х Е [о; 1) */ /* m Е [о; n  1] *1 Си: randomizeO; т ==randO; т ==random( n); х ==( double )rand()/( double)RANDMAX; /* #include <stdlib.h> #include <time.h> *1 /* int n, т; RАND..мАХ=32767 */ /* m Е [о; RАND..мАХ] *1 /* m Е [о; n  1] *1 /* х Е [о; 1] *1 Фортран: саН seed( k) саН random( х) /* include 'f1ib.fi' *1 /* integer*4 k *1 /* real*4 х х Е [о; 1) */ Теперь решим задачу вычисления числа 1r методом МонтеКарло. Приступим к решению. Зададим число испытаний n и подсчитаем частоту попаданий случайной точки (х, у), имеющей равномерное распределение на единичном квадрате, в сектор Kpyra единичноrо радиуса (рис. 4.6). Площадь заштрихованноrо сектора равна 1r /4, поэтому, обозначив через р  число попаданий в Hero случайной точки (х,у), получим 1r  4р/n. Псевдослучайные числа, равномерно распределенные на промежутке [о; 1], найдем с помощью random  функции алrоритмическоrо языка. 
187 ftJI,j) о 1х Рис. 4.6. Схема попаданий случайной точки в сектор Kpyra единичноrо радиуса Сформулированную задачу будут решать два алrоритма: roловной с именем Constpi и подчиненный, названный Mypi. Работу между ними распределим так: roловной алrоритм введет число испытаний n, выведет заrоловки, обратится к алr вещ Мурi(длинцел п), а за тем выведет полученное и контрольное значения 71"; подчиненный  в начале исполняемой части задаст начальное случайное значение reHepaTopy псевдослучайных чисел, очистит ("обнулит") счетчик по паданий в сектор и, таким образом, подrотовит цикл по целочислен ной переменной k == 1 (п ) 1. Затем он внутри цикла дважды вызовет функцию random, при верном неравенстве х 2 +у2  1 увеличит счет чик р на единицу, после выхода из цикла найдет 71" и, наконец, пере даст управление в rоловной алrоритм. Проект проrраммы прост. Он имеет вид: } { алrоритм ConsCpi алr вещ Mypi длинцел п начало ввести п вывести заrоловок задачи, п, заrоловки выводных данных, Mypi(n), контрольное значение 71" /* ео алr ConsCpi */ } конец { алr вещ Мурi(длинцел п) знач п длинцел р, k начало инициализировать rсч 
188 pO для k от 1 до n шаr 1 выполнять х  random у  random если х х х + у х у  1 то pp+1 конецесли конеццикл Mypi  4р/n возвратиться конец { /* ео подсчета числа попаданий *1 /* ео алr Mypi */ } Переменным n, р, k дадИМ имена N, Р, К. Представим "картинку" выводных данных: uЧислоuПи.uuuuМетодuМоntеСаrlо. uuuuИсходиыеuдаииые:u uчислоuиспытаиийuuN=uuuul00000 uuuuOTBeT: u Pi =3.145440 uрi=з.141593 uuuu Bce . . . При числе испытаний n = 100000 результаты решения таковы: Пас кальпроrрамма дала 1r = 3.14544, Сипроrрамма  7r = 3.14664 и Фортран проrрамма (для k = 1998)  7r = 3.14468. Время решения Ka ждой проrраммы меньше трех секунд (Pentium 200, RAM 16 Мбайт). Теперь решим задачу посещения библиотеки студентами, предпола rая, что через каждые пять минут в нее может заrлянуть один чи татель. Выведем время появления каждоrо студента от начала экс пери мента (в минутах) И общее количество студентов, посетивших библиотеку в течение h часов. Сформулированная задача проста. Обозначим через h  длитель ность эксперимента (час), t  текущее время (мин), n  число при шедших студентов и v  вероятность появления студента в биб лиотеке. По условию задачи в течение одноминутноrо промежутка времени студент может прийти в библиотеку с вероятностью 1/5, значит, исходное значение v есть 0.2. Пусть длительность наблюде 
189 ния равна получасу. В схеме подчинения два алrоритма: rоловной алrоритм  Library и подчиненный  ал!' Ноwоftеn(вещ h, v, цел n). Первый задаст зна чения h и v, а второй при выполнении условия random < v накопит значение n. Приведем проект проrраммы и результаты исследования: { ал!'оритм Library ал!' Howoften вещ h, v цел n начало вывести' h(ч), v ======>' ввести h, v вывести заrоловок задачи, h, v вызвать Howoften(h,v,n) вывести заrоловок результатов, n конец } /* ео алr Library *1 } { алr Ноwоftеn(вещ h, v, цел n) знач h, v рез n цел t начало n+------О инициализировать rсч вывести заrоловок протокола посещения для t от 1 до [60h + 0.5] ша!' 1 выполнять если random :::; v то n +------ n + 1 вывести n, t конецесли конеццикл возвратиться конец { /* ео подсчета числа посетителей *1 /* ео алr Н owoften *1 } 
190 uМоделированиеuлосещенияuбиблиотеки. uuuuИсходныеuданные:u uдлительностьuэкслериментаuН=uО.50u(час) uвероятностьuлоявленияuстудентаuвuбиблкеuV=О.200 UUUUOTBeT: uПuРuОuТuОuКuОuЛuuлосещенияuбиблиотеки uuuuuuu(отuначалаuэкслеримента) ulйuстудентuлоявилсяuчерезu2uмин u................................ . u8йuстудентuлоявилсяuчерезu29uмин uЭаuО.50uчасuбиблиотекуuлосетилиu8uстудентов. uuuu Bce .. . Упражнения 116. Методом МонтеКарло вычислите площадь: . Kpyra (х  а)2 + (у  Ь)2  R 2 , . квадрата, . прямоуrольника, . параллелоrрамма, . ромба, . трапеции, . треуrольника, . криволинейной трапеции при х == О, х == 1, У == О, Лх) == 4/( 1+х2), . криволинейной трапеции при х == О, х == 3, у == О, f( х) == == 2с х2 / v7r (заметим, что вычисление интеrрала 1 == f: f( х) dx заменой переменной t == (х  a)/(b а), dt == dx/(b  а) можно свести к нахождению площади криволинейной трапеции, расположенной в единичном квадрате). 117. Методом MOHTe Карло вычислите объем: . шара (х  а)2 + (у  Ь)2 + (z  с)2  R 2 , . куба, . параллелепипеда, . тела [61], описываемоrо неравенствами О  xi  1 (i == 1, 2, 3, 4), хl +x+x+x  0.7, хl +sin Х4  0.8, ХIХЗ  0.5, 2 . тела, описываемоrо неравенствами Izl  eT , r  5 в полярных координатах (r, 1) , z), 
191 . тела, оrраниченноrо плоскостью z == О, поверхностью z == == e(x2ty2) и цилиндром х2+у2==1. Замечание Решите предложенные ниже упражнения, учитывая, что в фор муле вида rk == {J(k, rkl)}, k Е N начальное значение ro Е (о; 1); число из промежутка [о; 1] преобразуется в целое число из проме жутка [а; Ь] по правилу [( Ь  а )rk + а]; для сравнения используйте встроенный reHepaTop. 118. Выясните качество reHepaTopoB псевдослучайных чисел. BЫBe дите соответствующий текст. текст или текст reHepaTop псевдо этот: этот: случайных чисел: "Орел" "Решка" rk == {37rk1} "Пан" "Пропал" rk == {7r + 1.13rk1} " Любит" "Не любит" rk == {(7r  2 + rk1)2} "Со щитом" "На щите" rk == {( 7r  1 + rk1)3} "Чет" "Нечет" встроенный reHepaTop О  rk  0.5 0.5  rk  1 ro Е (о; 1), k Е N. Число испытаний не превосходит 10000. Можно использовать KOMaH ду выбор с пятью ветвями, в каждой из которых подсчитывается число "левых" и "правых" ответов. 119. Два иrрока х и у имеют по 1000 жетонов для проезда в Subway (метро). Моделируется бросание двух жетонов. Выиrрывает х, если жетоны леrли одинаковой стороной; в противном случае выиrрывает у. Выведите результаты иrры. Используйте reHepaTop псевдослучай ных чисел rk=={7r2+11rk1}' 120. Разработайте проrрамму, формирующую случайный набор из двух целых одноразрядных чисел. Пользователь вводит свой набор чисел. Если наборы совпали, иrра закончена; в противном случае сообщается, сколько одинаковых чисел имеют наборы и иrра может быть продолжена. Используйте reHepaTop псевдослучайных чисел rk=={(7r+rkl)З}, 121. Получите 10000 случайных чисел rl, r2, ..., rlOOOO. Оцените по 
192 ним равномерность распределения, для чеrо разбейте промежуток (0;1) на 10 равных промежутков и постройте rистоrрамму, пока зывающую, сколько чисел из последовательности (rk) находится в каждом промежутке. Используйте reHepaTop псевдослучайных чи сел r k == {СЛ'  2 + r k  1 ) 2 } . 122. Пусть случайное целое число из промежутка [1; 6] COOTBeTCTBY ет линейной мере в британских единицах длины: . 1' inch (дюйм), 1 in == 2.54 см; . 2fооt(фут), 1ft==30.48cM; . 3  yard (ярд), 1 yd == 91.44 см; . 4  саЫе (кабельтов), 1саЫе==185.2м; . 5  mile (миля), 1 mile == 1609.344 м; . 6  nautical mile (морская миля, узел), 1 knot == 1852 м. Приведите ее эквивалент в метрических единицах. Разработай те систему оценок для проверки знания еДИНИЦ длины. COCTaBЬ те соответствующую проrрамму. Используйте reHepaTop ПсеВДО случайных чисел rk=={СЛ'  2+rk1)З}' 123. Астролоrи делят rод на 12 периодов и каждому из них ставят в соответствие один из знаков Зодиака: . Водолей: . Рыбье . Овен: . Телец: . Близнецы: . Рак: 20.118.2; 19.220.3; 21.319.4; 20.420.5; 21.521.6; 22.622. 7; . Лев: . Дева: . Весы: . Скорпион: . Стрелец: . Козероr: 23. 7 22.8; 23.8 22.9; 23.9 22.10; 23.1022.11; 23.11 21.12; 22.1219.1. Напишите проrрамму, задающую случайным образом дату He KOToporo дня rода и выводящую название соответствующеrо знака Зодиака. Используйте reHepaTop псевдослучайных чисел rk == {СЛ'  2+rk1)5}. 124. Целые числа, принадлежащие промежутку [1; 24], COOTBeTCTBY ют буквам rреческоrо алфавита: 1  о:' (alpha), 2  (з (beta), 3  I (gamma), 4  Б (delta), 5  Е (epsilon), 6  ( (zeta), 7  "7 (eta), 8  () (theta), 9  t (iota), 10  х (kappa), 11  л (lambda), 12  f1 (mи), 13  v (nu), 14   (xi), 15  о (omicron), 16  7r (pi), 17  (} (rho), 18  (j (sigma), 19  r (tau), 20  ер (phi), 21  Х (chi), 22  
193 V (upsilon), 23  'ф (psi), 24  w (omega). Используя команду BЫ бор и <енератор псевдослучайных чисел rk=={7r+11rk1}, выведите названия букв. Подсчитайте количество обращений к <енератору. 125. Тело, брошенное вертикально вверх с начальной скоростью VO, достиrает высоты h == Vб/(2g). Случайным образом выбирается BЫ сота h (h Е [о; 52.2] м) и задается скорость тела Vo (vo Е [о; 32) м/с). Выведите сведения о положении тела: НИЖЕ, СОВПАЛО, ВЫШЕ. Точность совпадения равна 0.5 м. Используйте <енератор псевдослу чайных чисел rk == {( 7r  1 +rk1)3}' 126. Сформируйте трехмерный массив ("параллелепипед") из 11 х х 12 х 13 случайных неповторяющихся целых чисел, принадле жащих промежутку [о; 2047). Определите количество обращений к <енератору псевдослучайных чисел. Вычислите математиче ское ожидание т х и дисперсию d x случайной величины х: 1 n 1 n . т х ==  I: Xi, . d x ==  I: х;  т;. n i=l n i=l Упорядочьте случайные числа по неубыванию. Используйте <e нератор rk=={(7r+rk1)7}. 127. Разработайте проrрамму обучения школьников младших клас сов умножению а на Ь, <де а, Ь  целые одноразрядные числа. OцeH ка выставляется по результатам анализа семи перемножений. Ис пользуйте <енератор псевдослучайных чисел rk == {37rk1}' 128. Пусть случайное целое число из промежутка [1; 10] COOTBeTCTBY ет мере веса в британских единицах: . 1  gran (gr, <ран) равен 64.7989x106K1, . 2  dram (драхма) равна 1. 7718437 < . 3  ounce (oz, унция) равна 28.34951, . 4  pound (lb, фунт) равен 453..592 <; . 5  stone (стоун) равен 6.3.502875 к1, . 6  quarter (четверть) равна 12.700575 Kr; . 7  слаr равен 14.5939 Kr; . 8  hundredweight (cwt, центнер) равен 50.8023 к1, . 9  short ton (судовая тонна) равна 907.185Kr; . 10  (long) ton (тонна) равна 1016.048Kr. Приведите ее эквивалент в метрических единицах. Разработай 
194 те систему оценок для проверки знания мер веса. Составьте соответствующую проrрамму. Используйте reHepaTop псевдо- случайных чисел r k = { (7r  1 + r k 1 )3 }. 129. Прямоуrольную таблицу размера т х n заполните т х n слу чайными числами 1 (1  1  т х n). Упорядочьте их по невозраста- нию. Выведите результат в виде "равнобедренноrо треуrольника". Используйте reHepaTop псевдослучайных чисел rk = {7r+ 11rk1}' 130. В старояпонском календаре принят 60-летний цикл, состоящий из пяти 12-летних подциклов, которые называются зеленый, крас- ный, желтый, белый и черный. Внутри любоrо подцикла rодам сопо- ставляются названия животных: крысы, вола, тиrра, кролика, дра- кона, змеи, лошади, овцы, обезьяны, петуха, собаки и кабана. На- пишите проrрамму, которая для случайно заданноrо номера rода (1984  n  2084) выводит ero название по старо японскому кален дарю (1984 r.  rод зеленой крысы  начало очередноrо цикла). Используйте reHepaTop псевдослучайных чисел rk = {7r + 17rk1}' 131. Пусть случайное целое число из промежутка [1; 10] соответству- ет номеру вопроса по истории, например: . 1  В каком rоду было Ледовое побоище? (Ответ: 1242) . 2  Начало войны Алой и Белой Роз. (Ответ: 1455) . . 10  Приказ ректора о создании кафедры "Прикладная ма- тематика" СПб rTY. (Ответ: 1962) Разработайте систему оценок для проверки знания дат. Составь- те соответствующую проrрамму. Используйте reHepaTop псевдо случайных чисел rk={(7r2+rk1)3}' 132. Пусть случайное целое число из промежутка [1; 6] соответству- ет мере сыпучих тел в британских единицах: . 1  gill (четверть пинты) равна 0.142065 л; . 2  pint (пинта) равна 0.56826 л; . 3  quart ( кварта) равна 1.13652 л; . 4  gallon (gal, rаллон) равен 4.54609 л; . 5  bushel (bsh, бушель) равен 36.3686 л; . 6  quarter (четверть) равна 290.94912 л. Приведите ее эквивалент в литрах. Разработайте систему оце- 
195 нок для проверки знания мер сыпучих тел. Составьте COOTBeT ствующую проrрамму. Используйте reHepaTop псевдослучайных чисел Tk=={Cl!'  1+Tk1)7}. ' 133. Составьте проrрамму иrры в "Абак": компьютер rенерирует цe лое число m Е [1; 999] и n целых чисел, а пользователь rотовит свои n чисел. Выиrрывает тот, чья сумма n чисел ближе к числу т. Ис пользуйте reHepaTop псевдослучайных чисел Tk == {11"+ 15rk1}' 134. Составьте проrрамму, моделирующую иrру двух человек в 1/ Альтернативу" (бросание шестиrранноrо кубика, rрани KOToporo нумеруются от 1 до 6). Используйте reHepaTop псевдослучайных чи сел Tk=={1I"+llTk1}' 135. Получите случайное целое число, принадлежащее промежутку [о; 9]. Уrадайте ero за три попытки. После каждой попытки BыдaeT ся информация  меньше или больше исходноrо набранное число. Используйте reHepaTop псевдослучайных чисел Tk == {( 11"  2+Tk1)5}. 136. Приведите проrрамму проверки знания учащимися таблицы Пи фаrора. Компьютер задает 10 вопросов вида"m умnожuтъ па n ==?", rде m и n  случайные целые числа из промежутка [2; 9]. При пра вильном ответе выводится сообщение" Верно. . . " и задается следу ющий вопрос, а при ошибочном  предлаrается снова ответить на' вопрос. Если количество попыток ответить на один и тот же вопрос станет равным трем, компьютер посоветует подучить таблицу и пре кратит проверку. Разработайте соответствующую систему оценок. Используйте reHepaTop псевдослучайных чисел Tk == {(11" + Tk1)5}. 137. Напишите проrрамму, моделирующую следующий опыт. В PYH дуке находятся 2046 шаров: 1024  черных, 512  синих, 256  зеленых, 128  rолубых, 64  красных, 32  фиолетовых, 16  коричневых, 8  серых, 4  желтых и 2  белых. Сообщите KOM пьютеру, сколько шаров каждоrо цвета вы хотите увидеть. Считаем, что после Toro, как шар вынут и цвет ero зафиксирован, шар возвра щается в ящик. Проrрамма должна моделировать извлечение шара из рундука, суммировать число шаров каждоrо цвета и выводить на экран полученный результат и сообщенный вами запрос компьюте ру. Для определения цвета извлекаемоrо шара нужно сrенерировать случайное целое число m из промежутка [1; 2046] и далее полаrать: 
196 если выполняется неравенство 1 :::;; т :::;; 2, то извлекается белый шар, если 2< т:::;; 6,  желтый,..., если 1022< т:::;; 2046,  черный. Ис пользуйте reHepaTop псевдослучайных чисел rk == {( 71"+ 1.23rk1?}' 138. Составьте проrрамму перевода целоrо числа т (1:::;; т :::;; :::;; 2147483647) из "своей", lОй системы счисления в "чужую", qю систему (q == 2,8,16; см. ПРUЛОJfCеnuе 2). Числа для перевода выби раются случайным образом. Используйте reHepaTop псевдослучай ных чисел rk == {37rk1}' 139. Квадратную таблицу размера (2п  1) х (2п  1) заполните слу чайными целыми числами т (1:::;; т :::;; (2п  1)2), расположив их по спирали в направлении по часовой стрелке, начав с центра квадрата. Используйте reHepaTop псевдослучайных чисел rk == {71" / e+9.1rk1}, 140. Получите случайное целое число, принадлежащее промежутку [1; 1000]. Уrадайте ero за 10 попыток (после каждой попытки BыдaeT ся информация  меньше или больше исходноrо набранное число). Используйте reHepaTop псевдослучайных чисел rk == {( 71"  1 +rkl?}' 141. rенерируются случайные целые числа, принадлежащие проме жутку [1; 10]. Определите их (допускается не более трех попыток на каждое число). Складывайте тройки чисел. Суммы контролируйте (обработайте не больше десятка троек чисел). Разработайте систему оценок суммирования. Выдайте результаты тестирования. Исполь зуйте reHepaTop псевдослучайных чисел rk == {( 71" + 13rk1)3}' 142. Составьте проrрамму "Эстафета". Соревнуются восемь команд. Дистанция  4 по 100 м. Скорость v м/с любоro беrуна на каждом этапе выбирается случайным образом (8.1:::;; v:::;; 10.2). Выведите пол ный протокол соревнований (в частности, как спортсмен х из KOMaH ды у выступил на своем этапе). Используйте reHepaTop псевдослу чайных чисел rk == {71"+2+з.7rk1}' 143. Составьте проrрамму иrры в "Ним". На стол кладут т спичек (т rенерируется rсч). Компьютер и человек по очереди "берут" со стола не более п спичек (1 :::;; п « т). П роиrрывает тот, кто берет со стола последнюю спичку. Используйте reHepaTop псевдослучайных чисел rk=={(71"1+1.7rk1)3}' 144. Напишите проrрамму иrры в "Кости" (Die) по следующим пра- 
197 вилам: число иrрающих  до пяти; кости бросаются по очереди; пер вый иrрок вводит целое число m Е [1; 6]; затем "бросаются кости"  компьютер rенерирует три случайных целых числа из промежутка [1; 6]; если среди них число m встретилось один раз  иrрок по лучает 5 очков, два раза  10 очков, три  15, не встретилось ни разу  О очков. Используйте reHepaTop псевдослучайных чисел Tk == { 1482Tk1 /37}. 145. Получите 128 случайных целых чисел. Отсортируйте их по He убыванию методом Дж. фО'Н, Нейма'Н,а (John von Neumann): объяви те два массива А и В (в А находятся исходные числа); упорядочьте пары соседниХ чисел (аl и а2, аз и а4 и т. д.) И запишите их в В; возьмите из В по две соседние упорядоченные пары и, слив их в упорядоченные четверки, снова запишите в А; затем каждые две соседние четверки из В слейте в упорядоченные восьмерки и пере несите их в А и т. д. Используйте reHepaTop псевдослучайных чисел Tk == { (п  2 + Tk 1)5}. 146. Составьте проrрамму перевода целоrо числа n (1  n  2147483647) из "чужой", qй системы счисления в "свою", 10ю си стему (q==2, 8,16; см. Прuложе'Н,uе 2). Числа для перевода выбира ются случайным образом. Используйте reHepaTop псевдослучайных чисел Tk == {( 7r  1 +Tk1)3}' 147. Если дата лежит в диапазоне от 1582 по 4902 rr., то номер дня недели (воскресенье имеет номер О, понедельник  1, ... , суббота  6) равен остатку от деления на 7 значения выражения [2.6т  0.2] + d + V + [у/4] + [С/4]  2с, [де d  номер дня в месяце; m  номер месяца в rоду (март имеет номер 1, апрель  2, '" , декабрь  10, январь и февраль считают ся месяцами с номерами соответственно 11 и 12 предыдущеrо rода); у  число, образованное двумя младшими цифрами [ода; с  число, образованное двумя старшими цифрами rода. Даны случайные целые числа u Е [о; 6], v Е [1; 12] и w Е [1582; 4902], обозначающие соответственно число, месяц и rод. Определите день недели, на который падает указанная дата. Используйте reHepaTop псевдослучайных чисел Tk == {( 7r  1 + Tk1)2}. 
198 Рекурсия в заключение rлавы познакомимся с "маленьким чудом" в проrрам мировании  рекурсией и рекурсивными алrоритмами. Рекурсия отражает черту абстрактноrо мышления, проявляющуюся в самых различных приложениях (в математике, синтаксическом анализе и трансляции, древовидной сортировке и обработке данных с динами ческой структурой, шахматных задачах и т. д.). Пользование ею из бавляет от необходимости последовательноrо (и часто, утомитель Horo) описания процессов. Алrоритм называется ре ""урс u 6пым, если он определен с помощью caMoro себя. При этом алrоритм nр,ямо ре""урси6еп, если он содержит вызов caMoro себя, и ""ОС6еппо  если он начинает цепочку обраще ний к друrим алrоритмам, заканчивающуюся вызовом caMoro себя (поэтому рекурсивность алrоритма не всеrда, может быть, сразу вид на из ero текста). В математике наиболее известным примером pe курсивно определенноrо алrоритма является факториальная функ ция (см. nодразд. "БеС""О'/iе'Ч'/iое nРОUЗ6еде'/iuе" разд. "ИтератU6'/iъti1 u,u""л" 2ла6ъt 3). Мимо нее никак не пройти. Вот это определение: J(n) == n х J(n  1), если n > о; J(O) == 1. Здесь функция J( n) задается через функцию J( n 1), которая в свою очередь определяется через J(n2) и т. д. вплоть дО J(O), значение которой равно 1. Таким образом, в этом примере rлубина рекурсии составляет n уровней. Чтобы подобный процесс сведения не оказался бесконечным, рекурсивное определение должно содержать перемен ную, значение которой изменяется по некоторому закону, и задание начальных значений aprYMeHToB. При записи рекурсивных алrоритмов можно пользоваться УСЛО6'/iЫМ 6ыраJfCе'/iUем 6 форме Ма""""арти [3]. Оно имеет вид: [Ь 1  al, Ь 2  а2, ..., bnl  anl, а n ] rде Ь ; (i == 1, 2, . . . , n  1)  условие (лоrическое выражение), а а;  выражение (i == 1, 2, . . ., n). Значение условноrо выражения Ha ходится так: последовательно слева направо вычисляются значения условий, пока не найдется условие b i , имеющее значение истина; co ответствующее этому значению выражение а; будет значением Bcero 
199 условноrо выражения; в противном случае (все b i ложны) значение условноrо выражения есть а п . К примеру, в форме Маккарти опре деление nфакториала имеет вид f(n) == [(n > 1)  n Х f(n  1), 1] Приведем теперь рекурсивный алrоритм f в записи псевдокодом: алr длинцел f (длинцел n) знач n начало если n > 1 то fnxf(nl) иначе fl конецесли возвратиться конец /* ео алr f */ Тот, кто не проrраммирует, вполне Mor бы предпочесть эту запись, так как она является точным "слепком" с соответствующеrо peKYP сивноrо определения, тоrда как создание нерекурсивноrо (итератив Horo) варианта factorial требует определенных навыков проrрамми рования: алr длинцел fасtоriаl(длинцел n) знач n длинцел р, k начало pl для k от 2 до n шаr 1 выполнять ppxk конеццикл factorial  р возвратиться конец /* ео алr factorial */ Заметим, что с рекурсивной функцией (процедурой) автоматически связывается множество локальных объектов (меток, констант, ти пов, переменных, функций и процедур). Всякий раз, Korдa peKYP сивный алrоритм вызывается, создается новое поколение локаль 
200 ных объектов с теми же именами, что при предыдущем обращении к алrоритму, но с текущими значениями локальных, связанных пере менных и формальных параметров. При этом правила области дей ствия имен (идентификаторов) позволяют успешно разрешать кол лизию имен (см. славу 8): идентификаторы всеrда относятся к caMO му последнему порожденному множеству переменных (это же пра вило имеет силу и для формальных параметров алrоритма). Друrим примером рекурсивноrо алrоритма служит алrоритм Евкли да (см. разд. 11 Арuфметшса" ранее в этоll славе). Назовем ero gcd: gcd(u, v) == [(v == О)  и, gcd(v, umodv)] В этом простом определении, заметим, сразу не известно, какая rлу- бина рекурсии будет достиrнута при вычислении, к примеру, значе ния gcd(544,119). Ясно, что она конечна, но крайне важно, чтобы она была мала. Большая rлубина рекурсии может привести к aBa рийному завершению работы (правильной) проrраммы (например, уже при ее тестировании) изза переполнения стека. В записи псев докодом рекурсивный алrоритм Евклида выrлядит так: алr длинцел gcd (длинцел а, Ь) знач а, Ь длинцел и, v начало u  lal v  Ibl если v == О то gcd  u иначе gcd  gcd(v, u mod v) конецесли возвратиться конец /* ео алr gcd *1 А это rоловной алrоритм нахождения нод(а, Ь): алrоритм Euclidrecursive алr длин цел gcd , , конст опе       two ' ==============================================' длинцел а, Ь симв ch 
201 начало вывести two, , u Нод. u u Рекурсивный алrоритмuЕвклида.' пока истина выполнять вывести оnе, 'uuuuдлинцелuа,uЬu== == ==>' ввести а, Ь вывести 'uнод(', а, ',', Ь, ')==', gcd(a, Ь), , u3авершитьuработу :uuуuилиun' ввести ch если ch == 'у' конеццикл вывести two, 'uuuuThe end. .. ' то прервать конецесли /* ео обработки а и Ь */ конец /* ео rолов алr */ в заключение приведем рекурсивный алrоритм [ерона (см. раза. "Повторение" 2лавы 3) в форме Маккарти (оцените, насколько изя щен этот алrоритм): Heron(a, х, с:) == [I(x  а/Х)/21  с:  х, Heron(a, (х + а/х)/2, с:)] И в записи псевдокодом: алr вещ Неrоn(вещ а, х, с:) знач а, х, с: начало если I(x  а/х) х 0.51  с: то Heron +----- х иначе Heron+-----Heron(a, (х+а/х) х 0.5, с:) конецесли возвратиться конец /* ео алr Heron */ Таким образом, рекурсия не является чемто нарочито усложнен ным и предназначенным для касты посвященных, а представляет собой еще одно средство проrраммирования, которым можно пользо ваться удачно или злоупотреблять, как и всяким друrим [з]. PaCCMO тренные выше алrоритмы вычисления f(n), gcd(m, n) и некоторые 
202 численные процессы (такие, как повторное интеrрирование) по CBO ей природе являются рекурсивными. Однако если существует Hepe курсивное решение задачи, то следует пользоваться именно им, так как при реализации рекурсии необходимо затратить больше систем ных средств, чем в итеративном решении (рекурсия требует допол нительноrо времени и памяти для размещения поколений перемен ных). С друrой стороны, рекурсивное решение необходимо в компи ляторах, при обработке динамических структур данных, в задачах оптимальноrо выбора, в системах моделирования человеческоrо MЫ шления (т. е. в области знаний, которую называют "искусственным интеллектом") и т. д. Итак, урок таков: следует избеrать рекурсивноrо решения там, rде есть очевидное итеративное решение, и использовать ero тоrда, коrда без рекурсии просто не обойтись. "Итерация свойственна человеку, а рекурсия  боrу" (Л. Питер Дойч). Упражнения Приведите рекурсивное и нерекурсивное (итеративное) решение сле дующих ниже задач (см. замечание к упр. 1 зо ранее в этой rлаве). Подсчитайте rлубину рекурсии. 148. Вычислите значения полиномов Чебышева 1ro рода (Tchebyseff): Т;(х) == 1, Tl'(x) == 2х  1, Т;н(х) == 2(2х  1)Т;(х)  T;l(X)' 149. Преобразуйте последовательными добавлениями или вычитани- ями 1r aprYMeHT х к промежутку [о; 1r]. 150. Получите ряд Фибоначчи (Fibonacci) и золотое сечение q: fo == 1, Л == 2, fn == fnl + fn2; q  fnl/fn (q == (\"'5  1)/2). 151. Вычислите п 2 (п Е N), используя лишь аддитивные операции. 152. Вычислите значение полинома рn(х) == аохn + alxn1 + ... + а n в точке х по правилу fopHepa (Horner): bl == О, b k == bklX + ak (k==O, 1, ..., п). 153. Выполните k-кратное дифференцирование полинома рn(х) = n . nk (k) . L:= aixnt. Коэффициенты полинома pJk)(x) == L:= ai xntk полу t=o i=o 
203 чите в первых n + 1  k элементах вектора а. 154. Вычислите значения полиномов Эрмита (Hermite): но(х) == 1, Нl(Х) == 2х, Нп(х) == 2xHп1(X)  2(n  1)Hп2(X)' 155. Вычислите коэффициенты бинома Ньютона: ао == 1, ak == akl(m  k + l)/k (k== 1,2,..., т). 156. Вычислите tg( n + 1 )х, rдe sin(n + l)х == 2sinnxcosx  sin(n  l)х, cos(n + l)х == 2cosnxcosx  cos(n  l)х. 157. Вычислите (2n)!! и (2n 1 )!! (например, 4!! == 2 х4, 5!! == 1 х 3 х 5). 158. Получите все перестановки символов а, Ь, с и d. 159. Подсчитайте количество всех различных размещений из т эле ментов по n: A == т, A == (т  n + 1) A 1 (1  n  т). 160. Выведите вводимые числа в обратном порядке. 161. Вычислите биномиальные коэффициенты: C==l, C==(n+1k)C1/k (lkn). 162. Вычислите значения полиномов Лаrrера (Lagger): L\x) == 1, Lk)(x) == Х  (k + 1), Lk)(x) == (х  k  2n  3)Lk1(X)  (n  l)(k + n  1)Lk2(x). 163. Разложите целое число на простые множители. 164. Вычислите биномиальные коэффициенты: C == с;:: == 1, c == О (n > т  О) C == c-=-\ + Cl (т  n > О). 165. Вычислите значения функций Неймана (Neumann) полуцелоro порядка (х > О, k  О): N1/2(X) == .) 2/( 7rx) sin х, N 1 / 2 (x) ==  .) 2/(7rX) cos Х, Nk3/2(X) + Nk+l/2(X) == (2/х) х (k  1/2)Nk1/2(X) (k> 1/2). 166. Сформируйте и выведите всевозможные последовательности, состоящие из n натуральных чисел, сумма которых равна т. 167. Задана непустая последовательность положительных веще 
204 ственных чисел, за которой следует отрицательное число. Объявите рекурсивную функцию Sиmplиs (без параметров) для нахождения суммы положительных элементов последовательности. 168. Выведите в обратном порядке цифры HeKoToporo числа. 169. Пусть дано объявление: КОНСТ lim  100 вещ массив А[1: lim] Приведите описание функции Min нахождения минимальноrо эле мента массива Х с помощью рекурсивной функции MinTail. Эта вспомоrательная функция определяет минимум среди последних (хвостовых) элементов массива Х, начиная с kro. Найдите мини мальный элемент массива А(п); п == 13, k == 7. 170. Вычислите значения функций Бесселя (Bessel) полуцелоrо по рядка (х > О, п  О): J1/2(X) == / 2/(7rx)cosx, Jl/2(X) == / 2/(7rx)sinx, Jn+l/2(X) == (2(п  1/2)/Х) х Jn1/2(X)  Jn3/2(X) (п> 1/2). 171. Вычислите значение полноrо эллиптическоrо интеrрала lro po да (ko == 0.5): ]{ ==  nQl (1 + k n ), k n == (1  / 1  kl) / (1 + .) 1 + kl ). 172. Дана последовательность ненулевых цел чисел, за которой сле дует О. Выведите сначала все отрицательные элементы последова тельности, а затем  все положительные (в любом порядке). 173. Вычислите значения функций Аккермана  Петера (Ackermann Peter): Ао,n == п + 1, Ат,О == Aтl,l' Ат,n == Aтl,Aт,n1 (т, п Е N). 174. Вычислите значения функций Бесселя 1ro рода nro порядка (Bessel): 00 Jo(x) == L (1)k(x/2)2k/(k!)2, k=o J 1 (x) == f(1)k(x/2)2k+l/(k!(k+ 1)!), k=o 2п/х х Jn(x) == Jnl(X) + J n + 1 (x); Е == 1011. 
205 175. Вычислите у == а n (n  цел), используя ркурсивную функ цию цел Pown, которая находит у так, как указано в табл. 4.2. Таблица 4.2. Правило вычисления степени у = а n а n у тип у любое n>О ахах... ха совпадает с типом а ,  , n раз а==О nO не определен  a:fO n==О 1 совпадает с типом а a:fO n<О 1/ (а х ах... х а) вещ ,  , 'nl раз 176. Сформируйте и выведите всевозможные последовательности, состоящие из n натуральных чисел, каждое из которых не превос ходит т. 177. Представьте Рn(х) == ао(х  с)n + аl(Х  c)n1 + ... + а n в вид полинома по убывающим степенямх. Вектор коэффициентов запи шите в исходный массив а. Воспользуйтесь обобщенной схемой [op нера (Horner): b ik == b i +1,k  Cbi+l,kl, bnk,k == ak, Ью == ао (k, i == n =0,1, ..., n); Рn(х)== L: bOkXnk. k=O Самостоятельная работа Далее сформулированы задачи, предназначенные для самостоятель ной работы. Решите их (см. замечание к упр. 1  30 ранее в этой rлаве). В задачах, rде исходные данные не заданы (или заданы не полностью), выберите их самостоятельно. Заметим, что предварительно подrотовленные упражнения в про rраммировании (в математике, физике, химии и т. д.) обычно точно сформулированы, потенциальные трудности в них либо обойдены, либо спрятаны, отодвинуты на второй план (и тоrда обучающийся оказывается "в положении ребенка, KOToporo часто кормят пересла щенной манной кашей"). Вероятность Toro, что в реальном проекте будет так же, близка к нулю. Практические задачи более жестки, 
206 но и более интересны. Они часто плохо сформулированы, т. е. их описания бывают неполны, неточны, неРЯШЛИВJ>I и даже содержат ошибки. 1. Выполните следующие действия над комплексными числами: . найдите z == х + iy == ZlZ2 == (Xl + iYl)(X2 + iY2) и Z == Zl/Z2; . найдите r.::  / . :!: ( . / у' х 2 + у2 + Х :!: . / у' х 2 + у2  Х ) у Z == V Х + zy == у 2 zy 2 ; знак + перед мнимой единицей при у  О, знак   при у < О. 2. Вычислите значения следующих функций: . Ceil( х) == r х 1 == min k; kx . Floor(x) == LxJ == maxk; kx { L х J == тах k, если х  О, Т ( )  kx · runc х  r 1 . k х == mш, если х < о; kx D . ( ) { [ х / у ] , если х / у  о ( х, у Е Z), . lV Х, У == [Ix/yl], если х/у < о; . Odd( х) == { false, если х  четное число, true, если х  нечетное число; .Pred(i)==il, iEZ; . Succ(i) == i + 1, i Е Z; . у == ах (х  вещ), используя функцию вещ Powx, которая находит у так, как указано в табл. 4.3. Таблица 4.3. Правило вычисления степени у = аХ а х у тип у а>О любой ехр (х х ln а) вещ а==О Х>О О вещ а==О XO не определен  а<О любой не определен  
207 3. Решите следующие rеометрические задачи: . найдите точку, расположенную на оси ординат, равноудален ную от начала координат и от точки Аа(Ха, Уа); . найдите точку, удаленную на 1 единиц длины как от точки Аа(Ха, Уа), так и от оси ординат; . на оси абсцисс найдите точку, равноудаленную от начала KO ординат и от точки Аа(Ха, Уа); . точка В симметрична точке Аа(ха, Уа) относительно биссек трисы первоrо и TpeTbero квадрантов; найдите длину отрезка АаВ; . даны точки A1(Xl, Yl) и А 2 (Х2, У2); найдите точки A и А;, сим метричные точкам Аl и А 2 относительно оси ординат, и BЫ числите площадь трапеции AIA2A;A. 4. Вычислите число 11", используя следующие формулы (е = 10q): 00 . 11" = 2 L р!/(2р + 1)!!; р=а . 11" = 3 2 I: (( m  1)!) 2 / (2т)! ; т=l .11"= 2(1 + n/2n  1)!!/((2n)!! х (2n + 1))); . 11" = 2VЗ( 1  1/3 х 1/3 + 1/5 х (1/3)2  1/7 х (1/3)3 + ...); . Валлиса (Wallis): 11" = 2nli 1/(2n + 1) х ((2n)!!/(2n  1)!!)2; . Рамануджана (Ramanujan): 11" = 2/ (1  5(1/2)3 + 9(1 х 3/(2 х 4))3  13(1 х 3 х 5/(2 х 4 х х6)) 3 + . . . ). 5. Вычислите числа: . Каталана (Catalan) G == L=l( 1)nl /(2n  1)2 == 0.915965594...; . Бернулли (Bernoulli) Вn == ((2n )!/1r2n22n1) Ll 1/ рn; 
208 . Эйлера (Euler)2 С == Пlijё/(l + l/k) == 0.5772156649015325...; . Эйлера (Euler) Еn == (22n+2(2n)!/7!'2n+l)I:I(1)kI/(2k 1)2n+l; . Непера (Napier) е ==  х (  ) 1/: ( 6 х 8 ) 1/ ( 10 х 12 х 14 х 16 ) 11.8.. 1 3 5 х 7 9 х 11 х 13 х 15 6. Постройте таблицу значений функции (с == 10q): . lnx == I:=I(l)n+l(x  1)n/n (О < х  2); . lnx == I:I(X  1)n/(nхn) (х> 1/2); . ln(l + х) == I:=I(l)n+lxn/n (1 < х  1); . ln(l  х) ==  I:=1 хn/n (1  х < 1); . ln(l + х)/(l  х) == 2I:=ox2n+l/(2n + 1) (Ixl < 1); . ln(x + l)/(х  1) == 2I:=o 1/ ((2n + 1)х2n+l) (Ixl> 1); . ln(n + 1) == lnn+2I:11/((2k1)(2n+1)2kl) (n==1, 2, . ..); . arctgx == I:=o(1)nx2n+l/(2n + 1) (Ixl < 1); . arcctgx==7!'/2+I:=o(1)n+lx2n+l/(2n+1) (Ixl < 1); . arcctgx == I:=o(1)n/((2n + 1)х2n+l) (х> 1); . arcctgx == 7!' + I:=o( 1)n / ((2n + 1)x2n+l) (х < 1); . е Х == I:=o хn/n! (х Е R); . ex2 == I:o(1)nx2n/n! (х Е R); . sinx == I:=I(1)nlx2nI/(2n  1)1 (х Е R); . cosx == I:=o(1)nx2n/(2n)! (х Е R); 00 1 х 3 х 5 х . . . х (2n  1) . arshx==x+I:(l)n х2n+l (l x l<l); n=1 2 х 4 х 6 х. .. х 2n х (2n + 1) 2 Леонард Эйлер (1707  1783)  великий математик, механик и физик. Швейцарец по происхождению. Петербурrский академик. Знаменитая петер бурrская, или чебышёвская, математическая школа идет в большой мере от Эйлера. Был похоронен на лютеранском Смоленском кладбище. Осенью 1956 r. останки Эйлера и памятник были перенесены в Петербурrский некрополь (АлександроНевская лавра). 
209 h (1 ( )  1 х 3 х 5 х . . . х (2п  1) 1 ) ( ) . arc х ==:!: n 2х    х > 1 ; n=l 2 х 4 х 6 х. . . х 2п х 2п х 00 т(тl) (тп+1) . (1:!:х)т==1+ 2: (:!:1)n "', х n (т>О, Ixl<l); n=l п. 00 т(т+1)...(т+п1) . (1:!:x)m==1+2:(=F1)n , х n (т>О, /xl<l); n=l п. ах а(а+1)х 2 . Куммера (Kummer) Ф(а, с; х) == 1 +  1 ' + ( ) , + ...; с. с с + 1 2. 00 (х/2)2Нn . Бесселя (Besse1) Jn(x) == 2: (l)k k' (k )' (О  х  1.8); k=O . + п . 2 х 2 2 2 00 2 n . erf х ==  f et dt == eX 2: x2n+l;  О .Ji n=О 1 х 3 х . . . х (2п + 1) Ф(z) == fI J eи2/2du : у-; О . Пусть u == t-J2 и z == x/-J2. Имеем z [f f (1)n (z/2)2n у -; n=О п!(2п + 1) Ф(z)== 1 ez2/2 [f ( 1 f (l)nl (2п1)!! ) при z4; z У -; n=l z2n . rаммаФункции r(x) == l/(хеСХП:'=l(l + x/п)eX/n), rде С == lim ( 2:k=l (1/ k)  1n п )  постоянная Эйлера noo (С == 0.577 2156649015325. . . ); Х e t 00 х n . Ei ( х) == f  dt == С + 1n I х I + 2: , ' oo t n=l п х п. rде С == 0.577 215664901 5325. . . ; Х dt 00 (ln х ) n · 1i( х) == f  1 == 1n 1n х + 2: , ; О n t n=l п х п. Х sin t 00 х2n+1 · Si(x) == [T dt == fo(l)n (2п + 1) х (2п + 1)! ; 00 cos t 00 х 2n . Ci(x)==fdt==C+1nx+ 2:(1)n ()" Х t n=l 2п х 2п. rде С == 0.5772156649015325. . . ; при z <4, 
210 1 х sin t  00 х2n+l · S(x) == v27i [ Jt dt == у;х nO( 1)n (4n + 3) х (2n + 1)! ; 1 х cos t  00 х 2n · С(х) == v27i [ Jt dt == у;х nO( 1)n (4n + 1) х (2n)! ' 7. Найдите периметр эллипса (е == 10q): L == 271"а (1  L1((2n  1)!!j(2n)!! х е n )2), е == v a 2  b 2 ja, L :::::; 11"( a+b)(643),4 )j(64 16),2), ), == (ab) j( а+Ь) (а == 10, Ь == 5). 8. Вычислите коэффициенты полинома Чебышева (Chebyshev): nn/2 (nkl)! Тn(х) ==  L (l)k k'(  k)' (2x)n2k 2 k=O . n 2 . (например, при n==8 имеем T8(x)==128x8256x6+160x432x2+1). 9. Решите следующие rеометрические задачи: . Даны (плоские) уrлы А== (Oi), В== (lЗ i ) и r == (,i) (i == 1, 2, ..., n), принадлежащие интервалу (о; 71"). Определите, из каких уrлов Oi, (3i И ,i можно построить TpexrpaHHbIe уrлы. . Даны координаты точек Pi(Xi, Yi) (i == 1, 2, ..., n). Найдите минимальный и максимальный радиусы окружностей, прове денных через любые тройки точек. . Фу'нкция У == ЛХ) задана на отрезке [а; Ь]. Методом дихото мии (бисекций) найдите minJ(x), mахЛх), infJ(x) и supJ(x); е == 10q. . В правильном nуrольнике провели несколько диаrоналей, причем никакие три из них не пересекаются в одной точке. На сколько частей диаrонали разбили nуrольник (диаrона ли заданы номерами вершин nуrольника, которые они co единяют; все вершины перенумерованы по порядку числами 1,2,...,n)? . В прямоуrольной системе координат заданы координаты трех вершин прямоуrольника (хl, Уl)' (Х2, У2), (хз, УЗ). Найдите KO ординаты четвертой вершины. . П ринтер печатает на странице т строк из n символов каждая. Расстояние между центрами соседних символов составляет по rоризонтали w единиц длины, по вертикали  h единиц. Ha 
211 чало координат находится в центре страницы. "Нарисуйте" символом * две окружности с центрами в точках (Хl, Уl), (Х2, У2) И радиусами соответственно rl и r2 (если окружно стям мало места на странице, то рисуйте только те их части, которые умещаются) [35]. . Из листа клетчатой бумаrи размера т х n клеток удалили некоторые клетки. На сколько кусков распадется оставшаяся часть листа (к примеру, если из шахматной доски удалить все клетки одноrо цвета, то оставшаяся часть будет состоять из 32 кусков)? . Из листа клетчатой бумаrи размера т х n склеили цилиндр высотой n, а затем удалили некоторые клетки. На сколько кусков распадется оставшаяся часть цилиндра? . Имеется n карточек. На каждой стороне каждой карточки на- писано целое число. Известно, что каждое из чисел 1, 2, . . . , n встречается на карточках дважды. Узнайте, МОЖI;Ю ли кар- точки разложить так, чтобы каждое из чисел 1, 2, ..., n было на верхней стороне одной из карточек. Если можно, то ука- жите для каждой карточки, как ее класть. . Дано n тетраэдров. На каждой rрани каждоrо тетраэдра Ha писано целое число. Известно, что каждое из чисел 1, 2, .. . , n встречается на тетраэдрах четыре раза. Выясните; можно ли поставить тетраэдры на плоскость так, чтобы каждое из чи- сел 1, 2, . . . , n встречалось на верхних rранях трижды. Если можно, то для каждоrо тетраэдра укажите, как ero ставить. . На клетчатой бумаrе нарисована окружность радиуса r (r Е N) с центром в точке пересечения линий. Найдите k  ко- личество клеток, целиком лежащих внутри этой окружности (например, если r == 5, то k == 60). . Трехмерное пространство разбито на кубики с длиной ребра, равной единице. Сколько кубиков помещается в сфере ради- уса R, центр которой находится в вершине одноrо из кубиков (например, в сфере при R == 3 размещается 56 кубиков)? n. m 10. Перемножьте подиномы Рn(Х)== LUjXn' и Qm(X)== LbiXmi. i=O i=O 11. Решите следующие задачи статистики: 
212 . Задана последовательность значений (xi) (i 1, 2, . . . , n). Подсчитайте: среднее х == (1jn)L::1 Xi, дисперсию т2 == (1jn) L::l X  х 2 , третий момент тз == (1jn) (L::l Х7  3х L::l Хп + 2х З , коэффициент асимметрии v == тз/Н. . Вычислите коэффициент корреляции последовательности пар случайных величин (Xi,Yi) (i==1, 2, ..., n): т== ппп L:: XiYi   L:: Xi L:: Yi i=l i=l i=l C X  C Xi)2)C1 У?  Cl Yi)2) 12. Решите задачу сrлаживания методом наименьших квадратов. Для этоrо надо выбрать функцию f, которая наилучшим обра зом описывала бы совокупность n пар экспериментальных данных (Xi, Yi) (i == 1,2, ..., n), т. е. минимизировала соотношение ()'2 == == (1jn) L::f=l (Yi  J( X i))2. Обычно разыскивается функция f задан Horo вида. Задача сводится к определению коэффициентов perpec сии, т. е. параметров функции y==J(x). Выполните сrлаживание: . прямой линией У == ах + Ь (линейная реrрессия), [де а == (L::xY  (1jn)L::xL::Y)/ (L::x 2  (1jn)(L::x)2), Ь == (1jn)(L::y  aL::x). . функцией У == аф(х) + Ь, сводящейся к прямой, [де а == (L::ф(х)у(1jn)L::Ф(х)L::У)/(L::ф2(Х)(1jn)(L::ф(х))2), ь == (1jn)(L::Y  аL::Ф(х)); ф(х) == 19x, ф(х) == sin7rx и т. д.; . экспонентой У == ае ЬХ , [де Ь == (L:: Х ln У  (1 j n) L:: х L:: ln У) / ( L:: х2  (1 j n) ( L:: х) 2) , а == ехр ((1 j n) (L:: ln У  Ь L:: Х )) ; . степенной функцией У == ах Ь , [де Ь == (L:: 19 х 19 У  ( 1 j n) L:: 19 х L:: 19 У ) / ( L:: 192 Х  ( 1 j n ) ( L:: 19 х) 2) , 
213 а == ехр (( 1 / n ) (Е 19 У  Ь Е 19 Х )) . 13. Решите следующие задачи обработки одномерных массивов: . Запишите в качестве i ro элемента массива А длины n сумму элементов от а п до ai включительно. . Осуществите циклический сдвиr массива А длины n на k эле ментов, так что элемент ai перемещается в ai+k, а последние k элементов массива переносятся в первые k ero элементов. . Даны три целочисленных массива A==(ai), B==(b i ), C==(Ci) (i == 1, 2, . . . , n). Известно, что существуют элементы, принад лежащие всем трем массивам. Найдите хотя бы один из таких элементов. . Переста'Н,О61Соi1 k .ч,uсел называется последовательность аl, а2, ..., а п , в которой встречаются по одному разу все числа от 1 до k (например, перестановками трех чисел являются (1,2,3), (1,3,2), (2,1,3), (2,3,1), (3,1,2), (3,2,1) и друrих перестановок этих чисел нет). Получите перестановки n чисел. . В массиве А длины n найдите наименьшее натуральное число т, обладающее следующим свойством: нужно так вычеркнуть некоторые элементы массива А, чтобы сумма оставшихся paB нялась т. . По двум заданным массивам А == (ai) и В == (b i ) (i == 1, 2, ..., n) получите третий Х == (Xi), rде Xi == QiXi+l +/3i (i == n, n1, ..., 1) Qi == b i /(2 + Qilai), /3i == (1  /3ilai)/(2 + Qilai) (i == 1,2, ..., n) с учетом Toro, что аl == О и Ь п == О. 14. Решите следующие задачи обработки матриц: . Умножьте матрицу А размера n х n на вектор х. . Умножьте вектор х на матрицу А размера n х n. . Транспонируйте матрицу А размера m х n. . Из матрицы А == (aij) (i, j == 1,2, ..., n) получите вектор Х == (Xi) (i == 1, 2, ..., n), rде Xj  скалярное произведение iй строки на столбцы матрицы А. Упорядочьте по неубыванию элементы этоrо вектора. . В матрице А размера m х n найдите строку с наибольшей суммой ее отрицательных элементов и сформируйте вектор 
214 х, элементы KOToporo суть упорядоченные по невозрастанию элементы этой строки. . Столбцы матрицы А размера n х n упорядочьте по неубыва нию их элементов. Сформируйте вектор х, элементы KOToporo равны суммам кубов элементов rлавной и побочной диаrона лей преобразованной матрицы А. . Из матрицы А размера т х n получите вектор, состоящий из упорядоченных по невозрастанию средних rармонических значений элементов строк матрицы А. . Дана матрица А размера т х n. Упорядочьте элементы ее нечетных столбцов по неубыванию, а четных по невозра станию. . Найдите седловую то'Чх;у атриц'Ы минимальный в строке и максимальный в столбце элемент матрицы А размера n х n. . Получите первые т строк треУ20л'Ьнuх;а Пасх;аля (Pascal). Ero образуют биномиальные коэффициенты, связанные COOTHO шениями Cik == Ci l,k+Ci l,k l (i == 2, 3, . . . , n; k == 1, 2, . . . , i 1), CiO==Cii==1 (i==O, 1, ..., n). . Методом "ceBepO BOCTOK" постройте маrический квадрат He четноrо порядка n. . Найдите элементы матрицы А размера т х n, сумма индексов которых равна заданной константе k. 15. Решите задачи обработки чисел: . Проверьте равенство C + C + C + ... + C l + C = 2 n . . Даны натуральные числа т и n (т n). Определите, какие из чисел т, т + 1, ..., n моrли быть номерами високосных rодов (в rриrорианском календаре каждый rод, номер KOTO poro делится на 4, является високосным, за исключением тех, которые делятся на 100 и не делятся на 400). . Уравнение х 4 + аlХЗ + а2х2 + азх + а4 == О решите, разложив левую часть на множители -методо-м неоnределенн'Ых х;оэф фuцuентов. В этом методе, исходя из равенства х 4 + аlХЗ + +а2х2 + азх + а4 == (х 2 + рх + q)(x 2 + rx + s), составляют си стему {р + r = аl, pr + q + s == а2, ps + qr == аз, qs == а4}; здесь предполаrается, что коэффициенты al, а2, аз, а4, р, q, r и s
215 целые числа. Систему решают подбором, начиная с последне ro уравнения qs == а4; Х == {х I х 4  4х 3  10х 2 + 37х  14 == О, х Е R}. . Создайте эффективный алrоритм нахождения нескольких цe лых чисел т, 11" l и k, удовлетворяющих равенству т 3  11,3 == == (/2 + k2( . Числа Пuфа20ра удовлетворяют равенству а 2 +Ь 2 == с 2 , rде а, Ь и с  натуральные числа. Разработайте эффективный алrо ритм определения 11, троек чисел Пифаrора. . ПО номеру дня недели (целому числу от 1 до 7) определите, сколько учебных часов в вашей rруппе в соответствующий день. . ПО последней цифре числа 11, определите последнюю цифру 11,2. . Найдите двузначное число, равное сумме цифры ero десятков и квадрата цифры единиц. . Определ ите, ка кую цифру обозначает каждая буква в paBeH ствах v КИА Й == ХА, АхА == БАХ, ПИ П == или, АА н == == АННА и КАК == Б К . . Можно ли число 11, представить как разность квадратов двух натуральных чисел? . Найдите 11, таких различных целых чисел, что произведение любых п  1 из них будет делиться на оставшееся число. . Найдите натуральные числа, которые увеличиваются в дe вять раз, если в их записи между цифрой единиц и цифрой десятков вставляется нуль. . Найдите трехзначное число, квадрат KOToporo оканчивается тремя одинаковыми цифрами, не равными нулю. . Может ли сумма квадратов двух нечетных чисел быть KBa дратом целоrо числа? . Фрукты хранятся в ящиках по 16, 17 и 21 Kr. Как отrрузить 185 Kr, не вскрывая ящиков? . Решите уравнение х! + у! == (х + у)! в целых числах. . Решите уравнение 1! + 2! + ... + х! == у2 в целых числах. . Найдите все двузначные числа, обладающие следующим свой 
216 ством: если к сумме цифр двузначноrо числа добавить KBa драт этой суммы, то снова получится исходное число. . Найдите четырехзначное число, которое при делении на 131 дает в остатке 112, а при делении на 132  в остатке 98. . Подставьте в цепочку символов 42 * 4* вместо звездочек такие цифры, чтобы по лучивш ееся пятизначное число делилось на 72. . Известно, что ij * * * * 3  натуральное число. Найдите ero. . Из всех цифр от 1 до 9 составьте три трехзначных числа, про изведение которых будет наименьшим; наибольшим. . Найдите сумму всех четырехзначных четных чисел, которые можно записать цифрами О, 1,2, 3,4, 5 (одна и та же цифра в числе может повторяться). . В трехзначном числе зачеркнули первую цифру слева. Коrда преобразованное число умножили на семь, получилось исход ное трехзначное число. Найдите ero. . Может ли сумма цифр точноrо квадрата равняться п? . Найдите все такие числа, что первая цифра числа равна KO личеству нулей в ero записи, вторая  количеству единиц и т. д. вплоть до десятой цифры, равной количеству девяток. . Найдите четырехзначное число, являющееся полным KBaдpa том, в котором две первые цифры одинаковы и две последние тоже совпали. . Найдите все такие трехзначные числа, что сумма каждоrо чи сла и инвертированноrо числа (числа с теми же цифрами, но записанными в обратном порядке) есть полный квадрат. . Два двузначных числа, записанные одно за друrим, образу ют число, которое делится на произведение исходных чисел. Найдите эти числа. . Даны натуральные числа j, k, 1, т, п. Найдите все четвер ки натуральных чисел р, q, r, s, удовлетворяющих равенству jp+kq+lr+тs=n. . Дано целое неотрицательное число п, не превышающее мил лиона. Выведите фразу "п кроликов" (например, при п = 13 результатом должна быть фраза "тринадцать кроликов", а 
217 при n == 1999  "одна тысяча девятьсот девяносто девять кроликов"). . Дано k целых чисел al, а2, ..., ak. Вычислите наибольшее возможное значение суммы Smn == а т + ат+l + . . . + anl, rде 1 :S; m :S; n :S; k. Учтите: число k столь велико, что исходные числа занимают одну пятую часть памяти, отведенной для хранения данных, а на выполнение k 2 даже простейших опе раций не хватает времени. . k целых чисел al, а2, . . . , ak записаны по Kpyry. Их сумма paB на нулю. Определите максимальное значение суммы стоящих подряд чисел. . На маrнитной ленте записаны n попарно различных HaTY ральных чисел. Компьютер может перематывать ленту на Ha чало и считывать числа одно за друrим. Оперативная память компьютера может хранить только несколько (целых) чисел. Найдите наименьшее натуральное число, отсутствующее на ленте. Приведите алrоритм, который сделает это за мини мальное количество пере моток ленты. . Некоторое двузначное число кратно трем. Если между ero ци фрами вставить нуль и к преобразованному числу прибавить удвоенную цифру ero сотен, то получится число, в девять раз больше исходноrо. Найдите исходное число. . Найдите минимальное число, которое представляется суммой четырех квадратов натуральных чисел не единственным обра зом. . Найдите все обыкновенные правильные несократимые дроби, . знаменатели которых не превосходят семи. . Найдите все простые числа, не превосходящие n, двоичная запись которых представляет собой симметричную последо вательность нулей и единиц, начинающуюся единицей. . Определите все пары" соседних" простых чисел, не превосхо дящих n, троичные представления которых получаются друr из друrа записью цифр в обратном порядке (5 и 7  первая такая пара). . Определите, является ли периодической последователь ностью двоичная запись натуральноrо числа т, т. е. имеет 
218 ли она вид аа... а, rде а  некоторая непустая последова тельность. . Найдите все пары натуральных чисел а и Ь, не превосходя щих n, для которых а0Ь = Ь0а, rде операция 0 определяется так: а 0 Ь = а  Ь + а (mod Ь). 16. На сельской улице проживают (в собственных коттеджах) семьи Волковых, Зайцевых и Собачкиных. Они решили переселиться так, чтобы все Зайцевы жили в начале улицы, Собачкины  в середи не, а Волковы  в конце. Известно общее количество коттеджей на улице и кто живет в каждом коттедже. Составьте план переселения при условии, что каждая семья должна переезжать не более одноrо раза, в каждом обмене должны участвовать не более трех семей и коJ1ичество тройных обменов должно быть минимальным. 17. Соревнования по прыжкам в высоту проводятся по следующим правилам: если спортсмен сбивает планку, то он выбывает из даль нейшей борьбы; в противном случае  становится в конец очереди. Известно, что соревновались n человек; сначала они прыrали в по рядке своих номеров (от 1 до n); между двумя последовательными неудачами каждый раз было m удачных попыток; последним сбил планку спортсмен с номером k. Выведите номера прыrунов в том ПОрЯдке, в каком они сбивали планку (например, при n = 10, m = 3 и k = 8 ответом должны быть числа 7, 1,5, 10, 6, 3, 2, 4, 9, 8). 18. Создайте алrоритм, моделирующий: . проверку выиrрыша/проиrрыша в иrре "крестики  нолики"; . поведение пассажира лифта в типичных ситуациях, которые MorYT с пассажиром случиться; . работу микрокалькулятора. 19. На каждую чашу весов помещается по одной монете. Разрабо тайте алrоритм определения самой леrкой и самой тяжелой из 100 монет различной массы, если на чашечных весах без rирь можно сделать не более 150 взвешиваний. 20. Среди 1000 монет одна леrче друrих. Она фальшивая. Докажите, что нет способа, rарантирующеrо нахождение фальшивой монеты за шесть взвешиваний (на чашечных весах без rирь). Дайте алrоритм определения фальшивой монеты за семь взвешиваний. 
219 21. Среди 2n + 1 различных по массе монет найдите среднюю, т. е. такую, которая леrче n монет и тяжелее n оставшихся. Создайте алrоритм, позволяющий выполнить работу на чашечных весах без rирь не более чем за 100n взвешиваний. 22. В бухrалтерских расчетах нередко требуется найти день недели d w по дате или количеству дней между двумя датами nl и n2' Cдe лайте это, используя следующий алrоритм: пусть d  день, т  месяц и у  rОДj для января и февраля (т== 1,2) вычислите n, paB ное 365у + d + 31(т  1) + [(у  1)/4]  [з ([(у  1)/100 + 1])/4], а для остальных месяцев  равное 365у + d + 31(т  1)  [О.4т + 2.3] + [у/4]  [з ([у/100] + 1)/4]. День недели d w (О  суббота, 1  воскресенье и т. д.) найдите по формуле d w == n  7[n/7], а t::.d == 'nl  n21, rдe nl соответствует пер вой дате, а n2  второй. Определите день недели, приходящийся на начало HOBoro тысячелетия, т. е. на 1 января 3001 rода. 23. Подсчитайте количество суббот в месяце, если даны номер меся ца т (целое число от 1 до 12) и целое число У, равное выбранному rоду (учтите, что 2000 rод високосный). 24. Определите количество понедельников и пятниц по сезонам rода в 2002 rоду. 25. Вычислите длину столетия (к примеру, количество дней между 1 января 2001 rода и 1 января 3001 rода). 26. Внекотором реrионе n пунктов соединены авиационным сообще нием. Стоимость перелета из iro пункта в jй записана в матрице Р == (pij) (i, j == 1, 2, . . ., n). Составьте алrоритм определения стои мости полета из kro пункта в lй по самому дешевому маршруту (с возможными пересадками). 27. Решите следующие шахматные задачи. . Приведите алrоритм отыскания таких ходов шахматной фи rypbI (короля, ладьи, коня), посредством которых она после довательно обходит все клетки доски, посещая каждую из них ПО одному разу ([1]). 
220 . Предложите алrоритм расстановки 8 ферзей (16 королей, 8 ладей, 32 коней, 14 слонов) на доске так, чтобы они не били друr друrа. 28. Ознакомьтесь с расписанием местных авиалиний. Разработайте автоматизированную систему продажи авиабилетов. 
Кодирование алrоритмов 5 б 7 8 9 10 rрафики 11 Списки Кодирование линейных алroритмов Кодирование разветвлений Кодирование циклов Кодирование подчиненных алroритмов Составные типы Часть 11 
223 r лава 5 Кодирование v линеиных алrоритмов Цель этой части  дать краткий обзор трех наиболее употребитель ных языков проrраммирования: Паскаля (см. [17, 30, 34, 40, 43, 44, 54, 58, 59]), Си (см. [11, 24, 28, 46, 48, 49, 50, 56, 67]) и Фортрана (см. [4, 5, 6, 7,42,52, 62]). Проект алrоритма разработан. Теперь приступим к воплощению ero в конкретную проrрамму с использованием различных языковых средств. Наша первая nporpaMMa Приведем сначала примеры простых Паскаль, Си и Фортран проrрамм. Они выводят на экран дисплея здравицу "Vivat Russie!" ('Виват Россия!') и предназначены лишь для Toro, чтобы показать, как выrлядят проrраммы. program Pascal; begin write (' Vivat Russie!') end. #include <stdio.h> main ( ) 
224 { } puts (" Vivat Russie!"); program Fortran write (*, *) , Виват Россия!' end Отметим сначала, что во всех проrраммах ключевые (по друrому, служебные, предопределенные) слова языков выделены полужир ным прямым шрифтом, имена  курсивом, а строковые KOHCTaH ты  прямым шрифтом. Сделано это для большей наrлядности, удобочитаемости проrрамм. Сипроrрамма начинается с команды (директивы) препроцессора #include. Она подключает предопределенный (rоворят еще, заrо ловочный) файл stdio.h, обеспечивающий выполнение CTaHДapT ных действий по передаче данных. В имени файла аббревиатура std  от standard (стандартный), i  от input (ввод), о  от output (вывод), а расширение h  от head (заrоловок). В Паскаль и Фортранпроrраммах подобный сервис подключается автоматиче ски, по умолчанию. Все проrраммы содержат заrоловки: это program Pascal, main ( ) и program Fortran. В них Pascal и Fortran  выбранные нами име на проrрамм. Сипроrрамма имени не имеет (по определению). За заrоловком Паскаль и Фортранпроrрамм может следовать декла ративная часть. Здесь она отсутствует. В Сипроrрамме возможное местоположение декларативной части  перед заrоловком main ( ) и/или за левой фиrурной скобкой {. Исполняемая часть Паскаль и Сипроrрамм представляет собой co ставной оператор, состоящий из ОДНоrо оператора ВЫВода. В спис ке вывода находится строковая константа 'uuВиватuРоссия!', Слова begin и end, а также символы { и } по своему функциональному назначению являются открывающей и закрывающей операторными скобками. Заметьте, что Паскальпроrрамма заканчивается точкой. Исполняемая Часть Фортранпроrраммы содержит оператор вывода на экран и завершается оператором end. 
225 Алфавит языка Язык проrраммирования  это искусственный язык, предназначен ный для описания данных и их обработки на компьютере. Он являет ся средством общения между проrраммистом и компьютером. Разно образие языков проrраммирования велико, но каждый из них, как и любой естественный язык, обладает внешней формой (синтаксисом) и внутренним содержанием (семантикой). Язык проrраммирования имеет иерархическую структуру, нижний уровень которой образует алфавит. Выше в этой структуре находятся слова, затем выраже ния, потом предложения языка и, наконец, подпроrраммы и модули. Каждый более высокий уровень структуры формируется из элемен тов предыдущих уровней. Изучение любоrо языка начинают со знакомства с ero алфавитом. Так мы и поступим. Алфавит языка образуют три rруппы основных символов: цифры, буквы и специальные знаки. Пифры  это деся тичные цифры О, 1, . ..,9, двоичные О и 1 (Фортран), восьмеричные О, 1, ..., 7 (Си, Фортран) и шестнадцатеричные О, 1, ..., 9, А, В, С, D, Е, F. Последние шесть можно заменить символами а, Ь, с, d, е, f. К бу-к;вам относятся латинские буквы и знак разбивки . В Фортране буквой является еще и знак денежной единицы $. В Паскале и в Фортране прописные и строчные буквы не различаются (если только они не входят в символьные и строковые константы и комментарии). Кроме Toro, в текстах можно использовать кириллицу. Сnециа.л:ьные символы Паскаля  это символы 1 +  * / == , I . : ; < > [ ] ( ) { } А @ $ # и следующие пары символов <== >== <> . (* *) (. .) Сnециал'Ьные символы Си  это символы +*/==".:;<>[](){}A#"I%\? & а также пары и тройки символов <== >== !== ==== ++ // /* */ [] () > « »&& 11 ? +== == *== /== %== «== »== &== А== 1== ## :: .* >* l@  знак цены (коммерческое at); #  знак номера (хэшсимвол); &  амперсанд (коммерческое и); I  коммерческое или. 
226 И, наконец, специальные символы Фортрана  это символы +  * / ==,'..; < > () 11 %?! &\ и пары символов ** <== >== /== // (/ /) ==> Смысл их будет пояснен далее. В проrрамме составные символы разделять нельзя. Разделителями считаются пробел (пусто), конец строки и комментарий. !(онец стРО1Си и пробел не имеют rрафиче cKoro изображения (впрочем, при необходимости в тексте проrраммы пробел можно представлять символом u). В Паскале 1CoMMeHmapui1 начинается с символа { или (*, может содержать любые символы, например, концы строк, за исключением} или *), и заканчивает ся символом} или *). Подобным образом строится MH020cmpO"iHbli1 1CoMMeHmapui1 и в Си, но он начинается символом /*, а заканчива ется */. Кроме Toro, в Си определен oaHocmpO"iHbli1 1CoMMeHmapui1. Он должен начинаться с символа / /. в Фортране допускается толь ко oaHocmpO"iHbli1 1CoMMeHmapui1. Он начинается с восклицательноrо знака! или с символа с (с  начальная буква слова comment; она должна находиться в первой позиции строки проrраммноrо текста). Концевые знаки комментария }, *) и */ разрешены в строковых KOH стантах; там они являются элементами строковых значений. Словарь языка Словарь языков образуют ключевые (служебные) слова. Они пред назначены для описания свойств объектов проrраммы, для обо значения действий, стандартных (встроенных, предопределенных) функций, дескрипторов формата (форматных кодов) и т. д. В Typ бо Паскальсистеме служебных слов больше 2500, из них 48 (and, array, ..., xor) являются зарезервированными. Это значит, что их нельзя использовать в роли произвольно выбираемыIx имен (иден тификаторов). Компилятор прервет трансляцию при попытке при менить зарезервированное слово не по назначению. В словаре Си системы более 2300 служебных слов, причем 85 из них (asm, auto, ..., while) зарезервированы. Словарь Фортрана относительно CKpO мен. Он содержит больше 300 слов и не имеет зарезервированных. Тоrда, если в какойнибудь проrраммной единице Фортрана HeKOTO 
227 рые слова, скажем, Мах, Min, Sum выбраны в роли имен перемен ных, то стандартные функции тах, min и sum в этой проrраммной единице будут недоступны, поэтому (во всех языках) не стоит объ являемым объектам давать имена, совпадающие с какиминибудь словами языка. Константа Любые цепочки символов, над которыми можно выполнять опера ции, являются данными. Всякое данное имеет определенный тип. Типы данных в языках проrраммирования довольно изощренные: в Паскале  это простые (вещественный и порядковые  цe лый, лоrический, символьный, перечисляемый, диапазонный), co ставнъtе (массивовый, записной, множественный, файловый), У1Саза телъ, стРО1Совыi1, подпрО2раммныi1 и обое1Стнъti1 типЪtj в Си  это nycmoi1, С1Сал.я,рнъtе (арифметические  целый, вещественный, KOM плеКСНЫЙj символьный, перечисляемый, указатель и ссылочный), ФУН1Сци.я, и составнъtе (массив (в частности, строка), структура, объ единение и класс) типъt 2 j в Фортране  это 6строеннъtе (целый, вещественный, комплексный, лоrический, символьный), стРО1Совъti1, м,ассивовыi1, У1Сазателъ и производные (запись, объединение) типы. Каждый из составных, друrими словами, структурных данных в KO нечном итоrе строится из данных простых типов. Познакомимся с такими данными. Целое число Константа  один из элементов данных. Она имеет фиксированные тип и значение (СМ. подразд. "Тип данных" разд. "Данное" 2лавы 1). Любой компьютер обрабатывает арифметические данные  целые числа и десятичные дроби, умноженные, если нужно, на целую CTe пень десятки. При этом различают числа без знака и со знаком. Целое без зна1Са  это конечная цепочка цифр. Целыi1 тип в языках проrраммирования состоит из нескольких под типов, каждый из которых определяет свое подмножество целых дe 2Подруrому, типы Си разделяют на основные (void, char, int, float и double вместе с вариантами short, unsigned и long) и nроизводные (указатели и ссылки на друrие типы, массив, функция, структура, объединение и класс). 
228 сятичных чисел (см. табл. 5.1; в ней, в колонке Си не указан тип short int, эквивалентный типу int; типы перечислены по paHry, в порядке увеличения старшинства). Таблица 5.1. Целые типы данных Тип Длина, Диапазон Паскаль Си Фортран байт значений shortint  integeN 1 1 [128; 127] byte   1 [о; 255] integer int integer*2 2 [32768; 32767] word unsigned int  2 [о; 65535] longint long integeN4 4 [2147483648; 2147483647]  unsigned long  4 [о; 4294967295] Как видно из табл. 5.1, тип константы определяется по ее запи си. Так, если некоторое целое (см. колонку Паскаля) принадлежит промежутку [о; 127], то оно имеет тип shortint; если промежутку [128; 255], то  byte; если промежутку [256; 32767], то  integer; если промежутку [32768; 65535], то  word и, наконец, если про межутку [65536; 2147483647], то  longint. Если целое не принадле жит промежутку [2147483648; 2147483647], имеет место 'Цело'Чuсле1t ное nереnОЛ1tе1tuе. В константном выражении эта исключительная ситуация диаrностируется и выполнение проrраммы прерывается. Следствием выхода целых значений за rраницы диапазона COOTBeT ствующеrо типа будет невыполнение в компьютерной арифметике сочетательноrо и распределительноrо законов математики. Языки проrраммирования имеют средства обработки исключитель ных ситуаций. Так, директива Паскаля {$R+} и метакоманда $debug Фортрана задают контроль rраниц диапазонов значений пе ременных (и массивов); встроенный отладчик ТшЬо Pascal включа ется директивой {$D+}; в Си полезен ТшЬо Debugger и собственный обработчик matherrO. Все числа в памяти компьютера хранятся в двоичной системе счи сления. Целые числа представляются в естественной форме (в фор ме с фuх;сuрова1t1tоi1 то'Чх;оi1, но сама точка не изображается). Ha пример, данное типа longint (Паскаль), long (Си) и integer*4 (Фор тран) занимает 4 байта (32 бита) памяти (рис. 5.1). 
229 rsl цифры числа / longint, long, integer*4 зо О I цифры числа I unsigned long 31 О Рис. 5.1. Стандарт BHYTpeHHero представления целоrо данноrо Старший бит знаковоrо типа хранит знак числа. Если он раВен О, число положительное, если 1  число отрицательное. Беззнаковое число (uпsigпеdчисла) не имеет знаковоrо разряда S. Кроме десятичных чисел в языках проrраммирования определены числа в системах счисления, отличных от десятичной: в Паскале  это шестнад'Цатерu"tные "tuсла (число начинается с префикса $; см. Прuло:ж;енuе 2); в Си любая константа, начинающаяся с префикса О, считается BOCbMepu"tHoi1, а с префикса Ох или ОХ  шестнадцате ричной; в Фортране для задания числа в системе счисления с OCHO ванием от 2 до 36 нужно применять следующую форму записи: [ :i: } [ [основание } # } к;онстанта [де в записи к;онстанты с основанием от 11 до 36 вкупе с цифрами О, 1, . . . , 9 используются строчные или прописные буквы латинскоrо алфавита. При этом, если основание опущено, а символ # указан, то число будет шестнадцатеричным, а если опущен еще и символ #, то  десятичным. Числа Си MorYT содержать суффиксы: суффикс L или 1 явно YKa зывает на константу типа long, а суффикс U или u  на константу типа unsigned. Оба суффикса можно комбинировать в любом по рядке, например, 123L, 123U, 123LU и 123UL. Вещественное число Вещественное число имеет Две формы записи: фиксированную (с фик еированной точкой) и экспоненциальную (с плавающей точкой). Чи ело без знака в фuк;сuрованноi1 форме состоит из последовательно ети цифр, разделенной точкой на целую и дробные части (например, 123.4567). В Си и Фортране такое число может начинаться с точки и ею заканчиваться. Число в эк;сnонен'Цuалъноi1 форме состоит из MaH тиссы (числа в фиксированной форме) и экспоненты (символа Е или 
230 е и порядка числа  целой константы, количество цифр в которой не больше четырех; например, 123.4567еО, 12.34567е1 и т. д. При этом символ е (е  от exponential) следует читать как "умножить на 10 в степени"). Заметим, что если мантисса m удовлетворяет HepaBeH ству 0.1  Iml < 1, то она н,ормализован,а (к примеру, 0.1234567е3). Мантисса числа, представленноrо в н,ау'Чн,оuн,оmшции, удовлетворя ет неравенству 1  'т' < 10 (например, 1.234567е2). Экспоненци альную форму, как правило, используют при записи как слишком малых, так и слишком больших чисел (к примеру, 1 aHrcTpeM равен 1010 м, 1 см есть 0.01 м, а световой rод равен 9.46х10 15 м; в проrрамме соответствующие значения этих единиц длины можно представить в виде 1e10, 0.01 и 9.46е15). Кроме Toro, она удобна при выводе дaH ных, область изменения которых в процессе выполнения проrраммы неизвестна. Мантисса числа определяет точность ero записи (табл. 5.2). Таблица 5.2. Примеры записи числа 11' в экспоненциальной форме 7r 3.141593еО 3.1415926536еО 3.14159265358979еО 3.14159265358979324еО Число цифр 7 11 15 18 Ошибка 8. 7e8 1.5e12 1.2e 16 6.5e19 в третьей колонке табл. 5.2 приведено значение разности между 32 разрядным числом 7r и ero приближениями, записанными 7, 11, 15 и 18ю цифрами. Видно, чем больше цифр содержит мантисса, тем точнее представлено число 7r. Порядок задает наибольшее и наи меньшее число (по модулю). Действия над вещественными числами всеrда выполняются с He которой поrрешностью. Она обусловлена, вопервых, неточностью исходных данных (исходные данные  результаты измерений), BO вторых, невозможностью точно представить некоторые числа при замене их десятичными дробями (речь идет об иррациональных и трансцендентных числах (таких, как vf:2, 7r, е и пр.) и числах, не представимых точно в двоичной системе счисления (например, 
231 0.110 == 0.0(6314)8 == 0.000(110011001100)2; СМ. Прuлож;е'Н,uе 2)) и, втретьих, конечностью разрядной сетки компьютера. Количество цифр мантиссы в языках проrраммирования всеrда оrраничено сверху (скажем, 19ю цифрами). Числа с меньшей раз рядностью надо уметь правильно записывать. При этом число мож но либо усечь, либо окруrлить. Соответственно получим ошибки yce чения или окруrления. В обоих случаях лишние цифры числа отбра сывают, но при окруrлении результат корректируют: если первая OT брошенная цифра числа есть 5, 6, 7,8 или 9, то в последний разряд усеченноrо числа добавляют единицу. Окруrление числа предпочти тельнее усечения, так как поrрешность окруrления меньше (к при меру, представим константу 11" с семью значащими цифрами: сначала усечем 11" (получим 3.141592, ошибка равна 6.5e 7), а затем oKpyr лим (имеем 3.141593, ошибка равна 8.7e8)). Вещественное число независимо от точности записи всеrда хранится процессором в некотором приближении. Это, в частности, означает, что если при решении некоторой задачи должна, например, полу читься тройка, то в памяти компьютера она может быть предста влена с недостатком (к примеру, 2.999999), точно (3.000000) или с избытком (3.000001). Таким образом, ДВа числа, равные в услови ях обычной арифметики, перестанут совпадать в арифметике KOM пьютерной. Поrрешность, вызванная конечностью разрядной сетки, естественна (при этом мера точности с; приблизительно равна 1 on, rде n  количество цифр мантиссы хранимоrо вещественноrо чи ела). Итак, действия с вещественными данными всеrда дают неверные результаты, но насколько неверные, зависит от природы вычисле ний. Большей частью результаты достаточно правильны, чтобы ими можно было успешно пользоваться, однако иноrда ошибки бывают значительными. Речь идет о получении ненадежных цифр, сокраще нии (взаимном уничтожении значащих цифр при вычитании почти равных значений) и исчезновении числа (случай отрицательноrо пе реполнения), а также о переполнении ПОрЯДКа (результат деления на нуль или на близкое к нулю число). Большую часть ошибок, об условленных вещественной арифметикой, трудно обнаружить, Прав да, переполнение порядка  не такая серьезная проблема для про rраммиста. 
232 Теперь познакомимся с типами вещественных данных в языках про rраммирования. Каждый вещественный подтип определяет конечное подмножество множества R (см. табл. 5.3; в ней типы перечислены в порядке увеличения старшинства). Таблица 5.3. Вещественные типы данных Тип Длина, Число Диапазон mш Паскаль Си Фортран байт цифр порядка € single float real*4 4 78 [45; 38] 1.20х10 ,( real   6 1112 (38; 38] 9.10х 10lЗ double double real*8 8 1516 (324; 308] 2,23х 10lб extended long  10 1920 [4931; 4931] 1.09х 1019 double Как видно из табл. 5.3, в Паскале принадлежность числа KaKOMY либо подтипу определяется количеством цифр мантиссы и/или по рядка. Использование типов single, double и extended возможно при включенной директиве {$E+,N+} (сопроцессор 8087 OTCYTCTBY ет) или директивы {$N+} (сопроцессор наличествует). В Си при знаком числа типа double является присутствие в ero записи точки и/или символа е. При наличии суффикса F или f Сичисло имеет тип float, а при L или 1  long double. В Фортране число двойной точности (тип real*8 или, подруrому, double precision) должно быть записано в экспоненциальной форме, и при этом символ е Ha до заменить символом d (d  от double). Вещественные числа в памяти хранятся в двоичной системе. Фор ма их представления  экспоненциальная. Так, число типа double (Паскаль и Си) и real*8 или real(8) (Фортран) занимает 8 байтов (64 бита) памяти (рис. 5.2):  порядок I 6362 5251 .мантисса 'luсла I double, double, real*8 О Рис. 5.2. Стандарт BHYTpeHHero представления вещественноrо данноrо Мантисса TaKoro числа всеrда нормализована. 
2ЗЗ Комплексное число Комплексное число z == х + yi в Си имеет тип complex и преk ставляется как complex(x, у), а в Фортране  тип complex*8 или complex*16 и записывается как пара (х, у) (например, если z == 1, z == 1 + 2i и z == 2i, то в Си эти числа можно соответственно записать как complex(1., О.), complex(1eO,2eO) и complex(0.,2.); в Фортране они будут соответственно иметь вид (1dO, OdO), (1dO, 2dO) и (OdO, 2dO)). Паскаль не имеет комплексноrо типа и это не является недостатком языка (ответьте на вопрос: "Коrда вы в последний раз имели дело с комплексными числами?"). Этот тип в Паскале можно определить посредством записей (по друrому, структур). Но можно перейти на язык Си или Фортран и обработать комплексные дaH Ные. Такое решение проблемы кажется разумным. Окончательную оценку ему поставит практика. Лоrические константы Лоrические константы истина и ложь записываются в Паскале co ответственно как true и false, а в Фортране  как . true. и .false. В Си подобные константы отсутствуют (Си не имеет лоrическоrо типа). Вместо них можно использовать целые числа 1 и О. Символьная константа Символьная константа в языках проrраммирования  это любой символ, заключенный в апострофы (например, '*'  звездочка, "  пустой символ, ""  апостроф, '11'  двойная кавычка). Она имеет тип char (Паскаль, Си), character*1 (Фортран) и занимает в па мяти 1 байт. Код от О до 255 в этом байте определяет один из 256 возможных символов. Закрепление конкретных символов за кодами отображено в 1\,одовои таблице. Она является расширением таблицы 11 аски" (американскоrо стандартноrо кода для обмена информацией ASCII, дополненноrо кириллицей, rрафическими и друrими симво лами). В Паскале символьную константу можно представить, разместив за знаком # внутренний код символа (к примеру, #42  звездочка, #13  символ возврата каретки CR, #10  символ перевода строки LF). В Си определены специальные управляющие символы (напри мер, '\n'  односимвольный, '\n\t'  двухсимвольный; табл. 5.4). 
234 Таблица 5.4. Управляющие символы в Си Изображение '\а' '\Ь' '\f' '\п' '\r' '\ t' '\у' '\ \' '\" '\'" '\ ?' Реакция, смысл Звуковой сиrнал (а  от audible Ье11) Возврат на шаr, забой (Ь  от backspace) Новая страница (f  от form feed) Новая строка (п  от new line, line feed) Возврат каретки (r  от carriage return) rоризонтальная табуляция (t  от horizontal tab) Вертикальная табуляция (у  от vertical tab) Обратный слэш Апостроф (одинарная кавычка) Двойная кавычка Знак вопроса Кроме Toro, символьные константы '\000', '\001', ..., '\377' TpaKTY ются как коды BHYTpeHHero представления, заданные в восьмерич ной системе счисления (к примеру, '\052'  звездочка *, '\025'  Э, ' \ 033'  +----- ' \ 036' . ' \ 037'   ' \ 362'  > ' \ 363'  < ' \ 366'  -т , , , , , , '\367' , '\370'  о, '\373'  V' '\374'  n, '\375'  2, '\376'  8). Фортран допускает использование управляющих символов Си, но они должны заключаться в апострофы и заканчиваться буквой с (например, '\t'c  rоризонтальная табуляция, '\r\n'c  новая CTpO ка). Отметим эквивалентные типы Фортрана: integer и integer*4, real и real*4, complex и complex*8, logical и logical*4, character и character* 1. Строковая константа Строковая константа  это любая последовательность символов, за ключенная в апострофы (Паскаль, Фортран; например, 'Даламбер' и 'd" Alembert') или двойные кавычки (Си, Фортран; например, "Дa ламбер" и "d' Alembert"). В Паскале #13#10 и #13#10'uuBce...'  тоже строки. Дадим примеры одинаковых строк: 
235 LJ Паскаль . ' uu Theuend . . .' . 'uuThe'+'uend.,.' LJ Си . 11 uu Theuend . . .11 . luu The " "u end .. ,11 LJ Фортран . ' uu Theuend , , " . 'uuThe'jj'uend".' Строка имеет тип string{rlJ} (Паскаль), char[] (Си) и character*l (Фортран), rде 1  максимальная ДЛИНа строки, Имя Слова проrраммы делятся на две rруппы: ключевые слова (они за ранее известны в системе) и слова, определяемые проrраммистом (имена меток, констант, типов, переменных, объектов, функций, про цедур, модулей, полей и проrрамм). Имя  это, с одной стороны, синтаксическая единица (должно строиться по правилам синтакси са), а с друrой  семантическое понятие (должно нести смысло вую наrруЗКуj это важно для тех, кому придется читать проrрамму, включая caMoro проrраммиста). Правила формирования имени Ta КОВЫ: LJ имя должно начинаться с буквы, за которой может следовать произвольная конечная цепочка буквенноцифровых символов и знака разбивки (например, InJ, SиP, MonteCarlo, RиngeJ(иttaA); LJ в роли имени нельзя использовать ключевые слова. Длина имени произвольна, но значимыми являются только первые 32 символа. Напомним, что в Си прописные и строчные буквы раз личаются. Переменная Переменная имеет фиксированное имя, фиксированный тип и пере 
236 мен ное значение. В проrрамме переменная представляется именем. Тип  одно из фундаментальных понятий любоrо языка проrрамми рования. Он задает множество значений, которые может принимать переменная данноrо типа, форму представления ее значений в па мяти компьютера и операции над переменной. Тип связывается с именем посредством объявления. В соответствии с ним компилятор резервирует некоторую область памяти, rде будут храниться TeKY щие значения переменной. Все объявления размещаются в деклара тивной части проrраммы. Объявление простых переменных в Паскале Познакомимся с объявлением переменных в языках проrраммирова ния. Начнем с объявления простых переменных в Паскале. Любой пор.ядх:овый тип данных определяет конечное и упорядоченное MHO жество значений, которые отображаются на последовательность по рядковых номеров О, 1, ... (кроме целых чисел; они отображаются сами на себя). В каждом типе существует минимальное и макси мальное значения. Для любоrо значения, кроме минимальноrо, есть предшествующее значение, и кроме максимальноrо  последующее значение. Вещественные типы также задают конечное количество значений, но их столь MHoro, что сопоставить каждому значению ero номер не представляется возможным (в соответствии с предназна чением таких данных это и не надо делать). Пусть слово тип именует любой из простых типов Паскаля или какойнибудь новый тип, определ.яе'мЫЙ просра'м'мистом. Тоrда в разделе объявления переменных var (от variable) можно написать var Vl, V2, . . . , V N : тип; Например, если внекоторой проrрамме переменные 1, J, К, L, М, N должны быть длинными 'Целыми, А, В, С  одинарной то'Чности, D, Е, F  двойной то'Чности, Р, Q, R  лоzи'Чесх:ими и И, V, W  символьны,Ми, то соответствующее объявление может иметь вид: var 1, J, К, L, М, N : longint; А) В, С : single; D, Е, F : double; Р, Q, R : Бооlеап; И, V, W : char; Отметим, что термин "Bool ean " происходит от имени анrлийскоrо 
237 математика Джорджа Буля (G. Boole), опубликовавшеrо в 1854 r. работу, ставшую началом алrебры лоrики (Булевой алrебры). Строr.;овые nереме'Н:н,ые (короче, cmpor.;u) Vl, V2, . . . , v n определяют ся так: var Vl, V2, ..., V N : string[[l]J; rдe 1  длина строки (1  1  255). Например, строки И и V MaK симально возможной длины (1 == 255 байтов) и строку W из 80ти символов можно объявить как var И, V : string; W: string [80]; Строка в Паскале трактуется как цепочка символов. К любому из них можно обратиться, как к элементу одномерноrо массива array[O..l] of char. Первый байт строки содержит текущую дли ну строки. Он имеет индекс О (например, длина строки И равна ord(U[O])). Первый символ строки хранится во втором байте, имеет индекс 1 и т. д. до lro символа, имеющеrо индекс l и содержащеrося в (l + 1 )M байте. Используя Паскаль, проrраммист может создавать свои порядковые и:пы двух видов: nере"iиСЛ'я'ем'Ыu и диаnазо'Н:н,ыu. Первый задает упо рядоченное множество значений перечислением в круrлых скобках имен констант, разделенных запятой. Само определение типа долж но находиться в разделе определения типов, которое начинается сло вом type, содержит им,Я, типа, знак равно и тип: type им,Я, типа == тип; Например, определение type LighCtype == (Red, Amber, Green); утверждает, что любая переменная типа Lighttype может иметь oд но из трех указанных значений и никаких друrих. Компилятор co поставит Red номер О, Amber  1 и Green  2. Тип LighCtype можно использовать в разделе объявления переменных, к примеру, так: var Trafficlight : LighCtype; Заметим, что оба определения леrко объединяются в одно: . var Trafficlight : (Red, Amber, Green); но в большинстве практических случаев предпочтительнее отделять определения типов от объявлений переменных. Наложив оrраничения на некоторый порядковый тип, можно полу 
238 чить новый порядковый тип, диаnаЗО1t1tыi1. Он определяется двумя константами (rраницами), задающими диапазон значений этоrо ти па. Нижняя и верхняя rраница должны разделяться двумя точками, например: type Months == (Dec, Jan, Feb, Mar, Apr, М ау, Jun, Jul, Aug, Sep, Oct, Nov); var Winter: Dec .. Feb; Spring : Mar .. Мау; Summer : Jun .. Aug; Autumn: Sep .. Nov; Здесь, в частности, тип переменной Winter задается путем указания необходимоrо диапазона значений. Вот еще один пример: type Size == 1 .. 80; var Mark : 1 .. 5; Continue : 6 .. 6; Statement : 7 ., 72; Emptiness : 73 .. 80; Comment : 1 .. 80; Lengthline : Size; Перечисляемый и диапазонный типы усиливают надежность Пас кальпроrрамм, так как любое значение переменной, не принадле жащее объявленному списку или диапазону значений, будет зафик сировано как ошибка. Объявление скалярных переменных в Си Теперь объявим скалярные переменные в Си. Сначала введем лоrи ческий тип, используя переименование типов typedef: typedef cmapbti1 тип H06'bli1 тип; Тип Logical определим на типе unsigned: typedef unsigned Logical; Тоrда объявление простых переменных (см. выше) может иметь сле дующий вид: long 1, J, К, L, М, N; float А, В, С; double D, Е, Р; Logical Р, Q, R; char И, V, W; complex Х, У, z; Тип char является типом целый. Данное типа char может paCCMa триваться компиляторм и как данное со знах:о,М (signed char), и как 
239 данное без зна'/Са (unsigned char). Если тип char трактуется как signed (форму данноrо можно установить либо явно, либо по умол чанию [28, 48, 55, 67]), то старший бит ero кода определяет знак. В этом случае [128; 127]  диапазон значений типа char. В случае unsigned char все восемь битов рассматриваются как код, а диапа зоном возможных значений будет [о; 255]. В Си отсутств ует (cTporo rоворя) строковый тип. Стро'/Су символов можно определить как массив элементов типа char или посредством указателя (ссылки) на символ. Так объявление char v [l + 1]; заставит компилятор зарезервировать область памяти для 1 симво лов строки v. Первый символ строки имеет индекс О. Он занимает первый байт памяти. Последний, 1й символ строки имеет индекс 1  1. Ero хранит 1й байт. Нулевой символ '\0' (нультерминатор), отмечающий конец строки v, компилятор разместит в последнем, (1 + 1) м байте памяти. Строке v, определенной выше как массив сим волов, нельзя назначить значение в операторе присваивания. Зато этоrо можно добиться в самом объявлении или, например, посред ством функции gets (v);. Обобщим объявление строковых перемен ных V1, v2, . . ., v n : char V1 [11 + 1], V2 [12 + 1], о.., V n [1n + 1]; Тоrда, например, строки И и V из 255ти символов каждая и 80ти символьную строку W можно объявить так: char И [256], V [256], W [81]; Пере'Числ,Я,емыi1 тип данных используется в Си для создания MHe монических, "rоворящих" имен целых чисел. Они разрешены в Bыpa жениях, rде допустимы данные целоrо Типа. Этот тип можно ввести несколькими способами. Один из них таков: enum иМ,Я, типа {списо'/С пере-ч,ислени,Я,}; enum имя типа V1, V2, ..., V n ; Списо'/С пере'Численu.я состоит из разделенных запятыми имен KOH стант, которым можно назначить начальные значения. Если этоrо не делать, компилятор сам присвоит первому имени нулевое значе ние, второму  единицу и т. д. Например, определим тип LighCtype и объявим переменную TrafficJight: enum LighCtype {Red, Yellow, Green}; 
240 епиm LighCtype Trafficlight; В соответствии с приведенным объявлением значение Red равно О, Yel10w  1 и Green  2. Объявление простых переменных в Фортране И, наконец, объявим простые переменные в Фортране. Объявление переменных типа целый и вещественный в этом языке может быть нея6ныM и Я6НЫМ. При неявном объявлении типа действует "ij klтn правило". Оно означает следующее: при отсутствии явноrо объявле ния с именем переменной связывается тип integer*4, если первая буква имени есть i, j, k, [, т или п. В противном случае (имя начи нается с одной из букв а, Ь, ..., h, о, р, . . . , z) тип переменной будет real*4. Неявное задание типа является анахронизмом в языке. Оно делает Фортранпроrрамму ненадежной, так как увеличивает Bepo ятность ошибок и мешает выбору мнемонических имен (например, при вычислении силы Р==М *А, rде М  масса, а А  ускорение, в случае неявноrо объявления возможная дробная часть значения массы будет отсечена). Везде ниже откажемся от неявноrо объявле ния. Если при этом в каждой проrраммной единице написать опера тор implicit попе, то любая переменная, тип которой не установлен явно, вызовет сообщение об ошибке во время компиляции. Если словом тип назвать любой из встроенных типов или CTpOKO вый тип Фортрана, то простая форма объявления типа переменных V1, V2, ..., V N имеет вид munr ZJ V1r [у, V2f lJ, ..., Vnr [п} rде [, [1, [2, .. . , [n  длина значений (в байтах). К примеру, дадим объявление простых переменных (см. выше): integer 1, J, К, L, М, N real А, В, С dou Ые precision D, Е, F logical Р, Q, R character И, V, W complex Х, У, Z Заметим, что данные двойной точности можно объявлять по друrому, указав в байтах длину значений переменных *8 после сло 
241 ва real (!  общий параметр длины; действует на все переменные Vi (i == 1,2, ..., п)) или за любым именем переменной Vi*8 (li  локаль ный параметр; действует только на переменную Vi (i == 1, 2, ..., п), отменяя указание общеrо параметра l). Тоrда, например, третье предложение (см. последнее объявление) можно заменить на: real*8 п, Е, F или на: real п*8, Е*8, F*8 Более Toro, второе и третье предложения можно объединить в одно: real А, В, С, п*8, Е*8, F*8 В расшuрен:н,О1l форме объединенное предложение выrлядит следу ющим образом: real :: А, В, С, п*8, Е*8, Р*8 СтрО1СО6'Ые nеремен:н:ые Vl, V2, ..., V N В Фортране объявляются так: character!* ZJ Vl!* [у, V2!* [у, . . ., v n !* [тj rде любой из параметров длины принимает значения в диапазоне от 2 до 32767. Вот, к примеру, одно из возможных объявлений строк И и V (длина каждой из них равна 255ти символам) и 80ти сим вольной строки W: character*255 И, V, W *80 Каждый символ строки имеет свой номер: первый  номер 1, BTO рой  2 и т. д. Задание констант ... и начальных значении Задание констант и начальных значений, как правило, "выrодно и удобно". Оно, способствуя реализации правила "поменьше маrи ческих чисел в исполняемой части проrраммы", делает проrрамму (почти) универсальной. Константы и начальные значения в Паскале в Паскале определены функция pi типа real и две стандартные KOH станты: maxint, равная 32767, и maxlongint, равная 2147483647. 
242 Любые друrие константы (нетUnUЗUРО6аннные Vl, V2, . . ., V N И ти nUЗUрО6анные Ul, и2, ..., и т ) можно задать в разделе определения констант так: const Vl==6ыраЭfCенuеl; V2==6ыраЭfCенuе2;"'; V п ==6ыраЭfCенuе n ; Ul: mUnl==6ыраЭfCенuе 1; ...; И т : тUn m ==6ыраЭfCенuеm; В 6ыраЭfCеНUUj и в 6ыраЭfCенuuj (i==l, 2, ..., njj==l, 2, о.., т) раз решены арифметические операции, отношения и лоrические ОПера ции, а также следующие функции: abs, chr, Ы, length, 10, odd, ord, pred, ptr, round, sizeof, succ, swap, trunc. К примеру, зададим максимально возможную длину Lim OДHOMep Horo массива, новую линию (строку) Nl, отрезки прямых Оnе и Two, удвоенное 7r, модуль Юнrа Е и коэффициент Пуассона J1. для стали: const Lim == 100; Nl == #13#10; Оnе == ''; Two==' ' ; Twopi : double == 2.0 * pi; Е: double == 2.06е6; Ми: double == 0.29; Константа не может изменяться в ходе выполнения проrраммы. Теперь запишем число Непера с 17ю цифрами после точки. Процес сор будет хранить ero в некотором приближении (см. результаты): {$N+ } program Primitiveerrors; const Nl == #13#10; ENapier : extended==2.7182818284.5904.523; ENapiervar: extended; var begin ENapiervar:==exp( 1.0); writeln(NI, ENapier:19:17, end. Nl, ENapiervar:19:17) Результаты выполнения проrраммы таковы: 2.71828182845904523 2.71828182845904524 Если ваш компьютер не оснащен арифметическим сопроцессором, скорость обработки данных всех вещественных типов примерно оди 
243 накова. Коrда же сопроцессор наличествует, использование, к при меру, типа real требует дополнительноrо времени на преобразование real к типу extended, поэтому не используйте тип real на компью тере с сопроцессором. Арифметический сопроцессор всеrда обраба тывает значения так, как будто бы соответствующие переменные бы ли объявлены типом extended. Три остальных вещественных типа (single, real, double) в этом случае получаются простым усечени ем результатов до нужных размеров (и применяются в основном для экономии памяти [58]): {$N+ } program Types; const Nl : string == #13#10; var Pir : realj Pid: doublej Pie: extendedj begin Pir:==pi; Pid:==pi; Pie:==pi; writeln(NI,' Pi...r==', Pir, " " Pir:19:17, Nl, , Pid==', Pid, " " Pid:19:17, Nl, , Pie==', Pie, " " Pie:19:17) end. Pi...r == 3.14159265358830Е+ОООО, 3.14159265358830453 Pid == 3.14159265358979Е+ОООО, 3.14159265358979312 Pie == 3.14159265358979Е+ОООО, 3.14159265358979324 К этим двум проrраммам можно будет вернуться после знакомства с вводом/выводом в Паскале. В Паскале начальные значения переменным задать нельзя. Константы и начальные значения в Си в заrоловочном файле Си <values.h> перечислены 21 CTaHдapT ная константа MAXINT, MAXLONG и т. д. Их значения приведены выше (см. колонку "Диапазон значений" табл. 5.1). Константа RANDMAX равна 32767 (см. <stdlib.h». Файл <limits.h> содержит список из 15 констант (от CHARBIT, paB НОЙ 8 (число битов В байте), дО ULONGMAX, равной 4; 294 967 295 (максимальное значение для unsigned long)). Файл заrоловков <math.h> содержит имена следующих математических констант: /j ME е /j MLOG2E log2 е 
244 CJ MLOG 10Е loglo е CJ MLN2 ln 2 CJ MLNI0 ln 10 CJ MPI 1r CJ MPI2 1r/2 CJ MPIA 1r/4 CJ M1PI 1/1r CJ M2PI 2/1r CJ MlSQRTPI 1/ .Ji CJ M2SQRTPI 2/ .Ji CJ MSQRT2 v2 CJ MSQRT 2 V2/2 нетuпuзuрова1i'н,ыle 1Со'Н,ста'Н,тъ! определяются директивой #define. Это делается так: #define uм.я з'Н,а1.{,е'Н,uе Она в тексте проrраммы заменяет каждое вхождение име'Н,и на з'Н,а 1.{,е'Н,ие (например, #define True 1 #define False О). тuпuзuрова'н,'н,ыle 1Со'Н,ста'Н,тъ! задаются модификатором const. COOT ветствующее объявление может иметь вид: const тип ul==выlаже'н,uеl,, u2==выlаже'н,uе2,, ..., um==выlаже'н,uеm ; ; Слово тип можно не указывать. Тоrда будет выбран установленный по умолчанию тип int. В выlаже'н,uujj (j == 1, 2, . . ., т) разрешены арифметические операции, отношения, лоrические операции и CTaH дартные функции языка. на1.{,алъ'н,ыe з'Н,а1.{,е'Н,u.я переменным Vl, V2, . . ., V N можно назначить в их объявлении. Делается это следующим образом: тип Vl ==выlаже'н,uеl,, v2==выlаже'н,uе2,, . . . , vn==выlаже'н,uеn ; ; Например, зададим значения констант (см. примеры выше), а также объявим константу с == J1r /2 и две переменные УО и io, начальные значения которых суть 0.03 и 1.2: #define Lim 100 const char Оnе[] == " Two[] == 11 const double Twopi == 2.*MPI, Е == 2.06е6, Ми == .29, C==sqrt(MI2); 11 , 1 '. , double Уа == .03, ТО == 1.2; Константы и начальные значения в Фортране Фортран имеет фУ'Н,1С'ЦU'/О pi. Для зада'Н,u'я' 1Со'Н,ста'Н,т Vl, V2, . . ., и n 
245 предназначен оператор parameter. Он имеет следующий синтаксис: parameter (Vl==З1и'Чениеl, V2==зна'Чение2, ..., vn==зна'Чение n ) Строкиконстанты произвольной длины (в частности, формальные параметры) удобно объявлять в модификации оператора charac ter*( *). Тоrда длина строки определяется по ее значению. На'Чалъное зна'Чение переменной можно задать либо в ее объявлении, либо в операторе data. В случае data любое имя Vi (i == 1,2, ..., п) может быть списком имен переменных, именем или элементом Mac сива, подстрокой или циклическим элементом. Константу нужно окаймить слэшами и разместить за именем Vi. Перед нею можно записать коэффициент повторения k*, rде k  отличное от нуля целое без знака. Например, объявим константы и переменные (см. примеры выше), а также переменную Zo, начальное значение которой есть 2.4: integer Lim character*( *) Опе, Two, Nl real*8 Pi, Twopi, Е, Ми, YO/3d2/, TO/1.2dO/, ZO parameter(Lim == 100, Nl == '\r\n'c, + Оп е == ' + Two == ' + Pi == 3.141592653589793dO, + Twopi == 6.283185307179586dO, + Е == 2.06d6, + Ми == .29dO) data ZO/2.4dO/ , , , , Здесь при записи фраrмента Фортранпроrраммы использована фик сированная форма представления исходноrо кода. В роли символа продолжения текста строки проrраммы выбран знак +. При свобод ной форме, если строка текста завершается символом &, то следу ющая строка является строкой продолжения. Контрольныii вопрос Верно ли написано (Фортран): data Pi, Е, Ми/3.141593, 2.06е6, .29/ Ответ Верно при условии, что тип Ми есть real. 
246 Стандартные функции Стандартные функции предназначены для вычисления значений Ma тематических и лоrических функций, выполнения операций преобра зования, получения псевдослучайных чисел, времени и даты, обра ботки символов, строк, массивов (Фортран), ввода/вывода, битов и адресов, для динамическоrо распределения памяти, работы с Tep миналом, rрафических работ, поиска и сортировки (Си). Обраще ние к любой функции (выов6 фу1t'Ции) выполняется посредством ее имени, за которым в круrлых скобках записывается aprYMeHT (или aprYMeHTbI, разделенные запятой). AprYMeHToM может быть BЫ ражение языка. Ero значение должно принадлежать области опре деления функции, например, D(log) == R+, D( j) == Ro, D(tg) == == (7rk  7r /2; 7rk + 7r /2), k Е Z и т. д. Но так как в процессоре можно представить только конечное подмножество действительных чисел, то, например, D(exp) #- R и W(exp) #- R+. AprYMeHTbI триrономет рических функций задаются в радианах. Предопределенные функции и процедуры Паскаля Список предопределенных функций и процедур Паскаля содержит больше полусотни наименований. Познакомимся сначала с .мате.мати'Ч,еси.ми фу1t'Ци-я.ми. Функция abs(x) находит Ixl, arctan(x)  arctgx, cos(x)  cosx, ехр(х)  ех, frac(x)  {х}, int(x)  [х], ln(x)  lnx, pi  7r, sin(x)  sin х, sqr(x)  х 2 И sqrt(x)  у'Х. Тип результата будет тот же, что у aprYMeHTa х для функций abs( х) и sqr( х); для всех остальных функций тип результата  extended (используется сопроцессор), в противном случае тип  real. Четыре представленные ниже функции относятся к фу1t'Цu.я.м npe образова1tи-я. CJ Функция chr(x), rде aprYMeHT х типа byte, возвращает символ с заданным порядковым номером х. CJ Функция ord( х) возвращает порядковый номер, соответствую щий значению х порядковоrо типа: О или 1 для лоrическоrо х, целое от О до 255  для CTpoKoBoro х и целое от О до 65535  для перечисляемоrо х (к примеру, если написано объявление 
247 type LighCtype == (Red, Orange, Green); то ord(Orange) вернет 1). (J Функция round( х) окруrляет значение х вещественноrо типа до ближайшеrо целоrо. (J Функция trunc( х) отсекает дробную часть значения х веществен Horo типа. Тип результата функций ord(x), round(x) и trunc(x)  longint. К роме Toro, явное преобразование типа значения х можно выпол нить, используя имена типов, например, так: shortint( х), byte( х), integer(x), word(x) и longint(x), rдe х  выражение типа целый. rруппу функ'Цui1 и nро'Цедур nорядковоzо тиnа составляют пять сле дующих подпроrрамм. (J Функция odd(x) выдает true, если целое хнечетно, и false, если х четно. (J Функция pred(x) возвращает предшествующее значение aprYMeH та (например, pred(Orange) даст Red). (J Функция succ( х) возвращает последующее значение aprYMeHTa. Тип результата функций pred(x) и succ(x) совпадает с типом aprYMeHTa. (J Процедура dec(xf, !:::.}), rдe тип !:::.  longint, уменьшает значе ние переменной х на величину !:::., а если aprYMeHT !:::. не задан  на 1 (т. е. в последнем случае действие процедуры эквивалентно оператору х:== xl или х :==pred(x)). (J Процедура inc(xf, !:::.}) действует подобно процедуре dec, увели чивая значение переменной х на величину !:::.. Перечислим несколько функ'Цui1 разноzо назна'Ч,енuя. (J Функция high( х) возвращает максимальное значение порядково ro типа. (J Функция low( х) возвращает минимальное значение порядковоrо типа. (J Функиия random[( n )}, rде n имеет тип word, возвращает псев дослучайное число (если параметр n опущен, результат  веще ственное число из промежутка [о; 1); если указан  целое чис 
248 ло из промежутка [о; n  1]). Для rенерации различающихся по следовательностей псевдослучайных чисел предназначен опера тор randomize. Он, используя текущее время, сообщаемое KOM пьютером, задает начальное случайное число. CJ Функция sizeof( х) возвращает число байтов, занимаемьiх apry ментом х. Тип результата функции  word. В заключение рассмотрим две фаil'лО6'blе фу'Н:к:'Цuu. CJ Функция eof(f) возвращает true, если указатель конца файла находится вслед за последним элементом файла, и false  в противном случае. CJ Функция eoln(f), rде f  текстовый файл, возвращает true, если текущая файловая позиция находится на маркере конца строки или вызов eof(f) возвратил значение true. Во всех друrих ситу ациях значением функции будет false. Если f  стандартный файл (input, output), то синтаксический элемент и) можно опустить. Предопределенные функции Си Список маmеМаmu'Чес'/Сuх фун'/С'Цui1 Си содержит более 60ти имен. Их прототипы описаны в заrоловочных файлах <math.h> и <stdlib.h>. AprYMeHTbI всех функций (кроме функций abs, frexp, labs, ldexp, poly, powl0 и random) объявлены типом double. Все функции (кроме функций abs, labs, rand и random) возвращают значения типа double. Функции, имена которых снабжены суффик сом 1, предназначены для обработки данных типа long double. CJ Функция abs(x) типа int возвращает jxl; тип aprYMeHTa должен быть int. CJ Функции acos(x) и acosl(x) вычисляют arccosx. CJ Функции asin(x) и asinl(x) вычисляют arcsinx. CJ Функции atan( х) и atanl( х) вычисляют arctg х. CJ Функции atan2(x,y) и atan21(x,y) вычисляют arctgx/y. CJ Функции ceil( х) и ceill( х) находят r х 1 = min n. nX CJ Функции cos( х) и cosl( х) вычисляют CoS х. CJ Функции cosh(x) и coshl(x) вычисляют chx. 
249 о Функции ехр(х) и expl(x) вычисляют е Х . О Функции fabs(x) и fabsl(x) возвращают Ixl. о Функции floor(x) и floorl(x) находят lxJ == mахn. nX О Функции fmod(x,y) и fmodl(x,y) вычисляют х mod у, т. е. Haxo дят остаток от деления х на у. При у==О результат равен О. О Функции frexp(x,&y) и frexpl(x,&y) из значения х выделяют нормализованную мантиссу т и несдвинутый порядок r. Тип r есть int. Мантисса возвращается функцией, а порядок помещает ся в область памяти, на которую указывает у. Найденные зна чения удовлетворяют соотношениям т х 2 Т и 0.5  т < 1. Опера ция "адрес" & дает адрес cBoero операнда. Ее результатом явля ется указатель на операнд. О Функции hyp ot(x,y) и hypotl(x,y) вычисляют длину rипотену зы, равную V X2 + у2. о Функция labs(x) типа long возвращает Ixl; тип aprYMeHTa  long. о Функции ldexp(x, r) и ldexpl(x, r) возвращают число, сформиро ванное по заданным мантиссе хинесдвинутому порядку r: хх2Т, 0.5x < 1. Тип r есть int. о Функции log(x) и logl(x) вычисляют lnx. о Функции log10(x) и log101(x) вычисляют 19 х. О Функции modf(x,&y) и modfl(x,&y) вычисляют [х] и {х} числа х. Дробная часть со знаком числа возвращается функцией, а цe лая часть размещается в области памяти, на которую указыва ет у. О Функции poly(x, n, а) и polyl(x, n, а) для заданных х, порядка n (тип n  int) и массива коэффициентов а (а  массив ао, аl, ..., а n ) вычисляют значение полинома рn(х) В точке х рn(х) == аnх n + an1xn1 +... + аlХ + ао. LJ Функции pow(x,y) и powl(x,y), rде х == у i- О, вычисляют х У . Если х < О, значение у должно быть целым, большим единицы. о Функции powl0(n) и powl01(n) вычисляют 10 n . Тип n  int. о Функция rand() возвращает псевдослучайное число типа int, 
250 принадлежащее промежутку [о; RANDMAX]. Начальное зна чение случайноrо числа задается оператором randomizeO;. Определения rand и randomize находятся в файлах <stdlib.h> и <time.h>. О Функция random(n), rде aprYMeHT n типа int, возвращает псеВДО случайное число Toro же типа, принадлежащее промежутку [о; n1]. О Функции sin(x) и sinl(x) вычисляют sinx. О Функции sinh(x) и sinhl(x) вычисляют shx. о Функции sqrt(x) и sqrtl(x) вычисляют у'Х. О Функции tan(x) и tanl(x) вычисляют tgx. О Функции tanh(x) и tanhl(x) вычисляют thx. Файл <complex.h> содержит определения фун:к:'Цuil обработк:u К:OM nлек:с'ныx да 'н 'н 'blX . Речь идет о функциях abs, acos, arg, asin, atan, conj, cos, cosh, ехр, imag, log, log10, norm, polar, pow, powl0, real, sin, sinh, sqrt, tan и tanh. Их aprYMeHTbI должны быть KOM плексными (кроме функции polar, тип ее aprYMeHToB есть double). Комплексными будут и значения функций (исключая функции abs, arg, conj, imag, norm и real, результаты выполнения которых  double). о Функция arg(z) вычисляет rлавное значение aprYMeHTa KOM плексноrо числа z == х + yi (7r < arg z:::;; 7r). О Функция conj(z) возвращает z == х  yi. О Функция imag(z) возвращает Imz == у. о Функция norm(z) вычисляет jzl2 == х 2 + у2. о Функция polar(r, 'Р) возвращает комплексное число, имеющее модуль r и значение aprYMeHTa, равное 'Р. О Функция real(z) возвращает Re z == х. Преобразова'Нuе тиnа з'Наче'Нu,я, х можно выполнить, используя име на типов, например, так: (unsigned int)(x), long(x), (unsigned long)(x), rде х  выражение типа целый, и float(x), double(x), (long double)(x), rде х  выражение типа вещественный. Опера ция sizeof(x), rде х  тип, выдает размер (в байтах) выражения или типа х (например, 1 == sizeof(l.l) == sizeof(l.L) ==10 байтов). 
251 В файлах <stdio.h>, <io.h> и <conio.h> перечислены средства noaaepJfC"'"u ввода/вывода. LJ EOF  специальная константа, равная  1, используемая при проверке конца файла. LJ Функция feof(J) проверяет состояние конца файла в потоке. Если при чтении из потока будет достиrнут конец файла f, то feof(J) возвращает нуль; в противном случае вернет ненулевое значе ние. К стандартным относятся файлы stdin, stdout, stderr и stdprn. Предопределенные функции и процедуры Фортрана Одной из важнейших целей разработки языка Фортран было созда ние удобных средств для научных приложений, облеrчающих напи сание проrрамм. Поэтому в языке определен большой набор (больше сотни) стандарных функций и процедур. Мате.матu'Чес","uе ФУН","ЦUU имеют универсальные и специальные имена. При вызове функции по унuверсально.му и.мени aprYMeHT может быть любым допустимым. Тоrда тип значения функции будет совпадать с типом aprYMeHTa. При обращении по сnецuально.му и.мени тип aprYMeHTa должен co ответствовать типу, установленному для этоrо имени. Введем следу ющие обозначения: LJ целый i (integer*l, integer*2, integer или integer*4), i*l (integer*l), i*2 (integer*2) и i*4 (integer*4); LJ вещественный r (real или real*4, double precision или real*8), r*4 (real*4) и r*8 (real*8); О лоrический [ (logical* 1, logical*2, logical или logical*4), [*1 (logical*l), [*2 (logical*2) и [*4 (logical*4); LJ комплексный с (complex или complex*8, complex*16), с*8 (complex*8) и с*16 (complex*16). Функции нахождения абсолютНО20 зна'Ченu.я Определение Вызов функции Тип aprYMeHTa Тип Функции Jxl abs(x) i, r или с тот же, что ух, для c r*4 или r*8 
252 iabs(x) dabs( х) r*8 r*8 Izl (z=x+yi) cabs( z) с r*4 или r*8 cdabs(z) с*16 r*8 Три20пометри ч,ес'/Сuе функции Определение Вызов функции Тип aprYMeHTa Тип функции sшх sin( х) r или с тот же, что У х dsin(x) r*8 r*8 sшz csin(z) с*8 с*8 cdsin( z) с*16 с*16 cos х cos ( х ) r или с тот же, что У х dcos(x) r*8 r*8 cos z ccos( z) с*8 с*8 cdcos(z) с*16 с*16 tgx (x:j:.1rk+1r/2) tan(x) r тот же, что У х dtan(x) r*8 r*8 arcsin х (lxJ  1) asin( х) r тот же, что У х dasin(x) r*8 r*8 arCCos х (lxJ  1) acos(x) r тот же, что У х dacos( х) r*8 r*8 arctg х atan(x) r тот же, что У х datan( х) r*8 r*8 arctgx/y atan2(x, у) r тот же, что У х, У (lxl+lyl>O) datan2(x, у) r*8 r*8 ctg х (x:j:.1rk) cotan(x) r тот же, что У х dcotan( х ) r*8 r*8 sh х sinh(x) r тот же, что У х dsinh(x) r*8 r*8 chx cosh(x) r тот же, что У х dcosh(x) r*8 r*8 th х tanh(x) r тот же, что У х dtanh(x) r*8 r*8 
253 Функции вычисления эх:сnон,ен,ты Определение Вызов Функции Тип aprYMeHTa Тип функции е Х ехр ( х ) r или с тот же, что У х dexp(x) r*8 r*8 e Z cexp(z) с*8 с*8 cdexp( z) с*16 с*16 Функции вычисления н,атуралън,О20 ЛО2арuф.ма Определение Вызов функции Тип aprYMeHTa Тип Функции lnx (х>О) log( х) r или с тот же, что У х alog(x) r*4 r*4 dlog(x) r*8 r*8 ln z (z;i:O) clog( z) с*8 с*8 cdlog( z) с*16 с*16 Функции вычисления дес.ятU'iн,О20 ЛО2арuф.ма Определение Вызов Функции Тип aprYMeHTa Тип функции 19x (х>о) log10(x) r тот же, что У х alogl0(x) r*4 r*4 dlogl0(x) r*8 r*8 Функции вычисления х:вадратн,О20 х:орн,.я Определение Вызов функции Тип aprYMeHTa Тип Функции у'х (xO) sqrt( х) r или с тот же, что У х dsqrt( х) r*8 r*8  csqrt( z) с*8 с*8 cdsqrt(z) с*16 с*16 
254 Тип aprYMeHTa универсальных функций (sin, cos, tan, atan, atan2, cotan, sinh, cosh, tanh, ехр, log, log10 и sqrt) может быть i. Функции вычисления .ма1l:сu.малъноzо значенuя Определение Тип aprYMeHTa Тип функции Вызов функции maX(Xj, Х2, ..., Х n ) maX(Xl, Х2, ..., Х n ) maXO(Xj, Х2, ..., Х n ) amaxl(Xl, Х2, ..., Х n ) amaXO(Xj, Х2, ..., Х n ) maxl(Xj, Х2, ..., Х n ) dmaxl(Xl, Х2, ..., Х n ) z или r тотже,ЧТОУХl"" r*4 r*4 r*4 r*4 r*8 r*8 Функции вычисления .мuнu.малъноzо значения Определение Тип aprYMeHTa Тип функции Вызов функции min(Xj,X2, ...,Х n ) min(xj, Х2, ..., Х n ) minO(xl,x2, ...,Х n ) aminl(Xj, Х2, ..., Х n ) aminO(Xj, Х2, ..., Х n ) minl(Xj, Х2, ..., Х n ) dminl( Xj, Х2, ..., Х n ) z или r тот же, что у Xl,," r*4 r*4 r*4 r*4 r*8 r*8 Функции 01l:руzления Определение Вызов функции Тип aprYMeHTa Тип функции [ХХ 0.5] anint( х) r r (+ при Х  О) dnint(x) r*8 r*8 ( при Х < О) nint( х) r idnint( х) r*8 rxl = mш n ceiling( х) r nx lxJ = тах n floor( х) r nx 
255 Функции усечения Определение Вызов функции Тип aprYMeHTa Тип функции [х] aint(x) r r dint(x) r*8 r*8 Функции передачи зна'К:а Определение Вызов функции Тип aprYMeHTa Тип функции sign(x, у) == sign(x, у) l или r тот же, что У х, у == sgnyxJxl isign(x, у) dsign(x, у) r*8 r*8 Функция вычисления произведения двойной точности Определение Вызов функции Тип aprYMeHTa Тип функции хху dprod(x, у) r*4 r*8 Функции вычисления остат'К:а от деления Определение Вызов функции Тип aprYMeHTa Тип функции х mod у (у#О) mod(x, у) l или r тот же, что У х, У amod(x, у) r*4 r*4 dmod(x, у) r*8 r*8 Функции вычисления nоложител'Ьной разности Определение Вызов функции Тип aprYMeHTa Тип функции xy при х>у, dim(x, у) i или r тот же, что У Х,у 
256 иначе О idim(x, у) ddim(x, у) r.8 r.8 Функции преобразования к типу целыi1 Определение Вызов функции Тип aprYMeHTa Тип функции [х] int(x) ж, r или с intl(x) ж, r или с i.l int2(x) i, r или с i.2 int4(x) i, r или с i.4 intc(x) ж, r или с целыit Си ifix( х ) r.4 hfix( х) i, r или с i.2 jfix( х ) ж, r или с i.4 idint(x) r.8 Если aprYMeHT  комплексное число, то результатом функции бу дет усеченное значение действительной части aprYMeHTa. Функция intc( х) преобразует х к типу целый в смысле языка Си. Функции преобразования к типу вещественныi1 Вызов функции Тип aprYMeHTa Тип Функции real( х ) i, r или с r.4 float(x) r.4 sngl( х ) r.8 r.4 dble( х) i, r или с r.8 dreal( z) с.16 r.8 dfloat (х ) i, r или с r.8 Если aprYMeHT  комплексное число, то результат функции  пре образованная действительная часть aprYMeHTa. 
257 Функции преобразования к типу -к:о.мпле-к:с1tыi1 Вызов функции Тип aprYMeHTa Тип функции cmplx(x{y}) l, r или с с*8 dcmplx(x{ у}) i, r или с с*16 Если указан только один aprYMeHT, то при действительном х резуль татом функции будет комплексное число z == х + Oi. Функции для работы с таблицеi1 -к:одов Вызов функции Тип aprYMeHTa Тип функции ichar( х) char(x) character (х Е [о; 255]) character Функции получения M1tuMoi1 'Части о.мпле-к:с1tО20 'Чuсла Определение Вызов функции Тип aprYMeHTa Тип функции у = 1т z imag(z) с r*4 или r*8 aimag(z) с*8 r*4 dimag(z) с*16 r*8 Функции получения сопр.яже1t1tО20 о.мпле-к:с1tО20 'Числа Определение Вызов функции Тип aprYMeHTa Тип функции z = х  yi conjg( z) с*8 с*8 dconjg( z) с*16 с*16 Приведем еще несколько стапдартных средств Фортрана. а Оператор саН randomnumber(x) возвращает псевдослучаЙlfое 
258 число х или массив х таких чисел из полуинтервала [о; 1). Тип х должен быть r. LJ Оператор саН randomseed устанавливает стартовое случайное значение в зависимости от системноrо времени. LJ Функция eof(f), rде f  имя устройства, присоединенноrо к фай лу на диске (тип f есть i), даст .true., если достиrнут конец файла, и .false.  в противном случае. Стандартный файл ввода имеет имя 5, а вывода  6. Из девяти функций запроса 'Чuсловых хара-ктеристи-к упомянем лишь о функции epsilon(x), выдающей компьютерный е. Тип ap rYMeHTa х  r. Контрольноезание Для х типа r*8 (Фортран) напишите вызов функции сиrнум (см. разiJ. "Мноzозна'Чное ветвленuе" zлавы 2). Ответ sign(1dO,x) или dsign(1dO,x). Арифметическое выражение в зависимости от вида последней выполняемой операции выраже ние может быть арuфметu'Чес-кuм, лоzu'Чес-кuм или с'Цеnле1tuем. Лю бое такое выражение строится из nервu'Чных выраженuf1, к которым относятся константа без знака, переменная, элемент массива или записи (структуры), вызов функции и выражение в скобках. Из пер вичных с помощью знаков операций формируются составные Bыpa женuя. Арифметическое выражение представляет собой правило (формулу) для нахождения числа. Перечислим знаки арифметических опера ций (табл. 5.5). 
259 Таблица 5.5. Знаки арифметических операций Операция Паскаль Си Фортран плюс + + + минус умножить на * * * разделить на / / / разделить нацело на div / / остаток от деления mod % нет в степени нет нет ** Операции плюс и минус MorYT быть одноместными З (применяют ся к одному первичному выражению, например, +2, 2) и двy .местными (связывают два операнда, к примеру, 2 + 3, 2  3). ДBY местные плюс и минус образуют rруппу операций сложения (адди тивных операций). К двуместным относятся также операции YMHO жения и деления (мультипликативные операции). Операция цело- 'Ч,исленноzо деления возвращает целую часть частноrо (например, 2 div 3 == О, 2/3 == О). Деление по модулю дает остаток от целочислен Horo деления (2 mod 3 == 2  (2 div 3) * 3 == 2; 2 % 3 == 2). В Фортране нет такой операции, но зато определена функция mod(a, Ь) (и Torдa mod(2, 3) == 2). В Паскале нет операции возведения в степень, поэто му при положительном основании следует пользоваться основным лоrарифмическим тождеством: а Ь == ехр(Ь * ln(a)). В Си в степень возводит функция pow(a,b) (например, ij2"==exp(1.0/3.0*ln(2.0))== == 1.25992104989487316 при задании форматноrо кода : 19 : 17, pow(2., 1./3.) == 1.259921049894873 при задании формата %17.151f и 2.**(1./3.) == 1.259921). Для битовоrо представления целоrо числа k определены операции сдвиzа на n позиций влевовправо (k shl n и kshrn  Паскаль; k«n и k»n  Си) и т. д. Приведем правила записи и вы'Числения зна'Чениi1 выражениi1: а LJ выражение записывается линейно (например, дробь Ь в проrрам ме должна принять вид А/В); LJ в выражении знак "умножить на" между сомножителями опус ЗОдноместная, или унарная; двуместная, или бинарная; трехместная, или тернарная. 
260 кать нельзя (например, формула ах + Ь должна представляться как А * Х + В); LJ перенос части выражения можно выполнять в любом ero месте; к примеру, в выражении А + В + С + D + Е можно сделать такой перенос: А + В + С+ D+E LJ скобки исключают двусмысленность и ошибки; они использу ются, вопервых, для соблюдения семантических правил (к при а меру, формулу а ЬС надо представить как А**(В*С); дробь Ьс сле дует записать в виде А/(В*С), т. е. знаменатель дроби, если он не является первичным выражением, надо заключать в скобки; а+Ь дробь  d следует закодировать в виде (A+B)/(C+D), а дробь с+ аЬ  d  в виде (A*B)/(C+D) или в виде A*B/(C+D)). BOBTOpЫX, с+ для соблюдения синтаксических правил (к примеру, формулу ab следует писать как А**( B), т. е. два знака операций не долж ны стоять рядом или иначе  показатель степени следует писать в скобках, кроме случая (по желанию проrраммиста), коrда по казатель степени является первичным выражением (см. пары и тройки символов в разд. "Алфавит язых;а" ранее в этой rлаве)). И, втретьих, для указания порядка выполнения операций (Ha пример, в выражении (А + В) + С сначала подсчитывается сумма А + В, а в выражении А + (В + С)  сумма В и С); LJ порядок выполнения операций можно задать не только явно (скобками), но и неявно, пользуясь правилами языка: при OT сутствии скобок после вычисления значений функций сначала выполняется операция наивысшеrо, первоrо paHra (**; например, выражение  А**2 эквивалентно выражению  (А**2)), затем операции BToporo paHra (*, /, div, mod, %) и, наконец, опера ции TpeTbero paHra +, ; например, выражение А + В * C**D эквивалентно выражению A+(B*(C**D)), т. е. формуле a+bc d ); LJ если выражение содержит несколько последовательных операций наивысшеrо paHra, то они выполняются в порядке справа налево (например, выражения А**В**С и А**(В**С) тождественны; 
261 LJ в выражении допускаются данные различных типов, при этом все операнды преобразуются к наивысшему по paHry типу (см. табл. 5.1 и 5.3); операции +,  и * дают целый результат для целых операндов, в противном случае (хотя бы один операнд вещественный), результат будет вещественным (напомним, что в Си старший тип  complex, а в Фортране  complex*16); в Паскале при выполнении операции / получается веществен ное значение (например, 1/2==0.5); в Си и Фортране операция / для целых числителя и знаменателя означает "разделить и OT бросить дробную часть частноrо" (поэтому 2/3==0, 1*2/2==1, но 1/2*2 == О, т. е. при целочисленном делении нельзя утверждать, что I*J/I<==I/I<*J); операции div, mod и % определены для целых операндов и дают целый результат; заметим, что если а кратно Ь, то, например, А%В==О; целый результат для целых операндов даст и операция ** (к примеру, 2**3==8, а 2**( з)=о, так как по определению степени 2**( 3)==1/2**3=1/8==0; однако 2.**3==8., 2.**(3)==1.j8.=.125). Операциям + и , выполняемым над вещественными данными, Bce [да предшествует выравнивание порядков операндов: мантисса чи сла с меньшим порядком денормализуется, т. е. сдвиrается по раз рядной сетке сумматора вправо так, чтобы порядки операндов cpaB нялись. Это действие может привести к потере значащих цифр (по этому, например, в общем случае А+В+С == (А+В)+С =1 А+(В+С); действительно, 1е30+ 1000000 1е30 = О, в то время как 1e30 1е30+ +1000000 = 1е6 (Паскаль)). При MHoroKpaTHoM добавлении к боль шому числу малых величин результат может остаться неизменным. Сложение сначала двух малых чисел, а затем добавление б6льшеrо даст более точный результат. Здесь MHoroe з ависи т от квалиф икации проrраммис та. Та к, ф ормул ы Уl == 108 Х ( V х 2 + 1  V х 2  1) и У2 = = 2 х 108/( v x2 + 1 + v x2  1) математически эквивалентны. Однако при х = 1 вычисления на компьютере дадут Уl == У2 = 1.414214х10 8 , а при х == 108  Уl == О, У2 = 1 (Си). Отметим исключительные ситуации, ведущие к прерыванию выпол нения проrраммы. При делении А/В, [де В =1 О, опасно значение В, близкое к нулю, так как в случае малоrо по модулю делителя частное может оказаться вне области значений переменных веще CTBeHHoro типа (см. табл. 5.2). Исключительная ситуация возникает 
262 при вычислении значения выражения А**В, коrда А или при А < О и вещественном В. ОиВО Контрольноезание b + у! Ь 2  4ас Закодируйте формулу 2а Ответ (B + sqrt(B * В  4.0 * А * С))/(2.0 * А) (B + sqrt(B * В  4. * А * С))/(2. * А) (Паскаль) (Си, Фортран) (учтите следующую ситуа Приведите друrие решения этой задачи цию: Ь велико, а а и с малы). Оператор присваивания Предложения языков проrраммирования делятся на невыnолняемые и выполняемые, причем первые (объявления) описывают xapaKTe ристики и структуру данных, их способ редактирования, а также вводимые в употребление константы, типы, подчиненные алroрит мы (функции, процедуры) и их библиотеки ( модули); вторые (опе раторы) определяют действия. Операторы MorYT быть nростыми и сложными. Простые операторы не содержат внутри себя друrих опе раторов, а сложные включают таковые (и не только простые). к про стым относятся операторы присваивания, ввода/вывода, останова, паузы (Фортран), пустой, перехода, прерывания, продолжения, про- цедуры, возврата, открытия, закрытия, "перемотки" файла и (дина мическоrо) размещения. Все остальные операторы языков  слож- ные (составной, условный, выбора, цикла и присоединения, причем последний определен только в Паскале). Составной оператор Паскаля имеет вид begin onepamOPl; оnератОР2; . . .; оnераторn end в Си  это { onepamOPl; оnератОР2; ...; оnераторn; } Здесь begin, end и {, } иrрают роль операторных скобок. Конструкция вида 
263 обо,я,влени,я, begin оnераторыl end в Паскале и { обо,я,вленUJt операторы} в Си называется блок:ом. Фортран подобных средств не имеет. В Паскале и Фортране (при свободной форме записи проrраммы) операторы разделяются символом; (в Паскале точка с запятой, KpO ме Toro, разделяет секции формальных параметров, и ею заканчи ваются простые предложения в разделах объявлений, а также  функции и процедуры). В Си точка с запятой является частью опе ратора (ею оператор заканчивается 4 ). Оператор можно разместить в нескольких строчках, но в Фортране перед строкой продолжения должен стоять символ &. Любому оператору (кроме описательных операторов Фортрана) можно придать метк:у, что позволит ссылаться на такой (помечен ный) оператор в командах перехода. Метка  это либо им,я, (Па скаль, Си), либо номер (Паскаль, Фортран), причем в Паскале HO мер должен принадлежать отрезку [1; 9999], а в Фортране  отрезку [1; 99999]. Местоположение метки  перед оператором, но в Паска ле и Си она должна отделяться от оператора двоеточием. Метки mI, т2, . . . , т п в Паскале объявляются только явно  в разделе описа ния меток label вида label mI, т2, ..., т п ; а в Си и Фортране  всеrда неявно. В Фортране сложные опера торы MorYT снабжаться еще и дополнительным именем. Оно через двоеточие пишется в заrоловке оператора и в ero концевой части (например, им,я, : if . .. end if им,я,). Имя может присутствовать и в простых операторах (к примеру, exit им,я, и cycle им,я,) , а также в пунктах then, else и case. Самый употребительный оператор в проrрамме  это оператор npи сваивани,я,. Он имеет вид LJ Паскаль v :== а 4Составной оператор Си не должен заканчиваться точкой с запятой, а если она написана за закрывающей Фиrурной скобкой, это означает, что перед точкой с запятой стоит пустой оператор. 
264 CI Си v == а; CI Фортран v==a и служит для присваивания значения выражения а переменной v или имени функции v (в Паскале и Фортране). Знаки :== и == чи таются как "присвоить значение". В Си допускается "MHoroKpaTHoe присваивание" : Vl == V2 == . . . == V n == а; Типы пере мен ной v и значения а в случае обработки арифметиче ских данных MorYT различаться. Тоrда перед присваиванием значе ние а редактируется в соответствии с типом переменной v. В Па скале недопустимым является присваивание для v типа целый и а типа вещественный. Например, рассмотрим следующие фраrменты проrрамм: О Паскаль var У : single; J: longint; begin У :== 2.999999; J:== У; CI Си { float У; long J; У == 2.999999; J == У; CI Фортран real У integer J У == 2.999999 J==Y Они определяют значение У, равное 2.999999, и значение J, равное 2 (Си, Фортран). Паскалевский оператор J :== У синтаксически He верен. Если по условию задачи требуется окруrленное значение У, то оператор J :== У надо заменить оператором J :== round(Y). Иде 
265 альный случай, коrда v и а совместимы по присваиванию. Подчеркнем отличие математической записи Х == Х + 1 от предло жения языка Х == Х + 1. Запись Х == Х + 1 является уравнением, множество корней KOToporo пустое. Запись Х == Х + 1 есть оператор присваивания. В ero левой части Х является мишенью, а в правой  источником. Следовательно, оператор Х == Х + 1 представляет co бой формулу вида Хновое == Хстарое + 1, но не уравнение Х == Х + 1. Он назначает переменной Х новое значение, равное Х + 1. в Си список операций арифметики и присваивания расширен. Так, к целочисленной переменной можно применить одноместную ОПера цию увеличения на единицу (операцию и'Н:х;ремента ++; например, 1 + +; и + + 1;) или уменьшения на единицу (операцию дe'/CpeMeH та ; например, 1 ; и I;). Они MorYT быть nостфи'/Ссными (к примеру, 1 == 1; J == 1 + +; / / J == 1, 1 == 2) и nрефи'/Ссными (I == 1; J == + + 1; / / 1 == 2, J == 2). Эти операции быстротечны. Дополнительными операциями присваивания являются + ==,  ==, * ==, /==, %==, «==, »==, &==, А== И 1== (тоrда, например, вместо оператора Х == Х + 1.; можно написать Х + == 1.;). Стандартный ввод/вывод Решение даже простой задачи на компьютере не обходится без опе раций ввода/вывода. Ввод данных  это передача информации от внешнеrо носителя (с клавиатуры, дискеты, винчестера, микрофо на, сканера, видеокамеры и т. д.) В процессор, а вывод  переСЫk ка в обратном направлении (на экран, дискету, винчестер, принтер, плоттер, наушники и пр.). Под фаi1лом будем понимать поимено ванную область памяти на диске, хранящую некоторые однотипные данные. В ряде случаев под файлом подразумевают устройство, KO торое может выдавать или получать информацию (к примеру, экран, принтер, клавиатура). Для доступа к файлу необходимо определить файловую переменную. Любой проrрамме на любом языке доступны два предварительно объявленных файла со стандартными фаi1ло вы.ми nеременными: в Паскале  это input, output, в Си  stdin, stdout, в Фортране  5 и 6, причем первые (input, stdin и 5) предназначены для ввода данных с клавиатуры, а вторые (output, stdout и 6)  для вывода на экран. 
266 Ввод/ вывод в Паскале Ввод с клавиатуры в Паскале осуществляют процедуры read и readln (здесь ln  аббревиатура от line feed: перевод строки). Они имеют переменное число параметров и вызываются операторами nроцедур вида read(Vl' V2, о.., V n ) readln( Vl, V2, . о ., V n ) readln rде Vl, V2, . о ., V n  элементы списка ввода (переменные или эле менты структурных данных целоrо, вещественноrо, символьноrо или CTpOKOBoro типа). При своем выполнении процедура read ожидает набора значений этих переменныхо Набираемые числа должны OT деляться друr от друrа хотя бы одним пробелом или переходом на следующую строку. После набора они высвечиваются на экране (в "режиме эхо"), а нажатием клавиши ввода (Enter) назначаются пере менным Vl, V2, ..., v n . Возможные начальные пробелы у чисел иrно рируются. Типы значений и соответствующих переменных должны совпадать. Приведем пример ввода значений трех переменных типа real: X==lo7, У==2.0 и Z==З.О. Справа от проrраммы даны варианты набора констант: program Askj var Х, У, Z : real; begin read(X, У, Z); writeln( Х, У, Z) end. LJ le 7u2.uЗ. (Enter) LJ le7u2. (Enter) З. (Enter) LJ le 7 (Enter) 2. (Enter) З. (Enter) Если в проrрамме несколько операторов процедуры read, то данные будут вводиться потоком. Процедура readln отличается от процедуры read тем, что после счи тывания значения V N из буфера клавиатуры курсор в случае readln автоматически перейдет на начало новой строки экрана, и, может быть, следует начать или продолжить набор данных. Этой же процедурой вводятся символы и строки. Окаймляющие апо строфы в них не набираются. Каждый символ, каждая строка долж на находиться на новой строчке. Снова приведем пример. Пусть Te 
267 перь Х == 1.0, У == 2.0, U == 'и', V == 'Вуе', W == 'Все' и Z == 3.0. Имеем проrрамму: program Askprime; var Х, У, Z : real; И: char; V, W : string[3]; begin readln(X, У); readln(U); readln(V); read(W, Z); { readln(W, Z); } writeln(X, У, 'uu', и, 'uu', V, 'uu', W, Z) end. А это варианты набора значений: C:J 1.u2. (j 1. C:J 1.u2. C:J 1. C:J 1.u2. C:J 1. u 2. u 2. u 2. Вуе u Вуе u Вуе u Все3. Вуе Bceu3. Вуе Все Вуе Все3. Bceu3. 3. Все 3. Оператор nроцедуры readln без параметров пишут обычно в KOH це проrраммы для задержки до нажатия клавиши (Enter) . Однако если предыдущий ввод запрашивался процедурой read, то никакой задержки не будет. Перечислим в дополнение средства управления лавиатуроi1. Они принадлежат модулю crt, поэтому сначала надо выполнить KOMaH ду uses crtj. Речь идет о двух функциях (без параметров): первая из них, readkey, считывает символ из буфера клавиатуры и возвраща ет значение типа char (при этом вводимый символ не отображается на экране, что широко используется для создания экранных интер фейсов типа "меню" и друrих приложений), вторая, keypressed, воз вращает true, если была нажата какаянибудь клавиша, и false  в противном случае. Модуль crt имеет также nроцедуру O'l{,UCmu эрана clrscr (от анrл. clear screen). Процедуры write и writeln выводят на экран числа, символы, CTpO ки И лоrические значения. Операторы nроцедур вывода имеют сле дующий вид: write(Vl, V2, ..., V n ) writeln(vl, V2, ..., v n ) 
268 writeln [де Vl, V2, . . ., V n  элементы списка вывода (выражения целоrо, Be щественноrо, символьноrо, CTpoKoBoro или лоическоrо типа). Пер вый из операторов предназначен для размещения в одной строчке нескольких значений (если это возможно, в противном случае BЫ вод продолжается на новой строчке), второй  для вывода данных и перевода курсора (или печатающей rоловки принтера) в начало следующей строчки, а третий  для перехода к первой позиции HO вой строчки. Например, при выполнении фраrмента проrраммы write(' После'); write(' родноrо'); writeln(' языка'); writeln(' анrлийский  второй язык'); writeln(' цивилизованноrо человека.'); получим следующий результат: uПослеuродноrоuязыка uuuuuuuанrлийскийuuвторойuязык uuuuuuuuuuuuuцивилизованноrоuчеловека. Все операторы используют неявно заданные форматы. Форма преk ставления определяется типом значений выражений Vl, V2, ..., V n . При этом целые числа выводятся в фиксированной форме (шири на поля вывода зависит от числа; см. табл. 5.1), вещественные  в экспоненциальной форме и научной нотации (при типе real без co процессора ширина поля w равна 17 позициям, из них 10 позиций отведены для дробной части (d==10) и 2  для модуля порядка (см. табл. 5.2); при наличии сопроцессора для данных всех веществен ных типов w==23, d==14 и 4 позиции зарезервированы для модуля порядка), символы выводятся по одному, строка  полностью, а ло rические значения  в виде TRUE или FALSE. Выводимые данные сцепляются (кроме вещественных положительных чисел: знак + не выводится и получается, что они разделяются одним пробелом), по этому в роли элемента списка вывода рекомендуется "отступ" uu и " R R " даже двоинои отступ uuuu. Рассмотрим теперь форматный вывод. В операторах процедур write и writeln после любоrо выражения V можно записать через ДBoe точие выражение w, задающее ширину поля вывода (тоrда элемент списка вывода примет вид V : w), а при вещественном типе и фик сированной форме записи значения V  через двоеточие еще и BЫ 
269 ражение d, указывающее количество цифр в дробной части v (тоща имеем синтаксическую конструкцию v : w : d, rде w>dO). Значения выражений w и d (перед использованием) должны быть целыми. Если значение v  lразрядное целое без знака, то при истинном неравенстве wl поле вывода перед первой цифрой числа будет за полнено wl пробелами; в противном случае (истинно условие w<l) число выводится полностью. Отрицательное целое при wl+l BЫ водится с wll начальными пробелами; в противном случае  полностью (см. табл. 5.1). Формат числа с фиксированноi1 точкоi1 таков: CJ начальные пробелы (возможно, ни одноrо); CJ знак минус, если число отрицательное; CJ цифры перед точкой; CJ точка; CJ d цифр после точки. Таким образом, по этому формату в поле шириной w выводится зна чение v с d цифрами после точки. Данное прижимается к правой rpa нице поля. В зависимости от значения d дробная часть либо допол няется справа нулями, либо ее цифры отсекаются (с окруrлением). Если d == О, то дробная часть и точка не выводятся, а число прини мает форму целоrо (возможно, окруrленноrо). Коща ширина поля w больше необходимой, левые позиции поля заполняются пробелами (этим обстоятельством можно пользоваться для разделения чисел). Если большое (по модулю) число не помещается в поле шириной w (параметр w мал), информация не теряется: поле вывода aBTOMa тически расширится до необходимых размеров и в силе останутся перечисленные выше правила, касающиеся дробной части. Приве дем пример: CJ х == 1.234567е2 writeln('uuX==', Х:8:4); writeln('uuX==', Х:10:4); writeln('uuX==', Х:9:3); writeln('uuX==', Х:5:0); writeln('uuX==', Х:5:4); CJ Результат uu X ==123.4567 uu X ==uu 123 .4567 uu X ==uu 123 .457 uu X ==uu 123 uuX== 123.4567 При х == 1e7 результатом выполнения вышеприведенноrо фраrмен 
270 та проrраммы будут одни нули. Формат числа с плавающей точкой таков: (j знак числа (либо u, либо ); (j первая цифра мантиссы (1, 2, . . ., 9); (j точка; (j остальные цифры мантиссы; (j буква Е или е; (j знак порядка (+ или ) j (j две цифры порядка (MorYT быть три и даже четыре). Таким образом, число с плавающей точкой всеrда состоит, по край ней мере, из восьми символов (к примеру, оператор процедуры writeln(le  7 : 8) выдаст u1.OE  07). Если w мало, вещественное число перед выводом окруrляется (например, имеем элемент спис ка вывода 7.777777е2 : 1 и результат u7.8E + 02). Количество цифр мантиссы после точки оrраничено числом 6 для типа single, 10  типа real, 14  типа doиble и 17  типа extended (см. табл. 5.2 и 5.3). Приведем пример вывода больших и малых чисел. Вывод co провождается явно и неявно заданными форматами: program PascalfioatJorтat; var х, У : real; [: word; begin Х :==1234567.0; у:==х; for [:==1 to 13 do begin writeln( У:13, 'uu', у); У:== У * 0.1 end end. ul.2345б7Е+Обuuul.2345б70000Е+Об ul.2345б7Е+О5uuul.2345б70000Е+О5 u........... .uuu................ ul.2345б7ЕОбuuul.2345б70000ЕОб Отметим следующий факт: так как w и d по определению  выраже ния, то в Паскальпроrрамме леrко строить переменные форматы. Если v  символ, то должно выполняться неравенство w  1. Тоrда в поле вывода перед символом разместятся w 1 пробелов (к примеру, 
271 вместо набора 13 пробелов перед словом "цивилизованноrо", можно написать writeln('u':13, 'цивилизованноrо человека.');). Если v  стро'К:а длины 1, то при выполнении условия w1 перед строкой будут выведены w1 пробелов; в противном случае (w<l) строка выводится полностью. Для true и false соответственно должны выполняться неравенства w4 и w5; в противном случае будут выведены слова TRUE и FALSE без лидирующих пробелов. Данные, коrда их MHoro 5 , можно 'Читать с дис'К:а иjили писать на дис'К:, подключив порты ввода! вывода. Для этоrо надо в командной строке набрать и выполнить одну из трех команд имя nрО2раММНО20 фаi],ла.ехеu< имя 660дНО20 фаi],ла u>и.мя 6Ъt60дH020 фаi],ла имя nрО2раММНО20 фаi],ла.ехе u < имя 660дНО20 фаi],ла имя nрО2раММНО20 фа i],ла. exeu > имя 6Ъt60дH020 фа i],ла Файл исходных данных должен размещаться в рабочем каталоrе, а имя файла результатов появится там после завершения работы про rpaMMbI. Если набрать »имя 6Ъt60дH020 фаi],ла, то выводные данные будут добавлены в 6Ъt60дHOй фаi],л (существующий или несуществую щий). B6oдHoй/6Ъt60дHoй фаi],л может иметь расширение (например, txt, dat и прочее). Заметим, что этим средством ОС можно пользо ваться и в Паскале, и в Си, и в Фортране (см. та'К:же разд. "Фаi],л" 2ла6Ъt 9). И, наконец, если написать команду uses printer; и применить опера торы процедур write(lst, Vl, V2, ..., v n ), writeln(lst, Vl, V2, ..., v n ) и writeln(lst), то 6Ъt60д дaHHЪtx будет сделан на nринтер (lst от list  печатать). Ввод/ вывод в Си Си поддерживает два вида передачи данных: потоковую (подключа ется файл <iostream.h» и форматную (требуется <stdio.h». По тO'К:06Ъtй 660д посредством клавиатуры (аналоr форматноrо stdin) выполняет оператор иЗ6ле'Ченuя из nото'К:а cin » вида 5 Ввод С клавиатуры даже сравнительно небольшоrо количества данных  достаточно утомительное занятие. 
272 cln » Vl » V2 »... » V n ; rде Vl, V2, . . . , V n  элементы списка ввода (переменные или эле менты структурных данных целоrо, вещественноrо, символьноrо или CTpoKoBoro типа). Он, получая данные с клавиатуры, направляет входной поток по адресам переменных Vl, V2, ..., v n . Набираемые данные MorYT размещаться свободно  от "все в одной строчке" (TO rда они разделяются хотя бы одним пробелом) до "каждое на CBO ей строчке" (разделяются нажатием клавиши (Enter)). Строка не должна содержать пробелов. После набора nro значения и нажатия клавиши (Enter) данные назначаются переменным Vl, V2, ..., V N . Пото'/Совы11 вывод на экран (аналоr форматноrо stdout) производит оператор записи в nото'/С cout « вида cout « Vl « V2 « .., « V n ; rде Vl, V2, ..., V N  элементы списка вывода (выражения целоrо, вещественноrо, символьноrо, CTpoKoBoro типа или" лоrические" пе ременные). Он предназначен для размещения в одной строчке He скольких значений (если это возможно, в противном случае вывод переносится на новую строчку). Данные вывода сцепляются. Для разъединения их можно привлечь "пустые" символы и строки: 'u', "u", "uu" И т. П., а также '\п', "\п", "\п\п", "\t" и т. д. К примеру, при выполнении следующеrо фраrмента проrраммы cout « "\п Проrраммистами"; cout«" рождаются,"; cout « "\n\ta пользователями становятся."; получим такой результат: uПроrраммистамиuрождаются, uuuuuuuuаuпользователямиuстановятся. Еще один пример: реализуем Сипроrрамму Askprime: #include <iоstrеаш.h> void шаiп(vоid) { double Х, У, z; char И; unsigned 1==1 <2, J==1>2; cin »Х» У » И » V » W » z; cout «Х« "uu" « У « "uu" « И « "uu" « V « "uu" « W « "uu" « Z « "\nuuI==" « 1 « "uuJ==" « J « "uuEps==" « 1e 7 « "uu2.j3.==" « 2.j3.; / / Askprime char V[4], W[4]; 
273 } Вводные данные: 1.u2.uuuByeuBceu3. Выводные данные: 1uu2uuuuuByeuuBceuu3 uuI== 1 uuJ ==OuuEps== 1 е  07 uu2. /3. ==0.66666 7 Специальные средства потоковой передачи, называемые ма1tиnул.я торами, позволяют форматировать данные и выполнять некоторые друrие операции. Так, манипулятор setw(w), rде w  выражение типа int, используется для установки ширины поля вывода (setw от set width). Он становится доступным после подключения заrоло вочноrо файла <iomanip.h>. Например, модифицируем проrрамму Askprime следующим образом: unsigned 1==1<2, J==1>2, К==3; .,. , cout « setw( К) « Х « setw( К + 1) « У « setw(K +2) « И « setw(I{ +3) « V « setw(I{ +4) « W « setw(K +5) « Z « '\п'; Тоrда получим: uu1uuu2uuuuuuuuByeuuuuBceuuuuuuu3 Манипуляторы без параметров flush, endl и ends действуют только при выводе; первые два очищают выводные потоки, но endl еще и включает в поток символ новой строки, например, cout « "\п Ждите: идет ввод статистики." « endl; ...; cout « "\п Имя файла ======>" « flush; Манипулятор ends включает в поток нультерминатор. Оператор cout. width( w); устанавливает ширину w поля вывода. Оператор cout.precision( d); задает вывод d цифр после десятичной точки. 
274 Фун""u,и.я eofO возвращает ненулевое значение, если достиrнут конец файла EOF (например, while (!cin.eofO) ... ;). Оператор cout.setf(ios::left ); прижимает данное к левой rранице поля вывода. Оператор cout.setf(ios: :right); прижимает данное к правой rранице поля вывода (это действие опре делено по умолчанию). Оператор cout.setf(ios: :scientific); устанавливает научную нотацию выводноrо даННоrо. Оператор cout.setf(ios: :fixed); задает фиксированную форму выводноrо данноrо. Оператор cout.setf( ios: :showpoint); задает вывод обязательной десятичной точки. Оператор cout.setf( ios: :showpos); добавляет знак + при выводе положительных чисел. Оператор cout.setf(ios: :unitbuf); очищает все потоки после выполнения операции «. Оператор cout.setf(ios::stdio ); очищает потоки stdout, stderr после выполнения операции «о Манипуляторы без параметров dec, oct и hex устанавливают COOT ветственно десятичную, восьмеричную и шестнадцатеричную систе му счисления данноrо. Файл заrоловков <conio.h> содержит определение функции очист 
275 ки экрана clrscr(); . Теперь кратко рассмотрим форматную передачу данных. Фор.мат ный ввод с клавиатуры выполняет функция scanf(). Ее прототип дан в файле <stdio.h>. Функция scanf(), так же как cin, является мноrоцелевым средством, ибо с ее помощью вводятся данные лю бых типов: числа, символы и строки. Имя функции (от анrл. scan formatted characters) отражает ее назначение  функция сканирует ( просматривает) клавиатуру, определяя, какие клавиши нажаты, а затем интерпретирует ввод, основываясь на форматах (дескрипто рах преобразований). Общий вид вызова функции следующий: sсапf("списо'Х:фор.матов", &Vl, &vz, ..., &V n ); Здесь символ & является операциеЙ полу'Ченuя адреса. Она YCTaHaB ливает, что в настоящий момент нужен адрес области памяти, заре зервированной для переменной Vj (i == 1, 2, ..., п), а не значение пе ременной, хранящееся в этой области. Операция & не используется со строковыми переменными, так как Систрока  массив символов (см. Сипроrрамму Askprime: значением V является адрес массива). Списо'Х: фор.матов задает способ преобразования данных. Он должен содержать форматы, разделенные пробелами (если между формата ми указан пробел, то набираемые данные также разделяйте пробе лом или переходом на новую строчку). Фор.мат, используемый при вводе, имеет вид %фор.матныii 'Х:од фор.матныle 'х:одыl, предназначенные для ввода целыlx данных, TaKO вы: О d, ld  для int или long десятичных чисел; О и, lu  для беззнаковых int или long десятичных чисел; О о, 10  для int или long восьмеричных чисел; LJ х, lx  для int или long шестнадцатеричных чисел. В них вместо префикса 1 можно писать префикс h, который YCTa навливает, что передается короткое целое число. фор.матныlмuu 'Х:ода.ми вещественныlx данныlx являются: о f, lf, Lf  для float, double или long double чисел с фиксирован ной точкой (соответственно); 
276 о е, le, Le  для ftoat, double или long double чисел с плавающей точкой (соответственно); о g, 19, Lg  заменяют f, е, lf, le или Lf, Le. ФорматНЫf1 1\,од сuмволъных данных есть с. Он определяет, что чи тается один символ. ФорматНЫf1 1\,од стРo1\,овых данных 8 означает, что читаются симво лы, пока не встретится символ "новая строчка" \п или пробел. Функция 8canf() принимает с клавиатуры все символы до нажатия клавиши (Enter) и помещает их в буфер. Затем по сnис1\,У форма тов определяется способ преобразования символов, причем данное, преобразованное в соответствии с первым форматом, помещается по адресу переменной Vl, т. е. &Vl; данное, обработанное по второму формату, помещается по адресу V2, т. е. &V2, и т. д. К примеру, при ведем модифицированную Сипроrрамму Askprime: #include <8tdio.h> void main(void) / / Asksecond { double Х, У, Z; char И; char V[4], W[4]; 8canf ("%lgu%lgu%cu%8u%8u%lg", &Х, &У, &и, V, W, &Z); printf(I/%lguu%lguu%cuu%8uu%8uu%lg\n", Х, У, и, V, W, Z); } Исходные данные: 1.u2.uuuByeuBceu3. А это результат: luu2uuuuuByeuuBceuu3 Вводимая строка не должна содержать пробелов. Дело в том, что по формату %8 функция 8canfO передает все символы строки до первоrо разделителя, в том числе и пробела. Оставшиеся в буфере символы будут поступать в проrрамму при следующих обращениях к функции (что может не входить в наши планы). По этой причине пе ред очередным обращением к функции 8canfO следует посредством функции fНU8h(8tdin) выполнить O"lUcm1\,y буфера (признаемся, что 8canf() не слишком удобна для ввода строк; см. далее функции get80 и getlineO). Заметим еще, что компилятор все символы после знака % до первоrо разделителя считает форматным 1\,0 дом. Мож но ошибиться при ero записи, и тоrда данные, формат которых не 
277 соответствует ожидаемому (написанному в списке форматов), иrно рируются, и они остаются в буфере. Здесь снова может оказаться полезной функция очистки буфера. Формат1tыil вывод производит функция printf() вида printf(" список форматов", Vl, V2, . . ., v n ); [де Vl, V2, ..., V n  целочисленные, вещественные, символьные, строковые или 11 лоrические" выражения. Теперь формат может иметь следующий вид: %[ флажок} [ W } [.d} формат1tыil код Здесь флажок есть знак  (тоrда преобразованное данное BыpaB нивается влево в поле вывода ширины w; справа от данноrо MorYT появиться пробелы; выравнивание вправо  по умолчанию), и/или знак + (тоrда для положительных чисел выводится знак +), и/или пробел u (тоrда перед положительным числом выводится пробел; знак минус для отрицательных чисел выводится всеrда), и/или # (для восьмеричных и шестнадцатеричных чисел; для десятичных чисел d==O обеспечивает вывод точки); параметр w задает минималь ную ширину поля вывода в w символов (если ширина недостаточна, данное выводится полностью); параметр d определяет число цифр после точки для кодов f, lf, Lf, е, le и Le, или число значащих цифр для кодов g, 19 и Lg (при d == О точка не ВЫВОДИТСЯ; по умолчанию d == 6). Список форматов может содержать управляющие символы, пробе лы и друrие символы, поясняющие выводные данные (они воспроиз водятся на экране; если нужен знак процента, то ero следует набрать как %%, а двойную кавычку  как \"). Длинный список форматов можно разбить на части таким образом: "список форматов 1" 11 СП исок форматов 2" 11 СП исок форма тов n " Например: #include <stdio.h> void main (void) / / Test { double Х == 1.234567e2; 
278 printf(" \ nuuX==%8.41f \ nuuX==% 1 0.41f \ nuuX==%9. 31f" "\nuuX==%5.01f\nuuX==%5.41f", Х, Х, Х, Х, Х); } Приведем еще пример. Он является Сианалоrом Pascal.floatJormat проrраммы: #include <stdio.h> #include <iostream.h> void main (void) / / C++.floaCformat { double Х! У; unsigned 1; for(X == 1234567., У == Х, 1 == 1; 1 < 14; 1++) { printf("\n%13.61guu", У); cout « У; У*==.l; } cout « '\п'; } Результаты вывода С++.flоаtJоrmаtпроrраммы таковы: uu1.23457e+06uu1234567 uuuuuuu123457uu123456.7 uuuuuu12345.7uu12345.67 uuuuuu1234. 57uu1234. 567 uuuuuu123.457uu123.4567 uuuuuu12.3457uu12.34567 uuuuuu1.23457uu1.234567 uuuuuO.123457uuO.123457 uuuuO. 0123457 uu O. 012346 uuuO.00123457uuO.001235 uuO. 000123457 uu O. 000123 uu1.23457e05uu1.234567e05 uu1.23457e06uu1.234567e06 Функции 1tеформаm1tоzо 1\,о1tСОЛЪ1tоzо ввода/вывода работают с сим волами или строками. Для ввода символа применяется функция getchar(), не имеющая aprYMeHToB. Набранный символ помещает ся в буфер (напомним правило: после отработки функции scanfO буфер следует очистить) и отображается на экране. Нажимать кла вишу (Enter) не надо (если только getcharO  не последняя в проrрамме). Так как вызов любой функции является выражени ем, то набранный символ можно присвоить переменной, объявлен 
279 ной как char. Эту функцию можно использовать для приостано ва выполнения проrраммы. Вывод символа v реализует функция putchar( v). Аналоrично двум рассмотренным функциям работают функции getc(stdin) и putc(v, stdout). Перечисленные функции являются макроопределениями. Чтобы избежать проблем, связанных с использованием функции getcharO после функции scanf(), применяйте вместо getcharO определенные в файле <conio.h> функции getchO или getcheO. Они не посылают символ в буфер (при выполнении getch() вводи мый символ не отображается на экране). Функция putch(v) анало rична функции putchar(v). Переда'Ч,у CтpO'/i: производят функции gets( v) и puts( v). Набираемая на клавиатуре строка может иметь пробелы. После нажатия КЛа виши (Enter) отрабатывает функция gets( v) и строка назначается переменной v. Выводимая строка v может содержать управляющие символы. Она передается на экран, после чеrо курсор перемещается на начало новой строчки экрана. КонтрольныJt вопрос Функции gets( v) и puts( v) подобны соответственно функциям scanf("%s", v) и printf("%s\n", v). В чем их отличие? Ответ Отличие состоит только в том, что функция gets( v) передаст в про rpaMMY все символы до '\п' (включая пробелы). Теперь выведем построчно законы эколоrии с 14й позиции в строч ке. Дадим три варианта решения. Сравните их. #include <stdio.h> void main(void) 11 Coтparison { printf("%13s%s\n%13s%s\n%13s%s\n%13s%s\n", "u", "Все связано со всем.", "u", "Все должно KyдaTO деваться.", "u", "Ничто не дается даром.", "u", "Природа знает лучше. "); printf("%13cBce связано со всем.\п" "%13сВсе должно KyдaTO деваться. \П" 
280 "%13сНичто не дается даром.\п" "%13сПрирода знает лучше.\п", , , , " , , ' ) . u, u, u, u , puts("uuuuuuuuuuuuuBce связано со всем.\п " "uuuuuuuuuuuuuBce должно KyдaTO деваться.\п" " Н О \ " uuuuuuuuuuuuu ичт не дается даром. n " П О " ) . uuuuuuuuuuuuu рир да знает лучше. , } Использование двух rоризонтальных табуляций \t\t позволяет BЫ вести законы с 17й позиции в строке. Форматный вывод на nринтер производит функция fprintf() вида fprintf(stdprn, "СnUСО1\,форматов", Vl, V2, ..., v n ); Здесь stdprn  стандартный файл печати. С началом работы про rpaMMbI он открывается автоматически. ВВОД/ ВЫВОД В Фортране Стандартные средства Фортрана поддерживают четыре вида BBO да/вывода: уnравл,я,емы11 сnис1\,ОМ (неименованный и именованный), форматныi1, неформатны11 и iJBoU"iHbl11. Рассмотрим первые два ви да. Они предназначены для передачи текстовой информации. Ynpa вл,я,емы11 неименованным сnис1\,ОМ ввод данных с клавиатуры выпол няют операторы read(*,*)Vl, V2, ..., V N И read*,Vl, V2, ..., V N Типы вводимых констант  арифметический, лоrический, символь ный и строковый. Сами константы MorYT размещаться в одной или в нескольких строчках. Разделителями значений должны быть про белы и/или символы конца строчки. При этом набор одинаковых подряд идущих констант лучше производить в форме 1\,оэффuцuент nовторенu,я, * зна"iенuе Лоrические числа удобно задавать буквами t и f. Символьные и строковые константы нужно заключать в апострофы. Апостроф, являющийся частью строки, следует удваить. К примеру, приведем Фортранпроrрамму Asksecond: program Asksecond implicit попе 
281 real Х, У character И, V *3, W *3 logical Р read (*, *) х, У, Р, И, V, W write(*, *) Х, У, Р,' " И,' " V,' " W end Вводные данные в этой задаче таковы: le7 u2. utu'u'u'Вуе'u'Всё' А это выводные данные: uuul.000000ЕО7uuuuuuuu2.000000uТuuuuuВуеuuВсё Строковую константу можно разместить в одной или нескольких строчках, например, так: 'Неuвсёuверно uuуuЖюляuВерна. ' Тоrда выполнение проrраммы Poems program Poems ! л. rолубков, rp. 1057/2 implicit попе character*80 Verse read (*, *) Verse write( *, *) Verse end даст следующий результат: НеuвсёuверноuуuЖюляuВерна. Строковая константа будет дополнена пробелами справа, если ее длина меньше объявленной длины; в противном случае концевая часть строки отсекается. Если в операторе read вместо первой звездочки указать номер устройства ввода (последовательный текстовый файл с COOTBeTCTBY ющим именем, очевидно, уже открыт (см. раза. "Фаил" 2лавы 9)), то можно выполнить ввод данных из этоrо файла. В списке ввода Vl, V2, . . ., V N допускаются циклические элементы (см. раза. "Массив" 2лавы 7). Сам список можно не писать. Тоrда при вводе будет про изведен переход к следующей строчке данных. Первыи оператор ввода допускает обобщение 
282 read(*,*,end==M eт1Ca l, err==M eт1Ca 2)Vl, V2, ..., V n Здесь параметр end задает .мет1СУl оператора, которому передается управление при считывании конца файла (символы 'Z), а параметр err  .мет1СУ2 оператора, который получит управление при возник новении ошибки ввода (см. проrрамму Enderr): program Enderr implicit попе integer N read (*, *, end == 10, err == 20) N write( *, *) N stop , Все. .. ' 10 stop' Конец файла: набрано Ctrl z' 20 stop , Ошибка в данном типа целый.' end При ее выполнении в обычной ситуации на экран будет выведено сообщение Всё. . . Уnравля,е.мъtu пeu.мeпoвaппъt.м сnuс1СО.м въtвод на экран выполняют операторы write( *, *) Vl, V2, ..., V N И print*, Vl, V2, ..., V N ТИП значения выражения Vj (n == 1, 2, . . . , n) такой же, как при BBO де: арифметический, лоrический, символьный или строковый. Дли на выводимой строчки не превышает 79 символов; в противном слу чае создаются новые строки данных вывода. Выводимые значения разделяются одним или несколькими пробелами (кроме символь ных и строковых констант). Каждый новый оператор write и print начинает вывод с новой строчки, например: program Law write( *, *) , Word"bI приходят и уходят,' write( *, *) , а ТеХ остается.' end uWоrd'ыuприходятuиuуходят, uuuuuuuuuuuаuТеХuостается. Этим обстоятельством при отсутствующем списке вывода можно пользоваться для вывода пустых строк. Вывод, управляемый списком, по существу, является разновид ностью форматноrо вывода (см. далее): преобразование данных из 
283 внутр.енней формы во внешную (текстовую) выполняется по неявно заданным форматам, зависящим от типа значений Vl, V2, ..., V N . Так, (j цело-ч,uслеппое даппое выводится в соответствии с форматом i11; (j формат вывода вещесmвеппоzо даппосо х определяется в зави симости от ero абсолютноrо значения: если истинно неравенство 1  Ixl < 107, числу одинарной точности соответствует формат Opf15.6, а числу двойной точности  формат Opf24.15; если же выполняется условие Ixl < 1 U 'хl  107, число одинарной точно сти выводится по формату 1ре15.6е2, а двойной точности  по формату 1ре24.15е3; (j лоzu-ч,еС1\:ое зпа'iепuе передается по формату 11, причем uT COOT ветствует .true., а uF  .false.; LJ вывод СU.Аиола и стРО1\:и производится по формату а (см. приве денные выше Фортранпроrраммы). Теперь выполним вывод па nриптер. Он имеет символическое имя 'prn' (подруrому, 'prn'  имя файла печати, подсоединяемоrо к устройству с произвольным номером, например, 26 (см. проrрамму Printer)) : program Printer implicit попе real*8 Х, У ореп(26, file == 'prn') read (*, *) х, у write( *, *) х, у write(26, * )Х, у end Вводной файл в этой задаче короток: 1d7u2dO А это выводной файл: uu1.000000000000000E007uuuuuuuu2.000000000000000 ! "Связываем" принтер ! с устройством 26 ! Вывод на экран ! Вывод на принтер Напомним, что первая звездочка в операторах read( *, *) и write( *, *) является номером устройства ввода/вывода. Ее можно заменить co ответственно на 5 и 6. Формаmпыil ввод с клавиатуры и вывод на экран выполняют опера торы 
284 read( *, сnецuфuх:ацuя формата) Vl, V2, . . ., v n read сnецuфuх:ацuя формата, Vl, V2, . . ., v n write( *, сnецuфuх:ацuя формата) Vl, V2, . . . , v n print сnецuфuх:ацuя формата, Vl, V2, ..., v n rде сnецuфuх:ацuя формата  это либо форматная строка вида I( сnисох: форматов у либо метх:а оператора format, который имеет вид метх:а format( сnисох: форматов) В любом случае сnuсох:форматов определяет порядок обработки данных и их типы. Он состоит из форматов, разделенных запяты ми (описывается одна строчка данных) или слэшами, т. е. косыми чертами (описывается несколько строчек). Один или несколько фор матов можно заключить в круrлые скобки. Получим rруппу форма тов. Перед нею можно указать коэффициент повторения, не превос ходящий числа 255. Любой формат может быть повторяемым или неповторяемым: первому может предшествовать коэффициент пов торения, а второму  нет (правда, неповторяемый формат можно превратить в rруппу, а перед rруппой разрешен коэффициент повто рения) . Повторяемые форматы иначе называются форматамu да н:пых . Они задают тип преобразования данных. Перечислим форматы и COOT ветствующие им типы: LJ iw, iw.l  целый; LJ bw, bw.l  целый двоичный; LJ ow, ow.l  целый восьмеричный; LJ zw, zw.l  целый шестнадцатеричный; LJ fw.d  вещественный с фиксированной точкой; LJ ew.d, ew.deт  вещественный с плавающей точкой и нормали зованной мантиссой; LJ dш.d  вещественный двойной точности; LJ gw.d, gw.deт  любой; LJ lw  лоrический; LJ а, aw  символьный, строковый. 
285 Здесь i, Ь, о, z, f, е, g, d, 1, а  форматные коды преобразований; w  ширина поля данноrо; 1  количество цифр целоrо числа; d  количество цифр дробной части; т  количество цифр показателя (w, 1, d, т  целые беззнаковые константы; wll, w>dO, тl). Константу в формате можно заменить заключенным в уrловые скоб ки выражением типа целый, к примеру, i < 'Це./tD-чuслеюtа,Я nере.меппая > При вводе с клавиатуры естествен свободный, неявно заданный фор мат, поэтому для ввода данных больше Bcero подходит управляемый списком оператор read. Для ввода символов и строк можно исполь зовать и форматный оператор read, но тоrда окаймляющие апостро фы надо опустить. К примеру, приведем модификацию Фортран проrраммы Asksecond: program Newasksecond implicit попе real Х, У character и, V *3, W *3 10gical Р read (*, *) х, У, Р read (*,'(a,lx,a,lx,a)') И, V, W write(*,*) Х, У, Р,' " И,' " V,' " W end Варианты набора исходных данных в этой задаче таковы: о 1e7 2. t О 1e7 2. О 1e7 О 1e7 u Вуе Все t 2. t 2. u Вуе Все u Вуе Все t u Вуе Все Для всех вариантов результат выполнения проrраммы одинаков: uuu1.000000E07uuuuuuuu2.000000uTuuuuuByeuuBce Если uuByeuBce набрать в двух или в трех строчках, например, так: о u Вуе Все CJ u Вуе Все то оператор read (*,'(a,lx,a,lx,a)') И, V, W должен принять COOTBeT 
286 ственно вид read (*,'(a,lx,aja)') И, V, W или read (*,'(ajaja)') И, V, W в последнем операторе список форматов можно сократить до ми нимума: read (*,'(а)') И, V, W. Поясним работу этих операторов. Формат lх устанавливает, что между данными должен быть проме жуток, равный одному пробелу u, а слэш или правая круrлая скоб ка списка форматов означают "конец строчки данных", "перейти к новой строчке". Оператор read (*,'( а)') И, V, W выполняется сле дующим образом. Начало работы оператора инициирует форматное управление, каждое действие KOToporo определяется как очередным элементом списка ввода, так и очередным форматом в форматной строке. Итак, с клавиатуры считывается четвертое данное (и) и в соответствии с форматом а и объявлением переменной И интерпре тируется как символ. Он назначается этой переменной. Затем фор матное управление попадает на правую скобку списка форматов и проверяется, не осталось ли в списке ввода элементов. Так как двум переменным еще не присвоены значения, то форматное управление разворачивается и передается левой скобке списка форматов. По сле реверсии управления пятое данное (Вуе) интерпретируется как строка из трех символов. Она назначается переменной V. Форматное управление снова попадает на правую скобку списка форматов. Но в списке ввода осталась одна переменная, значение которой еще не за дано. Тоrда форматное управление опять передается левой скобке, разворачивается и по формату а считывается строка Все. OHaTO и становится значением переменной W. Итак, список ввода исчерпан. Ввод данных завершен. К изложенному правилу выполнения фор MaTHoro управления добавим следующее: если в списке форматов наличествуют rруппы форматов, то при реверсии форматное упра вление передается не левой скобке списка форматов, а левой скобке последней rруппы (она, кстати, может иметь свои внутренние rруп пы форматов). к онтрольныJl вопрос Эквивалентны ли операторы read(*, '(Формат1, Формат2)') и1, и2, ..., и п и read(*, '(Формат1, (Формат2))') и1, и2, ..., и п 
287 Ответ Если в списке ввода не больше двух переменных, то эквивалентны; в противном случае  нет. Неповторяемые форматы называются также форматами уnравле ния. Они руководят передачей данных и в частности означают: LJ tm  переместить указатель позиции на т позиций вправо от начала строчки; LJ tlm  переместить указатель позиции на т позиций влево, счи тая от текущеrо ero положения; LJ trm и тх  то же, что tlтформат, но на т позиций вправо; LJ LJ LJ 8р  выводить знак + для положительных чисел; 88  отменить вывод знака + для положительных чисел; 8  установить стандартный режим вывода знака + для чисел: не выводить +; /  конец строчки, перейти в начало следующей строчки; \  при выводе на экран или принтер подавить действие правой скобки списка форматов;  прекратить просмотр списка форматов, если список ввода/ вывода исчерпан; LJ kp  задать масштабный множитель 10 k для f, e, d и gфор матов (127  k  127). C:J C:J LJ По умолчанию задан масштабныi1 множителъ Ор. Множитель kp изменяет данное, передаваемое по fформату. Он действует на все последующие форматы в списке форматов, пока не появится новый масштабный множитель. Отменить это действие можно посредством множителя Ор. Множитель 1р нужен для вывода научных данных, а 2р  процентных. При форматном выводе на экран или принтер первый символ строч ки данных является управляющим символом 6 . Сам он не выводится, а определяет продвижение по вертикали следующим образом: О пробел u или символ, отличный от о, 1 и +  перейти на новую бпри выводе, управляемом списком, первый символ интерпретируется как символ данноrо, а не как управляющий. 
288 строчку; О О  пропустить одну строчку; О 1  перейти на начало следующей страницы (при выводе на экран иrнорируется); О +  остаться на той же строчке (надпечатка, жирная печать). Чтобы предотвратить нежелательные действия управляющих сим волов, можно В начало каждой строчки вывода вставлять хотя бы один (дополнительный) пробел или перед форматом данноrо разме стить формат управления 1х (или t2). Приведем пример использования форматов управления при выводе законов эколоrии (см. проrрамму Comparison): program Comparison write( *,'(14х,а)') 'Все связано со всем.', + . 'Все должно KyдaTO деваться.', + 'Ничто не дается даром.', + 'П рирода знает лучше.' write(*,910) 910 format(j14x, 'Все связано со Р,сем.'! + t15, 'Все должно KyдaTO деваться.' j + 14('u'), 'Ничто не дается даром.' j + 'uuuuuuuuuuuuuuПрирода знает лучше.') end В этой проrрамме в роли спецификации формата сначала использу ется локальный формат '(фор.матная строка)', а затем  удален ный формат .метка format (фор.матная строка). Оператор форма та удобен в случае, коrда длинный список форматов используется больше одноrо раза. А это Fоrtrаnfiоаtfоrтаtпроrрамма: program FortranfioaCformat implicit попе real Xj1234567.j, V integer 1 у==х do 1==1, 13, 1 write(*,'(lpg13.6, а\)') У, 'uu' 
289 write( *, *) у Y==Y*.l end do end и результаты ее выполнения: 1.234567E+06 uuuu 1234567.000000 u123457.uuuuuuuuu123456.700000 u12345.7uuuuuuuuuu12345.670000 u1234.57uuuuuuuuuuu1234.567000 u123.457uuuuuuuuuuuu123.456700 u12. 3457uuuuuuuuuuuuu12. 345670 ul.23457uuuuuuuuuuuuuul.234567 u.123457uuuuuuuuuul.234567E01 1.234567E02uuuuuul.234567E02 1.234567E03uuuuuul.234567E03 1.234567E04uuuuuul.234567E04 1.234567E05uuuuuul.234567E05 1.234567E06uuuuuul.234567E06 Еще пример: проrрамма Test иллюстрирует "жесткую реакцию Фортрана" на ошибочно выбранный формат f5.4 (вместо значения х выводятся пять звездочек): program Test implicit попе real Xjl.234567e2j write(*,'(ja,f8.4 ja,f10.4 ja,f9.3 ja,f5.0 ja,f5.4)') + 'uuX==', Х, 'uuX==', Х, 'uuX==', Х, 'uuX==', Х, 'uuX==', Х end Результаты работы Теstпроrраммы таковы: u Х =12З.4567 uХ=uu12З.4567 uХ=uu12З.457 u Х =u 12З . u X =***** А это пример использования бэкслэша \: write( *,'( а \)') , N ======> ' 
290 read(*,*) N Значение N, набранное на клавиатуре, отобразится в строке под сказки (а не в начале новой строки). Операторы приостанова и останова. Пустой оператор Рассмотрим средства, пdзволяющие управлять ходом выполнения проrраммы. Прuостанов выnолненuя Паскаль и Сипроrрамм на t миллисекунд производит оператор процедуры delay(t); rде тип aprYMeHTa t есть соответственно word или unsigned int. Эти средства становятся доступными, если соответственно подклю чить модуль crt или заrоловочный файл <dos.h> (к примеру, delay(3000); задержит выполнение Сипроrраммы на 3 сек). В Фор тране схожим средством является оператор паузы раusе[сообщенuе} rде сообщенuе  либо строковая константа, либо целое число, при надлежащее отрезку [о; 99999]. Этот оператор приостанавливает pa боту проrраммы и выводит текст сообщения. При нажатии клавиши (Enter) выполнение проrраммы продолжится. В дополнение можно воспользоваться и вызовом саН system("pause"). Пре1Сращенuе выnолненuя Паскальпроrраммы и передачу управле ния ОС производит оператор процедуры halt[(n)} а Сипроrраммы  exi t( n ) ; rде n  код завершения проrрамм. Применение функции exit требу ет файла заrоловков <stdlib.h> или <process.h>. Подобное cpeд ство Фортрана  оператор stор[сообщенuе} 
291 Выполнение проrраммы завершается также, коrда в rлавной проrрам мной единице управление попадает на последнюю операторную скоб ку end (Паскаль) и } (Си) или на последний оператор end (Фор тран). Пустоi1 оператор  это пусто (Паскаль), точка с запятой (Си) или [мет'К:а}сопtiпuе (Фортран). Пустой оператор Паскаля и Си мож но тоже метить. Обычно этот оператор применяют в сложных опе раторах. Так, в Сипроrрамме ero используют с операторами цикла, коrда тело цикла не требуется (действия, которые должны выпол няться В теле, целиком описаны в заrоловке оператора цикла), или при необходимости пометить фиrурную скобку меткой. Структура и запись проrраммы Паскальпроrрамма Паскальпроrрамма состоит из заrоловка, тела проrраммы, называ eMoro бло'К:ом, и точки: fProgram uм,я nР02раммы} } за20лово'К: nр02раммы [раздел обб,Явле1tU,Я мето'К:) (Раздел оnределе1tИ'я 'К:онстапт) (Раздел оnределе1tUЯ тиnов) (Раздел оббявле1tUЯ nеременных) (Раздел оббявле1tU,Я фу1t'К:u,ui1 u nрочедур) begin бло'К: {оnераторъу end. } раздел операторов в за20лов'К:е за словом program находится имя Проrраммы (очевид но, смысловое) и точка с запятой. Ело'К: может содержать шесть разных разделов, первые пять из KOTO рых (разделы объявления меток label, определения констант const 
292 и типов type, объявления переменных var, функций function и про цедур procedure) составляют де'К:ларатuв1tУЮ -частъ блока. В ней перечисляются имена всех объектов, встречающихся в проrрамме, и для каждоrо указывается, что он собой представляет и как с ним нужно обращаться (например, в разделе var следует объявлять пе ременные, требующиеся в ходе выполнения проrраммы (в частности, rлобальные переменные, если таковые используют подпроrраммы), за исключением некоторых, буферных переменных, известных по умолчанию (input A , output A , 1st и т. п.)). Разделы друr от друrа OT деляются точкой с запятой. Некоторые из разделов или все разделы декларативной части можно опустить (так, раздел label присутству ет, если в проrрамме имеются операторы перехода; в разделе const вводятся синонимы для констант; раздел type нужен тоrда, коrда в проrрамме используются нестандартные типы данных и т. д.). По рядок следования разделов произвольный и более Toro, они MorYT встречаться сколько уrодно раз. Но заметим, что объявление имени объекта должно предшествовать ero использованию. Шестой раздел, раздел операторов, является исnол1tяемоu -частъю блока. Без нее блок не имеет смысла. В структурированной проrрам ме она, как правило, выполняет управленческие (диспетчерские) функции. В ней, кроме ввода данных и вывода результатов, coдep жатся вызовы подпроrрамм. Связь по данным между подпроrрам мами реализуется путем передачи значений и возврата результатов. Синтаксически этот раздел представляет собой составной оператор, за которым следует точка. Паскальпроrрамма может содержать комментарии. Их лучше пи сать в конце строчек, чтобы они не вплетались в собственно Проrрам мный текст. В качестве примера дадим Паскальпроrрамму опреде ления скорости и расстояния (см. разд. "Поша2овая детализация" 2лавы 1): {$N+ } program Velocityjjdistance; uses crt; const Оnе == 1  Two == 1 Nl == #13#10; W : byte == 11; var VO, А, Т, Vt, 5: extended; /. , 1 . , 
293 begin clrscr; writeln('u УО, А, Т ======> '); clrscr; writeln(NI,"NI, NI, Тшо, NI, , u Вычислениеuскоростиuи uпройденноrоuпути.', NI, 'uuuuИсходныеuданные:', NI, 'uvO ==', VO : W, 'uua ==', А: W, 'uut ==', Т: W); Vt :== VO + А * Т; 5 :== (VO + Vt) * Т * 0.5; writeln(NI, Оnе, NI, , UUUUOTBeTbI:', NI, 'UCKOPOCTbuu==', NI, , uрасстояние == " NI, Тшо) read(VO, ;1, Т); Vt: W, S:W, end. { ео Velocityj3distance } Заметьте, что за заrоловком проrраммы следует предложение uses, подключающее библиотечный модуль crt. Он содержит подпроrрам мы, управляющие текстовым режимом работы экрана. Кроме Toro, в usеsпредложении можно перечислить, разделив запятой, имена MO дулей printer, graph, dos, overlay, turbo3 и graph3 (см. [58, 59]). Сипроrрамма Сипроrрамма обычно состоит из файлов двух видов: файлов заrо ловков (имеют расширение h) и файлов кода (расширение срр). Фаi1 лы 'К:ода содержат исходный код проrраммы. Содержание засолово'Ч иыx фаi1лов  классы, шаблоны, структуры, объединения (смеси), перечисления и объявления функций, определения typedef, опре деления констант, функции inline и дерективы препроцессора. Все вместе это называется u1tтерфеi1со.м к файлам кода. Информация из файлов заrоловков нужна и компилятору, и проrраммисту. К при меру, если проrрамма будет использовать дисковые файлы или BЫ полнять вывод на принтер, то необходимо подключить файл заrо ловков stdio.h. Для этоrо в начале файла кода следует разместить 
294 директиву препроцессора 7 #include <stdio.h>8. Уrловые скобки, окружающие имя файла, указывают компилятору, что данный файл находится в некотором стандартном каталоrе INCLUDE. Если же использовать директиву #include "им,я фаi1ла.расшире1tие", то по иск будет осуществляться в текущем каталоrе (в нем находится Си проrрамма) . Простейшая Сипроrрамма представляет собой набор функций, одна из которых  mainO. Все они MorYT находиться в одном единственном файле кода. rде бы ни была rлавная функция, с нее начинается выполнение проrраммы. Остальные функции MO rYT размещаться перед mainO и/или после нее, и тоrда заrоловки функций (точнее, прототипы, опережающие объявления) следует написать перед rлавной функцией (и функции, и переменные долж ны объявляться до их использования). Здесь же можно разме стить переименования типов вида typedef (к примеру, typedef unsigned Logical;), директивыопределения вида #define им,я те'Х:стзаме1tЫ (например, директива #define Lim 100 заменяет в Сипроrрамме все имена Lim числом 100), определения констант (например, const unsigned Lim == 100; const Logical True == 1, False == о;), объявления rлобальных переменных и т. д. rлав1tа.я ФУ1t'Х:'ЦU,я состоит из заrоловка и тела: [тип фу1t'Х:'Ции} main ([списо'Х: параметров}) тело фу1t'Х:'ЦUU Если не указать тип фУ1t'Х:'ЦUU, подразумевается тип int. Функция, не возвращающая значений, должна иметь тип void. rлавную функ цию можно определить с параметрами, которые будут передаваться ей из внешнеrо окружения (например, из командной строки вызова Сипроrраммы [24]). Если такая передача не планируется, то спи 7Это текстовый процессор, используемый для обработки исходных файлов кода на первой фазе компиляции. Ero работой управляют директивы (включе ния, определения и др.). Любая директива начинается с хэшзнака #, который должен быть первым символом в строчке. Такая строчка называется 1Со.ма'Нд'Ной сmро1СОЙ nреnроцессора. Если она длинная, то символом продолжения являет ся бэкслэш \. После обработки препроцессором проrраммный текст (он уже не содержит директив) поступает компилятору. 8Командная строка с #include может встречаться в любом месте проrраммы. Препроцессор заменяет ее содержимым соответствующеrо файла. 
295 сок формальных параметров можно либо опустить, либо заменить словом void. Тело фУН'К'I.{UU  составной оператор или блок. Бло'К после OTKpЫBa ющей скобки { содержит объявления и лишь затем операторы. Блоки и составные операторы MorYT вкладываться друr в друrа. Для при мера дадим Сипроrрамму Velocityj3distance: #include <iostream.h> #include <iomanip.h> #include <conio.h> const char Оnе [] == 11 Тшо [] == 11 const unsigned W==ll; void main(void) / / Velocityj3distance { double VO, А, Т, Vt, 5; clrscrO; cout« "u УО, А, Т ======> 11; cin» VO» А» Т; clrscrO; cout« "\п\п\п"« Тшо « "\пuВычисление скорости и пройденноrо пути." « "\пuuuuИсходные данные:" «I\nuvO=="« setw(W)« VO « "uua==" «setw(W) «А « "uut==" «setw(W) « Т; Vt == VO + А * Т; 5 == (VO + Vt) * Т * .5; cout « '\п' « Оnе « l\nuuuuOTBeT:" « l\nucKopoCTbUU==" «setw(W)« Vt « "\пuрасстояние==" «setw(W)« 5 «"\п" « Тшо; 11 , 1 1. , } / / ео Velocityj3distance Но реальныЙ проrраммный проект обычно состоит из нескольких файлов кода и заrоловков, которые, скорее Bcero, компилируют ся раздельно, а затем редактором связей (компоновщиком) объ единяются в исполняемую проrрамму. При такой структуре Си проrраммы функции из разных файлов MorYT использовать внешние, ехtеrппеременные. Все функции определены (по умолчанию) на внешнем уровне и доступны из любых файлов кода Сипроrраммы. 
296 Фортранпроrрамма Фортранпроrрамма состоит из проrраммных единиц, одна из KOTO рых  rлавная. Она, определяя начало и конец проrраммы, BЫ полняет обязанности "мажордома". За нею (или перед нею) разме щаются внешние подпроrраммы  функции function и процедуры subroutine. Структура rлавной проrраммной единицы такова: [program и-мя} [раздел операторов обо.явления} [раздел выполняе-мых операторов} [contains раздел внутренних подпРО2ра-м-м} end [рrоgrаm[и-м.я}} Раздел объявлений содержит необязательные операторы implicit попе, объявления внешних имен, определения производных типов, интерфейсные блоки, объявления типа, определения констант, объ явления массивов, общих объектов, эквивалентности, начальных данных и операторных функций. Комментарии и удаленные форма ты MorYT размещаться произвольно. Рекомендуемое местоположение комментариев  в конце строчек, а операторов формата  вслед за операторами ввода/вывода. Каждая проrраммная единица физически строится из предложений и комментариев. Предложение делится на 80ти позиционные строч ки, первая из которых  начальная, а возможные остальные  строчкипродолжения. Для записи проrраммы предлаrаются на BЫ бор свободный и фиксированный форматы. Файл, представленный в свободно-м фор-мате, должен иметь расширение f90. Тоrда в одной строчке MorYT размещаться несколько разделенных точкой с запя той операторов. Если строчку закончить символом &, то следующая строчка будет строчкой продолжения. Файл, записанный в фих;сиро ванно-м фор-мате, должен иметь расширение for. Этот формат озна чает следующее: если комментариев нет, то первые пять позиций строчки либо пусты, либо содержат метку выполняемоrо операто ра (например, 10, 20, ..., 1010, 1020 и т. д.) или метку удаленноrо 
297 формата (например, 910,920, 0..,1910,1920 и то до); метку лучше Ha бирать с первой позиции; если предложение не уместилось в одной строчке, то шестая позиция должна содержать символ продолжения текста строчки  отличный от пробела или нуля символ (к при меру, +); число строчек продолжения равно 54; оператор должен размещаться в позициях строчки 7  72, а исходные данные  в по зициях 1  80. Но файл с расширением for можно представить и в свободном формате, если в начале проrраммы написать MeTaKOMaH ду $freeform. Тоrда символом продолжения будет минус. Приведем в качестве примера Фортранпроrрамму Velocity8distance. Она за писана в фиксированном формате: include 'fgraph.fi' program Velocity8distance implicit попе character*( *) Оnе, Two parameter( Оnе ==' ', + Two == ' ') real*8 VO, А, Т, Vt, 5 саН clearscreen(O) ! саН system("cls") write(*, *) 'иУО, А, Т ======> ' read (*, *) VO, А, Т саН clearscreen( О) write(*,'(/ ja ja ja j3(a,lpg1003))') Two, + 'uВычисление скорости и пройденноrо пути.', + 'uuuuИсходные данные:', + 'uvO ==', VO, 'ииа==', А, 'uut ==', Т Vt == VO + А * Т 5 == (VO + Vt) * Т * .5dO write( *, '(/а ja, 2(/a,lpg1003) ja)') Оnе, + ' ииииОтвет:', + 'искоростьии==', Vt, + ' uрасстояние==', 5, + Two end ! ео Velocity8distance Здесь оператор clearscreen очищает экран (имя процедурыlIдвор ника" находится во включаемом файле fgraph.fi). 
298 Контрольноезание Одно из произведений Жюля Верна именуется "20000 лье под BO дой". Как моrла бы называться книrа, если расстояние мерить ки лометрами, а также морскими, анrлийскими и русскими милями? Замечание 1 лье (морское или rеоrрафическое) == 5.55555 км, 1 морская ми ля == 1.852 км, 1 анrлийская миля == 1.609344 км, 1 русская ми ля == 7.4676 км. Приведите Паскаль, Си и Фортранпроrраммы. Ответ Паскаль проrрамма: {$N+H 1.11.99 program Renaтe; uses crt; const 51 == 20000; Ет == 1.609344; Nl == #13#10; var 5 : extended; begin 5 :== 51 * L; 5km :==round(5); 5ет :==round(5/ Ет); clrscr; writeln(NI, Nl, 'uuuuЖюль Верн.', Nl, 51: W, 'uлье под водой.', Nl, Nl, 'UUuuHoBbIe названия книrи:', Nl, 5km : W, 'uкилометров под водой.', Nl, 5nт : W, 'uморских миль под водой.', Nl, 5ет : W, 'uанrлийских миль под водой.', Nl, 5rm : W, 'uрусских миль под водой.') Coded Ьу Иванов П., rp. 1057/1 } L == 5.55555; Nm == 1.852; Rm == 7.4676; W:byte==7; 5 km, 5nт, 5 ет, 5rm : longint; 5nт :==round(5/Nm); 5rm :==round(5/ Rm); end. { ео Renaтe } Си проrрамма: // 10.01.00 #include <stdio.h> Coded Ьу Петров С., rp. 1057/2 
299 #include <math.h> #include <conio.h> const long S1 == 20000; const double L == 5.55555, Nm == 1.852, Ет == 1.609344, Rm == 7.4676; void main (void) / / Renaтe { double S; long Skm, Snm, Sem, Srm; S == SI * L; Skm == floor(S + .5); Snm == floor(S/(double)Nm + .5); Sem == floor(S/double (Ет) + .5); Srm == floor(S/double (Rm) + .5); clrscr() ; printf("\n\n%s \n%7Id%s \n\n%s" "u\n%7Id%s \n%7Id%s \n%7Id%s \n%7Id%s\n", "uuuuЖюль Верн.", S1, "uлье под водой.", "uuuuНовые названия книrи:", S km, "UK илометров под водой.", Snm, "uморских миль под водой.", Sem, "uанrлийских миль под водой.", Srm, "uрусских миль под водой."); } / / ео Renaтe Фортранпроrрамма: c 23.08.01 Coded Ьу Сидоров И., rp. 1057/3 include 'fgraph.fi' program Renaтe implicit попе integer S1, Skm, Snm, Sem, Srm real*8 S, L, Nm, Ет, Rm parameter (SI == 20000, L == 5.55555dO, Nm == 1.852dO, + Ет == 1.609344dO, Rm == 7.4676dO) S == dble(Sl) * L Skm ==nint(S) Snm == nint(S/Nm) Sem == nint(S/ Ет) Srm == nint(S/ Rm) call clearscreen(O) ! саН system("cls") 
300 write( *,'(/ ja ji7,a j ja, 4(/i7,a))') + 'uuuuЖюль Верн.', + 51, 'uлье ПОД ВОДОЙ.', + 'uuuuHOBbIe названия книrи:', + 5 km, , uкилометров ПОД ВОДОЙ.', + 5nт, 'uморских миль ПОД ВОДОЙ.', + 5ет, 'uанrлийских миль ПОД ВОДОЙ.', + 5тт, 'uрусских миль ПОД ВОДОЙ.' end! ео Renaтe 
301 r лава 6 Кодирование u разветвлении Рассмотренные ранее операторы выполнялись в порядке следования один за друrим. Для изменения eCTecTBeHHoro порядка выполнения команд в языках имеются специальные средства. Кратко познако мимся с ними. Лоrическое выражение Лоrическое выражение (условие) формируется из лоrических пер вичных выражений и знаков лоrических операций (с-м. разд. "Усло вие" 2лавы 2). Оно принимает значение истина или ложь (в Си 1 или 0)1. К ЛО2u'Чесх;u-м nервu'Чны-м выра'JfCенuя-м относятся лоrиче ские константа, переменная, элемент массива, функция, отношение и выражение, взятое в скобки. Перед любым первичным выраже нием можно написать знак операции отрицания (знак одноместной операции). В отношенuu знаком операции отношения связывают ся два выражения  либо арифметических, либо символьных, либо строковых. При этом математические знаки >, <, , , == и =1- в Паскале пишутся как >, <, >==, <==, == и <>, в Си  как >, <, 1 В Си лоrическоrо типа нет. Любое выражение, претендующее на роль усло вия, будет иметь значением 1 или О. 
302 >==, <==, ==== и !==, а в Фортране 2  как .gt., .lt., .ge., .le., .eq. и .пе. или как >, <, >==, <==, ==== и /== (например, отношение 'Тайцы'>'Москвы' истинно, так как ord('T')==146, а ord('M')==140 (Паскаль) ). Специфичной для Си является условна,я операция (арифметическое если), задаваемая знаками? и :. Она определяется следующим обра зом: условuе ? 6ыраJfCеНUеl : 6ыраJfCеНUе2 Это трехместная операция. При ее выполнении сначала анализи руется УСЛО6uе, и если оно истинно, то вычисляется 6ыраJfCеНUеl, в противном случае  6ыраJfCеНUе2 (к примеру, Мах == А> В ? А : В;). В табл. 6.1 приведены знаки лоrических операций. Таблица 6.1. Знаки лоrических операций Операция Паскаль Си Фортран не и ИЛИ экв неэкв, исклили not and or && 11 .not. .and. .or. .eqv. .neqv. xor Если Р и Q  лоrические выражения, то экв можно выразить как Р ==== Q, неэкв  как Р! == Q, а импл  как Р <== Q (Си). Дадим пример довольно распространенной ошибки (Си). Целочис ленной "лоrической" переменной l присвоим результат сравнения цe лочисленных переменных m и n. Вот правильный ответ: L == М ==== N; или, забеrая вперед, if(M ==== N) L == 1; else L == о; А это ошибочное решение: L == М == N; 2Знак .ge., к примеру,  сокращение от анrл. greater than or equal to. 
303 или if(M == N) L == 1; else L == о; Здесь М ==== N  лоrическое выражение (отношение), а М == N  выражениеприсваивание, которое "истинно" всеrда, кроме случая равенства нулю n. Важной особенностью компиляторов Паскаля, Си и Фортрана явля ется ускоренная обработка лоrическоrо выражения: вычисление ero значения прекращается, если результат уже ясен (это обстоятель ство может быть причиной ТРУДНQУЛОВИМЫХ ошибок)З. Директива компилятора Паскаля {$В+} позволяет включать rенерацию кода для полноrо вычисления лоrическоrо выражения. Выполнение каждой операции происходит с учетом ее приоритета. Ниже операции перечислены в nоряд'/Се убыва1iИЯ старШИ1iства. Bы ражение может содержать несколько операций одноrо paHra. Пояс нения к операциям, выполняющимся в порядке справа налево, BЫ делены курсивом. Все остальные операции производятся в порядке слева направо. Паскаль: О вызов функции О, выделение элемента массива []; о not, вы'Числе1iие адреса @; о *, /, div, mod, and, сдвиrи влево shl и вправо shr; о +,, or, xor; О операции отношения, принадлежность множеству ln. Си: О доступ '/с 2лобаЛ'Ь1iоil nepeMe1i1ioil ::, обозначение компонента класса :: ; О вызов функции (), выбор элемента массива [], прямой выбор KOM понента структуры или объединения, . (то'Ч'/Са), косвенный BЫ бор компонента структуры или объединения, адресуемоrо указа телем >, вы'Числе1iие размера sizeof; о не!, побитовое, т. е. nоразряд1iое отрица1iие  , одноместпые +, 3 Лоrическое выражение может содержать вызов функции, изменяющей внеш нюю среду. 
304 , и'Н,1Сре.ме'Н,т ++, де1Сре.ме'Н,т , вы'Чuсле'Н,uе адреса &, обра ще'Н,uе по з'Н,а'Че'Н,uю У1Сазател.я, т. е. по адресу *, nреобразова'Н,uе тиnа О, выделение памяти new, освобождение памяти delete; О прямое обращение к компоненту класса по имени объекта и YKa зателю на компонент .*, косвенное обращение к компоненту класса через указатель на объект и указатель на компонент >*; О умножение *, деление /, получение остатка % ; о о о о двуместные +,; сдвиrи влево « и вправо » ; отношения >, <, >==, <==; отношения ,. , ., о побитовое и & ; о побитовое исклили О побитовое или I ; о и &&; о или 11 ; о арuф.метu'ЧеС1Сое еслu ?: ; О простое и состав'Н,ъtе nрuсваuва'Н,u.я , + ==, , * ==, /==, %==, «==, »==, &==, '==, 1==; о , операция "запятая" (последовательное вычисление). Фортран: О выбор элемента массива О, вызов функции О; о ** (справа налево); О *, /; о од'Н,о.мест'Н,ые +, о двуместные +, ; О О О операция сцепления / /; операции отношения; .not. (справа налево); .and.; о 
305 (j .or.; (j .eqv., .neqv. Поэтому, к примеру, двойное неравенство 1x2 в проrрамме нужно представить следующим образом: (j Паскаль (1.0<==Х) and (Х <==2.0) (j Си 1. <==х && Х <== 2. (j Фортран 1. <== Х .and. Х <== 2. Контрольноезание Число т делится на n. Напишите выражение, отражающее этот факт. Ответ (j Паскаль MmodN == О (j Си М% N ===0 (j Фортран mod (М, N) .eq. О Оператор переход а .... и условныи оператор Оператор (беЗУСЛО6НОZО) перехода (оператор "Шаrом марш!") в язы ках проrраммирования имеет вид LI Паскаль goto метх:а LI Си goto метх:а; (:J Фортран goto номер Он передает управление оператору, помеченному метх:оu/номером 4 . 4В структурированных проrраммах go to применяется, коrда, "ну, очень надо выбить дно и выйти вон". 
З06 Запрещены передачи управления извне внутрь сложноrо оператора, блока, подпроrраммы и модуля. Теперь познакомимся с операторами, представляющими в языках проrраммирования команду "ветвление". В Пасх;але определены две формы условНО20 оператора  полная и сокращенная: . if условие then оператор! [else оnератОР2} Он работает так: при истинном значении условия выполняется оператор!, а затем (оператор! не является оператором передачи управления) управление получает оператор, физически следующий за данным условным оператором; если же условие ложно, то BЫ полняется оnератОР2 или в случае усеченноrо оператора if  пу стой (т. е. никакой) оператор, а затем (оnератОР2 не есть опера тор передачи управления) действует преемник условноrо операто ра. Для примера найдем тах(а, Ь): if А>В then Мах:=А else Мах:=В. Решение Мах:=В; if А>В then Мах:=А будем считать неудовлетворительным; почему? Условныi1 оператор Си  аналоr ifоператора Паскаля: if (условие) оператор!; [else оnератОР2;} Обратите внимание на обязательные скобки BOKpyr условия и OTCYT ствие слова then. Понятие условия в Си расширено: теперь условием может быть любое выражение языка. Пример: if (А>В) Мах:=А; else Мах:=В;. Заметим, что в Паскале и Си оператор! и/или one ратОР2  составные операторы (часто). А это два вида БЛО'ЧНО20 условНО20 оператора Фортрана (они, в свою очередь, MorYT быть полными и сокращенными): if (условие) then операторы! [ else оnератОР Ы 2 } end if и if (условие!) then 
307 оnераторщ else if (условuе2) then оnератОР Ы 2 else if (условuез) then оnераторыз [ else операторы} end if else if (условuе n ) then оnераторъl-n а также ЛО2u'Ческ;ui1 оператор if (наследие Фортрана 66): if (условuе) оператор rде оператор  любой выполняемый оператор, за исключением опе раторов do, else, else if, end if, end, блочноrо if или лоrическоrо if. Примеры блочноrо (полноrо) оператора if: if (А .gt. В) then Вир==А else Вир==В end if и ifлоrическоrо: Вир==В if (А .gt. В) Вир==А Но лаконичнее и эффективнее Bcero задача нахождения mах(а, Ь) pe шается с помощью стандартной функции Фортрана: Вир == mах(А, В). Контрольноезцдание По заданному rоду определите название животноrо из восточноrо 12летнеrо календарноrо цикла. Ответ program Calendar; { const Nl : string == #13#10; ПАСКАЛЬпроrрамма: } 
308 var Уеат, Choice : word; begin write(NI,NI,NI, , Year ======> '); read( Уеат); С hoice :== (Уеат  3) mod 12; write( Nl, Уеат:12, 'й  rод '); if Choice == О then writeln(' кабана.') else if Choice ==1 then writeln(' крысы.') else if Choice ==2 then writeln(' вола.') else if Choice ==3 then writeln(' тиrра.') else if Choice ==4 then writeln(' кролика.') else if Choice ==5 then writeln(' дракона.') else if Choice ==6 then writeln(' змеи.') else if Choice ==7 then writeln(' лошади.') else if Choice ==8 then writeln(' овцы.') else if Choice ==9 then writeln(' обезьяны.') else if Choice ==10 then writeln(' петуха.') else writeln(' собаки.') end. { #include <iostream.h> / / void main (void) / / Calendar { unsigned Уеат, Choice; cout « "\п\п\п Year ======> "; cin» Уеат; Choice == (Уеат  3) % 12; cout « "\n\t" « Уеат « "й  rод "; if (Choice ==== О) cout«" кабана."; else if ( Choice ==== 1) cout«" крысы."; else if (Choice ==== 2) cout«" вола."; else if (Choice ==== 3) cout«" тиrра."; else if ( Choice ==== 4) cout«" кролика."; else if ( Choice ==== 5) cout«" дракона."; else if (Choice ==== 6) cout«" змеи."; else if ( Choice ==== 7) cout«" лошади."; else if (Choice ==== 8) cout«" овцы."; else if (Choice ==== 9) cout«" обезьяны."; else if (Choice ==== 10) cout « " петуха."; else сои t « " собаки."; } / / ео Calendar } с и  проrрамма: ео Calendar 
program Calendar ! implicit попе integer Year, Choice write( *,'(/ / /а \)')' Year ======> ' read( *, *) УеаТ' Choice == mod (УеаТ'  3, 12) write(*,'(/i13,a\)') Year, 'й  rод' if (Choice .eq. О) then write( *, *) , кабана.' else if (Choice .eq. 1) then write( *, *) , крысы.' else if (Choice .eq. 2) then write( *, *) , вола.' else if (Choice .eq. 3) then write( *, *) , тиrра.' else if (Choice .eq. 4) then write(*, *) , кролика.' else if (Choice .eq. 5) then write( *, *) , дракона.' else if (Choice .eq. 6) then write( *, *) , змеи.' else if (Choice .eq. 7) then write( *, *) , лошади.' else if (Choice .eq. 8) then write( *, *) , овцы.' else if (Choice .eq. 9) then write( *, *) , обезьяны.' else if (Choice .eq. 10) then write( *, *) , петуха.' else write( *, *) , собаки.' end if end! 309 ФОРТРАНпроrрамма: ео Calendar Оператор выбора Команду "выбор" в языках проrраммирования представляют опе раторы выбора. Они построены по "принципу меню": содержат все 
310 возможные варианты условий и операторы, которые следует выпол нить в каждом конкретном случае. В ПаС1'>але оператор выбора имеет вид case въtраЭfCе1tuе of '/Сонстll, '/С онст 12, '/Сонст21, '/С онст 22, '/С онст 1р , '/С онст 2ч оnератОР1 ; оnератОР2; ... , '/Сонст n 1, '/Сонст n 2, . . . , '/Сонст nт оnераторn; [else оператор} end Он работает следующим образом. Сначала вычисляется значение выраЭfCе1tU.я. Ero тип должен быть порядковым. Потом в lй, 2й, ..., nй ветвях разыскивается константа '/C01tCmij (i == 1, 2, ..., n; j == 1,2, ..., p/q/... /r)5, равная значению въtраЭfCе1tU.я (пусть это будет '/Сонст/ т ). Тоrда выполняется оnератор/, а затем (оператор/ не является оператором передачи управления)  преемник опера тора выбора. Если в lй, 2й, . . ., nй ветвях такой константы нет, то управление получает elseBeTBb, rде выполняется оператор (в этой ситуации при отсутствии ветви else действие оператора case не ОПре делено). Заметим, вопервых, что любая '/C01tcmij может быть задана отрезком вида '/Сонст н . . '/Сонст в , и, BOBTOpЫX, в некоторых диалек тах Паскаля вместо слова else используется слово otherwise. Оператор выбора в Си имеет следующий вид: switch (вЪtраЭfCе1tuе) { case '/Сонстll : case '/Сонст12 : . . . : case '/Сонст1р : оnератОРЫ1; case '/Сонст21 : case '/Сонст22 : case '/Сонст2ч : оnератОРЫ2; ... , case '/Сонст n 1 : case '/Сонст n 2 ...: case '/Сонст nт оnераторъt n ; [default : оnераторъtj } Структурно И правилами выполнения он похож на паскалевский оператор выбора. Однако есть и отличия. В качестве '/C01tcmij (i==1, 2, ..., n; j == 1,2, ..., p/q/... /r) разрешены целые или символьные 5Запись p/q/ . . . /r означает, что верхняя rраница индекса j может быть paB ной р, q, . .. или r. 
311 константы. Список onepamOp06j (i == 1, 2, . . . , п)  либо пустой, либо содержит один или несколько операторов (и тоrда не требуется объ единять их в составной оператор). Выполнение оператора switch не заканчивается в конце ветви. Проrраммист должен сам позаботить ся о выходе, например, из lй ветви, если это требуется по сценарию (в противном случае следующей будет выполняться (l + l)я ветвь и т. д.). В роли последнеrо оператора ветви удобен оператор break (он прерывает выполнение операторов switch, while, do, for и пере дает управление преемнику сложноrо оператора) или какойнибудь друrой оператор передачи управления. Команду" 6ыбор" 6 Фортра1tе представляет оператор select вида select case (6ыраж:е1tuе) case( 1Сопстll, 1Сопст12, . . . , 1Сопстlр) оnератОР Ы l case( 1Сопст21, 1Сопст22, . . .. , 1Co1tcm2q) оnератОР Ы 2 case( 1Сонст n l, 1Сопст n 2, . . . , 1Сопст nт ) оnераторы n [case default операторы} end select Тип констант 1C01tCmjj (i == 1,2, ..., п; j == 1,2, ..., p/q/ .., /r)  цe лый, символьный или лоrический. В роли 1C01tCmjj можно исполь зовать отрезок вида 1Сопст н : 1Сопст в , Любая rруппа onepamOp06j (i == 1,2, ..., п) может быть пустой. При выполнении оператора se lect управление передается rруппе onepamOp06j (i == 1, 2, . . . , п), для которой значение 6ыраж:е1tuя совпадает со значением, указанным в iой ветви case, а затем (onepamopbtj (i == 1, 2, .. ., п) не явля ются операторами передачи управления)  преемнику оператора выбора. Отметим, что и в if, и в sеlесtоператорах onepamopbtj (i == 1, 2, . . . , п), операторы и фразы else, end if, case, end select должны размещаться с новой строчки Фортранпроrраммы. Контрольноезцдание Напишите Паскаль, Си и Фортранпроrраммы, использующие опе 
312 раторы выбора при обработке календаря 12летнеrо цикла. Ответ program Calendar; { Паскальпроrрамма: } const NI == #13#10; var Year : word; begin write(NI,NI,NI, , Year ======> '); read( Year); write(NI, Year:12, 'й  rод '); case (Year  3) mod 12 of О : writeln(' кабана.'); 1 : writeln(' крысы.'); 2 : writeln(' вола.'); 3 : writeln(' тиrра.'); 4 : writeln(' кролика.'); 5 : writeln(' дракона.'); 6 : writeln(' змеи.'); 7 : writeln(' лошади.'); 8 : writeln(' овцы.'); 9 : writeln(' обезьяны.'); 10 : writeln(' петуха.') else writeln(' собаки.') end end. { ео Calendar } #include <iostream.h> / / void main (void) / / Calendar { unsigned Year; cout « "\п \п \п Year ======> "; cin» Year; cout « "\n\t" « Year « "й  rод 11; switch( (Year  3) % 12) { case О : cout « " кабана. 11; break; case 1 : cou t « 11 крысы. 11; break; case 2 : cout « " вола."; break; Си  проrрамма: ... , case 9 : cout « " обезьяны."; case 10 : cout « 11 петуха."; default : cout « " собаки,"; break; break; 
313 } , } / / ео Calendar program Calendar ! implicit попе integer Уеа; write( *,'и / /а \)')' Year =====> ' read( *, *) Уеа; write(*,'(ji13,a\)') Year, 'й  rод' select case (mod (Уеа;  3,12)) case (О) write( *, *) , кабана.' case (1) write( *, *) , крысы.' case (2) write( *, *) , вола.' Фортран  проrрамма: case (9) write( *, *) , обезьяны.' case (10) write( *, *) , петуха.' case default write( *, *) , собаки.' end select end! ео Calendar Упражнения 1. Оператор Signx :== (Р(Х) < О) замените: . условным оператором; . оператором выбора. 2. Кратко выразите факт: n  четно или нечетно. 3. Есть ли здесь ошибка: if (Х > О) and (In(X) < О) then write (' Да.') else write (' Нет.'); 4. Что делает следующий фраrмент проrраммы: '" , var Х, У, Z, Т : extended; 
314 ... , if Х > у then Z :== О else Z :== У  Х; Т:== Х + Z; 5. Выведите соответствующий текст: переменная h м Е [11 022; О]  , Впадина.' (причем, если h ==  11022 м  ' Марианская впадина.'), h м Е [о; 200]  ' Низменность.' (h == 20 м  ' Волховская низина.'), h м Е [200; 500]  ' Возвышенность.' (h == 291 м  ' Вепсовская воз вышенность.'), h м Е [500; 8848]  ' ropa.' (h == 5642 м  ' Эльбрус.', h == 8848 м  ' Джомолунrма.', h == 8611 м  ' Чоrори.', h == 8585 м  , Канчеджанrа.', h == 8221 м  ' Джаулаrири.', h == 8126 м  ' HaHra парбат.'; в противном случае  , Не знаю названия.'). 
315 r лава 7 Кодирование циклов Циклические алrоритмы можно записать условными операторами и операторами перехода. Однако циклы настолько важны и распро странены, что для их представления во всех языках проrраммиро вания предусмотрены специальные конструкции. Операторы цикла в соответствии с двумя видами повторений, управляемых либо яв ным счетчиком, либо вычисляемым условием, определены два Ba рианта операторов цикла  оператор для выполнять (цикл с па раметром, с предусловием) и операторы пока выполнять (цикл с предусловием) и выполнять пока (цикл с постусловием; см. разд. "Повторение" 2лавы 3). Что общеrо имеют операторы цикла? Каждый из них состоит из за rоловка и тела. За20ловоr;; начинается ключевым словом (for, while, repeat  в Паскале; for, while, do  в Си; do и do while  в Фор тране), содержит условие повторения и, возможно, правила измене ния параметра цикла. Условие  это лоrическое выражение (в Си  выражение). Тело состоит из нескольких операторов (Паскаль, Фор тран) или из одноrо оператора (Паскаль, Си), например, cocTaBHoro. 
316 Любой цикл всеrда начинается с подrотовки. Вход в цикл разрешен только через ero начало, т. е. через заrоловок оператора, а выход может быть либо 1iор.маЛЪ1iЫ.м (естественным, коrда выполнилось заданное условие), либо сnециаЛЪ1iЫ.м (орrанизуемым посредством оператора goto (неструктурированный выход) или с помощью опе раторов прерывания или возврата (структурированный выход)). При нормальном выходе значение параметра цикла равно конечному ero значению (Паскаль) или конечному значению плюс шаr изменения параметра (Си, Фортран), а при специальном  текущему ero значе нию перед выходом. оnераторыl nрерыlа1iи.я  это операторы break (Паскаль, Си) и exit (Фортран), а возврата!  exit (Паскаль) и return (Си, Фортран). Кроме Toro, существуют оnераторыl nродол JfCе1iИ.я continue (Паскаль, Си) и cycle (Фортран). Они передают управление к очередному повторению цикла, даже если предыду щий виток еще не был завершен. В операторах с параметром все переменные и константы, связанные с орrанизацией повторений, должны быть, вопервых, одноrо типа и, BOBTOpЫX, не MorYT изменяться, переопределяться в теле цикла (начальное, конечное значения и шаr изменения параметра вычисля ются один раз перед входом в цикл). Заметим, что если параметром цикла является переменная Х вещественноrо типа и, например, она изменяется по закону Х == Хо( Х k) h (эта запись означает, что Х принИ мает последовательные значения от Хр до Xk включительно с шаrом h), то нет уверенности, что через п== l(XkXO)jh+0.5] + 1 шаrов по лучится значение Х, равное Xk (напомним, что вещественное данное представляется в процессоре приближенно; найдите п для случая Х == 0.3(15.3)0.3; ответ: 51 виток (Фортранкомпилятор насчитает 50 витков)). Поэтому, чтобы полностью выполнить цикл повторений, надо в роли конечноrо значения параметра брать величину xk+hj2, равную "теоретическому" конечному значению плюс полшаrа изме нения Х. Впрочем, в такой ситуации предпочтительнее целочислен ный параметр i == 1(п)1, rде конечное значение п находится так: о N:== round( (Х k  ХО)! Н) + 1 о N == ftoor((Xk  XO)jH + .5) + 1; (Паскаль), (Си), lОператор возврата передает управление ОС, если он написан в rлавной про rраммной единице, или к точке вызова подпроrраммЫ, если он находится в подпроrрамме. 
317 о N == nint((X k  Ха)/ Н) + 1 (Фортран) . Все языки проrраммирования имеют по три оператора цикла. Ha помним рекомендации к использованию циклических команд: если тело цих;ла будет выполнено хотя бы один раз то / * цикл с постусловием: * / используйте оператор выполнять пока иначе если 'Число повторении тела цих;ла известно то / * циклы с предусловием: * / используйте оператор с параметром иначе используйте оператор пока выполнять 2 конецесли конецесли Правда, реализовать цикл с известным числом повторений можно любым из трех операторов. Операторы цикла MorYT вкладываться дру, в друrа. При этом долж но выполняться следующее правило: если, к примеру, тело одноrо оператора цикла содержит друrой оператор повторения, то тело BHY TpeHHero оператора должно быть частью тела внешнеrо. Операторы цикла в Паскале Оператор выполнять пока (оператор с постусловием) в Паскале имеет вид repeat операторы until условие Он действует по правилу begin операторы; if not условие then repeat операторы until условие end 2Следуя буквально этой рекомендации, можно на практике получить бес конечно выполняющийся цикл. Для построения надежноrо цикла в алrорит мах последовательных приближений уместен оператор с параметром, предель ное значение KOToporo определяется из условия решаемой задачи (см. разд. /1 Итератuвный 11,U1Сл", "Степенной ряд" 2лавы 3 u разд. "М одулъ" 2лавы 8). 
318 которое расшифровывается так З : всеrда один раз выполняются one раторы; они работают повторно, если условие ложно; в противном случае (условие стало истинным) совершается нормальный выход из тела ЦИКЛа. Заметим, что здесь операторы не надо окаймлять скобками begin и end. К примеру, приведем фраrмент ПроrраММЫ вычисления значения факториальной ФУНКЦИИ J( n) == n! для n  2: F :== 1; К:== 2; repeat Р:== F * К; inc(I<) until I< > N Так как скорость возрастания nфакториала чрезвычайно велика, то при неправильном выборе типа переменной f можно получить неверные результаты: n n! Тип f 5 120 byte 6 208 byte 6 720 integer 7 5040 integer 8 25216 integer 8 40320 word 9 35200 word 9 362880 longint 12 479001600 longint 13 1932053504 longint 13 6.2270208000Е+09 real 33 8.6833176188Е+36 real 34 2.9523279904Е+38 real 34 2. 95232799039604Е+038 double 170 7. 25741561530800Е+306 double 171 1.24101807021767Е+309 double 171 1.241018070217667823Е+0309 extended 1754 1.979261890105010055Е+4930 extended 1755 3.473604617134292647Е+4933 extended *** error *** error *** error *** error *** error *** error *** error Ошибки цело'ЧислеННО20 nереnолненu.я не диаrностируются и BЫ ЗИ здесь, и ниже при пояснении работы операторов цикла будем предполаrать, что из тела цикла производится только нормальный выход. 
319 полнение проrраммы продолжается. Зато всеrда фиксируется ne реnо.л:н,ен,uе nор.ядх;а. Оно приводит к прерыванию работы Паскаль проrраммы. Закодируем теперь алrоритм repoHa (см. разд. "Повторен,uе" 2Jlд вы 3): {$N+ } program Н eron; const Nl == #13#10; W == 26; var А, Eps, Х, Delta : extended; begin repeat write(NI, Nl, Nl, , А>О ======> '); until А > о; repeat write(NI, , Eps>1.08e19 ======> '); read(Eps) until Eps> 1.08e 19; write(NI, Nl, , Алrоритм repoHa.', Nl, , А ==', А: W,' Eps ==', Eps:8); Х :== (А + 1.0) * 0.5; repeat Delta :== 0.5 * (Х  А/ Х); until abs(Delta)<==Eps; writeln( Nl, , Ответ:', Nl, , Корень квадратный из А равен " Х : W, Nl, , поrрешность: " (Х sqrt(A)):8) read(A) { ео ввода А } { ео ввода Eps } Х :== Х Delta { ео вычисления корня } end. { ео program } Оператор пока выполнять (оператор с предусловием ) имеет вид while условuе do оператор Он эквивалентен такому условному оператору if условuе then begin оператор; while условuе do оператор end что означает: тело цикла (т. е. оператор) не выполняется, если усло вие ложно (было таковым до входа в цикл или стало таковым в процессе работы). К примеру, задача вычисления n! (n  2) теперь 
320 решается следующим образом: F :== 1; К:== N; while К > 1 do begin Р:== F * К; dec(K) end А это фраrмент модифицированной проrраммы Heron: Х :== (А + 1.0) * 0.5; Delta:== 1е38; while abs(Delta»Eps do begin Delta :== 0.5 * (Х  А/ Х); end; Х :== Х Delta { ео вычисления корня } КонтрольныJl вопрос Перечислите отличия операторов repeat и while. Ответ Первое отличие: в операторе repeat проверяется условие заверше ния цикла, а в while  условие продолжения (противоположное условие). Второе отличие: в операторе repeat условие проверяет ся после выполнения тела цикла, а в while  до выполнения тела. Третье отличие: слова repeat и until иrрают роль операторных CKO бок. И, наконец, оператор для выполнять (оператор с предусловием) выrлядит так: for имя :== 'Н,а'ЧЛЛО to 1Соне'Ц do оператор downto Здесь имя  параметр цикла, '/t,а'iало и 1Соне'Ц  начальное и конеч ное ero значения. Их тип  порядковый. Если ввести вспомоrатель ные переменные )1, )з И переменную Ь лоrическоrо типа, то работу оператора for можно представить следующим образом: begin . . )1 : == '/t,а'iало; )з: == 1Соне'Ц; if )1  )з then  begin имя :== )1; Ь:== false; repeat оператор; 
321 if имя == jз then Ь :== true else имя :== SUCC (имя) pred until Ь end end Слово to (см. заrоловок for) используется, если значение имени должно "возрастать", например (см. nодразд. "Оббявление простых nеременных в Пасале" разд. "Переменная" 2лавы 5): for Trafficlight :== Red to Green do оператор { нормальный выход: имя равно значению jз } Коrда же известно, что значение параметра будет "убывать", то пи шут downto, например: for Trafficlight :== Green downto Red do оператор На практике (часто) имя  целочисленная переменная, и тоrда шаr изменения параметра по умолчанию равен 1 (для to) или  1 (для downto). К примеру, приведем фраrменты Проrрамм вычисления п! (п  2): F :== 1; F :== 1; for f{ : == 2 to N do Р: == F * f{ for f{ :== N downto 2 do Р:== F * f{ Несмотря на то, что в fоrоператоре нельзя задать шаr изменения, отличный от :f: 1, это обстоятельство' не является недостатком Па скаля, так как цикл с произвольным (и переменным) шаroм леrко представить repeat и whilеоператорами. Контрольноезание Опишите бесконечный цикл. Ответ repeat операторы until false while true do оператор Операторы цикла в Си В Си оператор выполнять пока (оператор с постусловием) do оператор; while (условие); представляет собой сокращенную запись следующих двух операто ров: .мeтa : оператор; if (условие) goto Meтa; 
322 Она означает: выполняется оператор. Он будет выполняться снова и снова, если условие истинно. Для примера подсчитаем значение J(n) == n! (n  2): F == 1; J{ == 2; do Р* == J{ ++; while (К < N + 1); А это решение задачи repoHa: #include <stdio.h> #include <math.h> void main (void) 11 Heron { double А, Eps, Х, Delta; do {puts("\n\n\n А>О ======> ,,); } while (А<==О); do { puts("\n Eps > 2.22e16 ======> "); scanf("%lg", &Eps); } while (Eps <== 2.22e16); 11 ео ввода Eps printf("\n \n Алrоритм repoHa. \n А == %23.171e" " Eps==%7.lle", А, Eps); Х == (А + 1.) * .5; do {Delta == .5 * (Х  АI Х); Х  == Delta; }while (fabs(Delta) > Eps); 11 ео вычисления корня printf("\n Ответ: \n Корень квадратный из А равен %.171e" "\n поrрешность: %.Ole", Х, Х  sqrt(A)); } 11 ео program Оператор пока выполнять (оператор с предусловием) while (условие) оператор; scanf("%lg", &А); 11 ео ввода А эквивалентен следующему помеченному оператору: м,ет-х:а : if (условие) {оператор; goto м,етх;а;} Здесь оператор будет выполняться, пока условие истинно. К приме ру, найдем J(n) == n! (n  2): Р==1; J{==N; while(I{>1)F*==J{; Фраrмент решения задачи repoHa теперь примет вид: Х == (А + 1.) * .5; Delta:== 1е38; while (fabs(Delta) > Eps) 
323 { } / / ео вычисления корня Наконец, оператор для выполнять (оператор с предусловием) BЫ rлядит так: fоr(L'начало; L'условие;L'продвиение) оператор; Он тождествен следующим действиям: начало; while (условие) {оператор; пpoдвиeHиe;} Каждая часть заrоловка цикла может состоять из нескольких Bыpa жений (в начале допускаются еще и объявления переменных). Друr от друrа они отделяются запятой. Начало устанавливает исходные значения счетчиков и переменных. В условии задается условие про должения цикла. Оператор выполняется повторно, если условие ис тинно. При отсутствии условия ero значение считается истинным. В пpoдвиeHии подсчитываются новые значения счетчиков (или пе ременных, иrрающих роль счетчиков). Делается это после выполне ния тела цикла. Для примера приведем фраrменты проrрамм вычи сления nфакториала (n;:: 2): for (Р = 1, J{ = 2; J{ < N + 1 ; J{ + +) F * = J{; for (unsigned long F = 1, J{ = N; J{ > 1; Р* = J{  ); Delta= .5 * (Х  А/ Х); Х  = Delta; //N12 КонтрольныМ вопрос Какому оператору эквивалентен оператор for ( ; условие; ) оператор; Ответ Эквивалентен оператору while (условие) оператор; Контрольноезццание Представьте бесконечный цикл. Ответ do оператор; while (1); while (1) оператор; for (;;) оператор; 
324 Операторы цикла в Фортране В Фортране оператор [имя} do операторы end do [имя} задает бесконечный цикл. Ero леrко превратить в оператор цикла с пост или предусловием, если в теле цикла написать оператор пе редачи управления, скажем, такой: exit [имя}. К примеру, ПрИве дем Фортранпроrрамму Heron, в которой оператор do представляет цикл с постусловием: program Н eron implicit попе real*8 А, Eps, Х, Delta do write( *,'(/ / / а \)') , А> О ======> ' read (*, *) А if(A .gt. О) exit end do do write(*,'(/a\)') , Eps > 2.22d16 ======> ' read( *, *) Eps if(Eps .gt. 2.22d16) exit end do write(*,'(/ /а /a,lpd2l.15,a,lpd7.1)') + ' Алrоритм [ерона.', + ' А==', А,' Eps==', Eps Х == (А + ldO) * .5dO do Delta == .5dO * (Х  А/ Х) Х == Х  Delta if (abs( Delta) .le. Eps) exit end do write(*,'(a /a,lpd2l.15 /a,lpd7.0)') + ' Ответ:', + ' Корень квадратный из А равен', Х, ! ео ввода А ! ео ввода Eps ! d7.1 ! ео вычисления корня 
325 + end , поrрешность: " Х  sqrt(A) ! ео prograт Фраrмент вычисления п! приведен НИЖе. Оператор Фортрана пока выполнять (оператор с предусловием ) определяется следующим оборазом: [имя} do while (условие) операторы end do [имя} Здесь тело цикла выполняется до тех пор, пока условие истинно. Для примера дадим фраrменты вычисления пфакториала (п  2) LJ Р==1 LJ Р==1 К==2 К:=.2 do do while(I< .lt. N + 1) р==р*к F ==р*к К==К+l К==К+l if(I< .gt. N) exit end do end do и проrраммы Н eron с do whilеоператором: Х :=. (А + 1dO) * .5dO Delta == 1d38 do while (abs( Delta) .gt. Eps) Delta :=. .5dO * (Х  А! Х) Х :=. Х  Delta end do ! ео вычисления корня в Фортране реализуется one Цикл с параметром (с предусловием ) ратором вида [имя} do nеременная==начало, 1\,оне'Ц(, шаz} операторы end do [имя} [де nеременная  параметр цикла (ero тип целый или веществен ный (одинарной или двойной точности)); выражения начало, 1\,оне'Ц и ша2  начальное, конечное значения и приращение параметра. Их значения вычисляются перед входом в цикл иl :=,начало, jЗ:='1\,оне'Ц, j2==ша2). Ша2 может быть положительным или отрицательным. По умолчанию (ша2 не указан) он равен 1. Число повторений цикла 
326 птах компилятор находит по формуле птах==mах([(j2+jзjl)/j2],0), Если птах ==0 (т. е. jl превосходит jз с caMoro начала (или jl меньше jз при j2 < О)), то цикл выполняться не будет совсем. После слова do допускается метх;а. Тоrда концевой оператор тела цикла может быть 'таким: метх;а continue. Сказанное проиллю стрируем фраrментами проrрамм вычисления п! (п  2): О Р==1 О Р==1 do J{ == 2, N, 1 do 10 J{ == N, 2, 1 р==р*к р==р*к end do 10 continue l(онтрольноезание Представьте бесконечный цикл. Ответ do while (.true.) операторы end do Массив Необходимость в массивах возникает всякий раз, коrда приходится иметь дело с большим, но конечным набором однотипных данных  последовательностью (вектором), таблицей (матрицей), пакетом Ta блиц ("параллелепипедом") и т. д. Эти структуры данных называ ются соответственно одномерпым, двумерпым, трехмерпым и т. д. массивами. Каждый массив, используемый в проrрамме, нужно объявить. KOM пилятор, получая информацию об имени массива и типе элемен тов, ero размерности и размере, резервирует соответствующий объ ем памяти и определяет вид допустимых операций над элементами. Элементы массива размещаются в смежных областях памяти. Всей области назначается имя массива, которое выбирается по обычным правилам. Чтобы обратиться к элементу, надо использовать ипдex; сирова'Н,1tуЮ nереме'Н,1tуЮ, т. е. написать имя массива, а в скобках (квадратных (Паскаль, Си) или круrлых (Фортран)) указать индекс, если массив одномерный, либо два индекса, если массив двумерный 
327 и т. д. Если элементам массива не были назначены значения, то он так же, как и любая переменная, будет иметь своим значением некий "мусор". Массивы MorYT быть статическими и динамическими. Память под статичес-к:иТ1 -массив выделяется при компиляции проrраммы. Во время ее выполнения длина TaKoro массива остается неизменной. К дина-мичес-к:и-м относятся ссылочный массив (Паскаль, Си, Фор тран), а также автоматический и размещаемый массивы (Фортран). Память под такие массивы отводится в процессе работы проrраммы и при необходимости может быть изменена или освобождена. Массивы в Паскале в Паскале описание массивоrо типа задает как тип элементов Mac сива, так и тип индексов. Оно в случае nMepHoro массива выrлядит как array [тип инде-к:саl, тип инде-к:са2, . . ., тип инде-к:са п ] of тип эле-ментов и размещается в разделе определения типов type вслед за и-мене-м типа и знаком равенства или в разделе объявления переменных var вслед за и-мене-м -массива и двоеточием. Здесь тип инде-к:саi (i == 1, 2, ..., п)  это порядковый тип (кроме типов integer, word и longint), а тип эле-ментов, или базовый тип есть тип простой, составной (массивовый, записной, множественный), строковый или ссылочный. Наиболее часто в качестве типа инде-к:саi используются диапазонный (с целочисленными rраницами) и перечисляемый ти пы. Например, вектор Т среднемесячных температур воздуха в rоду можно объявить так (с-м. nодразд. "Обб,я,вление nростыlx nepe-менныlx 6 Пас-к:але" разд. "Пере-менна,я," 2лавыl 5): type Months == (Dec, Jan, Feb, Mar, Apr, Мау, Jun, Jul, Aug, Sep, Oct, Nov)j А vеТ'аgеtетреТ'аtиТ'е==аrrау[ Months] of extendedj var Month: Monthsj Т : А vеТ'аgеtетреТ'аtиТ'е; Тоrда элемент массива T[Month] при значении индекса Month, paB ном Dec, J ап, ..., N ov, есть текущая среднемесячная температура. Значение индекса не должно выходить за предельные rраницы из мерения, указанные в объявлении. Проверку индексов производит 
328 директива компилятора {$R+ }. Она отключена, т. е. по умолчанию действует директива {$R}. Теперь, к примеру, объявим двумерный массив  квадратную MaT рицу А размера 3 х 3, элементами которой будут ехtепdеdчисла. Вот возможные объявления: 1. type Matrix == array[1..3,1..3] of extended; var А : Matrix; 2. type Matrix == array[1..3] of array[1..3] of extended; var А : Matrix; 3. type Vector == array[1..3] of extended; Matrix == array[1..3] of Vector; var А : Matrix; 4. type Vector == array[1..3] of extended; var А : array[1..3] of Vector; 5. var А : array[1..3,1..3] of extended; 6. var А : array[1..3] of array[1..3] of extended; Здесь в вариаНТ,ах 2, 3, 4 и 6 в роли типа эле,Ме1tтов использован массивовый тип. Чтобы обратиться к элементу матрицы aik, нужно написать переменную с индексами A[I, К] или A[I][I<]. Элементы массива располаrаются в памяти в лексикоrрафическом порядке (" по стро-ка,М": индекс, находящийся правее, меняется бы стрее индекса, стоящеrо левее). Например, зададим 1tа'ч,алъ1tыe З1tа 'Ч,е1tИЯ элементам единичной матрицы Е == (    ) : О О 1 type Matrix == array[1..3,1..3] of extended; const Е : Matrix == ((1.0, 0.0, 0.0), (0.0, 1.0, 0.0), (0.0, 0.0, 1.0)); Обратите внимание на внешние круrлые скобки, оrраничивающие весь список значений, и внутренние, окаймляющие каждую строку элементов. В Паскале определена ,Массивовая оnера'l.{ИЯ nрисваива1tИЯ: одним оператором присваивания можно передать все элементы одноrо Mac сива друrому массиву Toro же типа. Для примера приведем правиль ный 
329 type Matrix == array[1..3,1..3] of extended; var А, В: Matrix; . . .; В:== А; . . . и ошибочный type Matrix == array[1..3,1..3] of extended; var А: Matrix; B:array[1..3,1..3] ofextended;...; В:==А;... фраrменты проrрамм. В объявлении массива лучше использовать предварительно опреде ленные константы. Несмотря на то, что число элементов статиче cKoro массива должно быть заранее известно компилятору, можно работать с массивом переменной длины. Для этоrо надо в ero объ явлении установить максимально возможные верхние rраницы ин дексов (характерные для решаемой задачи), а затем использовать только часть зарезервированной памяти. Такой подход улучшает читаемость проrраммы и усиливает ее универсальность. Сказанное проиллюстрируем примером ввода/вывода квадратной матрицы А максимально возможноrо размера 80 х 80 (длина массива не может быть больше 65520 байтов). Дадим один из возможных вариантов Паскаль проrраммы: {$N+, R+} program GeCpuCmatrix; { const Lim == 80; Nl == #13#10; type Ind == l..Lim; Matr == array[Ind,Ind] of extended; var А: Matr; N, 1, I< : Ind; W: byte; begin { write(Nl,Nl,Nl, , N <==80 write(Nl, , 10 <==W<==26 for 1 :== 1 to N do for I< :== 1 to N do begin write(Nl, , А[', 1, ',', К, '] ======> '); end; { writeln(Nl,Nl,' Матрица for 1 : == 1 to N do begin for I< :== 1 to N do write(' ',A[I, К] : W); Declarations: } { W  ширина поля данноrо } Statements: }  > ' ) .  ,  > ' ) .  , readln(N); readln(W); read(A[I, К]) ео GeCmatr } А[l..', N, ',1..', N, ']:', Nl); 
330 writeln end; { end. { ео Putmatr } ео program } Элементами массивов MorYT быть как отдельные символы, напри мер, type Name == аттау[1..8] of char; const Не . Name == ( ' А' ' ф ' 'и' 'н' 'о' 'r' 'е' , н ' ) , . " , , , , , , She . Name == ( ' А' 'н' 'ж' 'е' 'л' 'и' 'к' 'а' ) ' . , , , , , , , , так и строки: const Lenstr == 8; type Bounds == 1..6; Names == array[Bounds] of string[Lenstr]j const They: Names == ('Карл " 'Клара " 'Епифан " 'Феврония', 'Кирилл " 'Мефодий '); КонтрольныИ вопрос В каком порядке размещаются в памяти элементы "куба" А размера 2 х 2 х 2? Ответ А[l,l,l], А[1,1,2], А[1,2,1], А[1,2,2], А[2,1,1], А[2,1,2], А[2,2,1], А[2,2,2]. Массивы в Си в Си oa1toMep1tbli1 ,м,ассив v объявляется оператором вида тип v[l]; rде тип есть тип данных (int, unsigned int, . . ., long double, coт plex, char), а 1  целочисленное константное выражение. Ero значе ние представляет собой количество элементов (длина) массива. Mac сив у v выделяется память из lx(sizeof(mun)) байтов. Число элемен тов массива можно найти по формуле sizeof( v )jsizeof( тип). Первый элемент массива имеет нулевой индекс, а индекс последнеrо элемен та равен 1  1. Например, объявление double Х[З]; определяет три элемента: Х[О], Х[l] и Х[2]. Константное выражение в объявлении массива можно опустить в следующих трех случаях: 
331 1. Коrда в объявлении массива ero элементам явно 4 задаются Ha чальные значения; в этом случае длину массива компилятор опре деляет по количеству констант; приведем пример: double Х[] == {1., 1., 1.}; 2. Коrда массив объявляется как внешний; при этом ему в друrом месте проrраммы выделена память и (возможно) присвоены началь ные значения. 3. Коrда массив является формальным параметром (указан в заrо ловке и в прототипе функции). Можно сократить объявление однотипных массивов, перечислив их имена Vl, V2, . . ., V N В одном операторе: тип Vl(lI], v2[12], ..., Vn[Znj; При этом элементам массивов Vj (i == 1, 2, ..., п) можно назначить начальные значения. К примеру, объявление char И[] == "Эххо!", V[10] == "Иииэх!", Не [5] == "Фрол", She[4] == {'А', 'д', 'а', '\О'}; устанавливает, что массив U состоит из шести элементов, V  из девяти, Не  из четырех и She содержит три элемента. М'Ноzомер'Ныu массив в Си есть массив массивов, т. е. массив, элемен тами KOToporo служат массивы. Объявление MHoroMepHoro массива v должно содержать сведения о типе, размерности и количестве эле ментов по каждому измерению. Вот как оно выrлядит: тип V(lI] [12] . . . [ц; rде р представляет собой размерность массива (значит, объявление двумерноrо массива содержит два константных выражения [11] [12], TpexMepHoro  три [11] [12][1з] и т. д). Однотипные массивы удобно объявлять одним оператором. Здесь же элементам любоrо массива можно присвоить начальные значения. К примеру, объявим и зада дим начальные значения элементам матрицы AO Н) 4Неявно (по умолчанию) статическим (static тип v[rл};) и внешним (extern тип v [rл};) переменным (например, массивам) назначаются нулевые значения. 
332 и единичной матрицы Е: double А[З][З] == {{1.,2.,З.}, {4.,5.,6.}, {7.,8.,9.}}, Е[][З] == {1., О., О., 0.,1., О., О., 0.,1.}; Заметьте, что внешние фиrурные скобки окаймляют весь список зна чений, а внутренние  элементы каждой строки матрицы А. Чтобы обратиться, скажем, к элементу аоо матрицы А, нужно использовать инде'К:сированное имя А[О][О]. MHoroMepHbIe массивы в памяти размещаются "по стро'К:ам" (пер вый индекс возрастает наименее быстро, а последний  наиболее быстро). Например, элементы "куба" А размера 2 х 2 х 2, объявлен HOro как double А[2][2][2]; в памяти располаrаются в следующем порядке: А[О][О][О], А[О][О][l], А[О][l][О], А[О][l][l], А[l][О][О], А[l][О][l], А[l][l][О], А[l][l][l]. Особый случай  массив из стро'К:. Объявляя ero, необходимо ис пользовать два константных выражения: первое задает количество строк в массиве, а второе указывает длину каждой строки. Напри мер, ... , const unsigned L == 81; .,. , char T[12][4]=={"Dec", "Jan", "Feb", "Mar", "Apr", "Мау", " J un" "Jul" "Au g " "Se p " "Oct" "Nov" } , , , , , , P[][L]=={"B ", "зыбком ", "мире ", "вещественных ", "чисел", "осторожность", "не", "может", "быть ", "лишней."}; Здесь определение char Т[12][4] задает 12 строковых переменных Т[О], Т[l], ..., T[ll] длиной не более трех символов каждая. Тоща, чтобы вывести, скажем, на экран последнюю строку, надо в списке вывода указать имя Т[ll]. Имя Т[ll][О] задает первый символ этой строки. Число строк массива Р равно sizeof(P)/sizeof(P[O]). Имя первой строки есть Р[О], а длина массива sizeof(P) равна 810 байтам. Передача массива в Си выполняется поэлементно. Приведем про rpaMMY ввода/вывода матрицы А максимально возможноrо размера 
333 80 х 80: #include <iostream.h> / /#include <iomanip.h> #include <stdio.h> const unsigned Lim==80; void main(void) / / GeCpuCmatrix { unsigned N, /* W, */ 1, К; double A[Lim][Lim]; / / cout « "\п \п \п N<==80 ======> "; / /cout « "\п 1l<==W<==16 ======> for(I == о; 1 < N; 1 + + ) for(K == о; к < N; К + +) { cout « "\п А[" « 1 « ,,] [" « К «") ======> "; cin « A[I][K]; } // cout «"\п\п Матрица А[" « N « ,,) [" « N « "):\п"; for(I == о; 1 <N; 1 + +) { for(K == о; К <N; К + +) / /cout « setw(W) « A[I][K]; printf("%26.161g", A[I][K]); cout « "\п"; Declarations: Instructions: cin »N; "; cin» W; ео Getmatr } // } // ео PuCmatr ео progr аm у казатеJIИ В Си Массивы в Си связаны с указателями. Различают указателипе ременные (или просто указатели) и указателиконстанты. У-к;азате лем называется переменная, предназначенная для хранения aдpe са области памяти, выделенной друrой переменной, а У'к;азателем x;o1tcma1tmoit  значение адреса оперативной памяти. Как извест но, память компьютера  это набор битов информации, причем BO семь последовательных битов именуются баitтом, два байта образу ют слово, а четыре байта  дли1t1tое слово. Байты имеют номера: о, 1,2, '" Они называются также адресами. Таким образом, если р  адрес HeKoToporo байта, то (р  1)  адрес предыдущеrо байта, а (р + 1)  адрес последующеrо. Адресами слов будут адреса началь ных байтов слов, т. е. числа о, 2, 4, ..., а двойных слов  числа о, 
334 4, 8, . .. Так как указатель содержит адрес HeKoToporo байта, то, Me няя значение указателя, можно перемещаться по памяти, адресуясь к различным данным. Используя указатель, мы ссылаемся на объ ект проrраммы так же, как это делает компьютер. Это сокращает время доступа к объекту и, значит, применение указателей полезно. У казатели делятся на два вида  указатели на объект (константу, переменную, массив, строку, структуру, объединение, класс, друrой указатель) и указатели на функцию. В простейшем случае объявле ние У1Сазате.л.япеременноi1 на обlJе1Ст должно содержать тип дaH ных, адреса которых будет содержать указательпеременная, и и.м.я указателя с предшествующей звездочкой: тип *и.м.я; Здесь тип  любой основной или производный тип объекта дaH ных, для доступа к которому используется указатель (или, как ча сто rоворят, на который ссылается указатель). Им может быть и тип, определенный пользователем. Вкупе тип и * воспринимаются компилятором как особый тип данных  "указатель на чтолибо". Например, объявление int 1, *Iptr; представляет переменную 1 и указательпеременную /ptr. Перемен ной 1 выделено два байта памяти. Указатель Iptr имеет тип int *, т. е. тип "указатель на целое". Он может указывать на целочислен ную переменную, массив из целочисленных элементов или на какой нибудь друrой объект, размещенный в памяти. Место, выделяемое компилятором под такой тип, зависит от модели памяти [24, 48]. Объявление char и, * Uptr; вводит символьную переменную U и указатель Uptr на объект типа char  символьную переменную, строку (т. е. на массив из симво лов) или на область памяти, выделенную при динамическом распре делении памяти. Приведенные выше объявления резервир:уют память для указате лейпеременных, но Iptr и Uptr пока ни на что не указывают. Как только указателю будет присвоен адрес какоrолибо объекта, /ptr или Uptr можно использовать в работе. Дл,я полу'Чени'я адреса обlJ е1Ста применяется операция "адрес" &. Например, выражение &/ 
335 означает: получить, взять адрес, по которому переменная 1 хранит ся в памяти (точнее, взять адрес первоrо байта 1). Используя эту операцию, указателям можно присваивать адреса объектов (к при меру, Iptr == &1; Uptr == & И; теперь указатель Iptr содержит адрес переменной 1, а указатель Uptr  адрес переменной И). Обращение к оббекту 'l.{,ерез указател'Ь выполняется посредством операции разадресации, по друrому, разыменования, раскрытия ссылки или доступа по адресу *. Она рассматривает свой операнд как адрес HeKoToporo объекта и использует этот адрес для выборки значения. Типом результата операции * является тип объекта, aдpe cyeMoro указателем. Например, оператор присваивания *Iptr +== 1; означает: взять содержимое памяти по адресу, равному значению указателя Iptr, прибавить к этому содержимому 1 и результат поме стить по тому же адресу (заметим, что этот оператор по результату работы эквивалентен любому из операторов 1+ == 1; 1 ++; ++ 1; (*Iptr) ++; или ++ (*Iptr);). Приведем пример проrраммы, иллюстрирующей сказанное выше (значение указателя выводится в формате %[wJp, rде w  ширина поля вывода): #include <stdio.h> void main(void) // Pointerl { int 1, *Iptr; 1 == 123; Iptr == &1; printf(" Адрес 1: %р \п" " Значение 1: %d \п" "Значение Iptr: %р \п" " Значение, адресуемое переменной Iptr: %d \п", &1, 1, Iptr, *Iptr); } / / ео program Результат выполнения проrраммы: Адрес I: FFF4 Значение I: 123 Значение Iptr: FFF4 Значение, адресуемое переменной Iptr: 123 Количество байтов, извлекаемых из памяти и участвующих в опера ции, определяется компилятором исходя из типа, на который указа 
ЗЗ6 тель "указывает". В данном примере в памяти выделяется два байта (число байтов равно размеру типа int(sizeof(int))). Эти два байта преобразуются к типу int и результат выводится. у казатель в объявлении может получать начальное значение. Ha пример: int 1, *1ptr == &1, *Jptr == (int* )512, *Kptr == (int* )ОХ400, *Lptr == new int, *Mptr(NULL); *1ptr == 123; *Jptr == 456; *Kptr == 789; *Lptr == 1; Здесь объявлено пять указателейпеременных: 1ptr получает в Ka честве начальноrо значения адрес, по которому в памяти хранит ся 1 (&1 есть FFF4); Jptr  начальное значение 512 (адрес 0200; при этом выполняется явное преобразование к типу "указатель на целое"); Kptr  адрес 0400, Lptr  адрес 068Е и Mptr  нулевой, пустой указатель на объект типа int (адрес 0000). Значение, aдpe суемое переменной 1ptr (значение 1), есть 123; значение, адресуемое переменной Jptr  456, значение *Kptr  789 и значение *Lptr  123. Над указателямипеременными разрешены операции преобразова ния типа, присваивания, отношения и некоторые арифметические операции. Указатель на объект одноrо типа можно трансформиро вать в указатель на друrой тип, используя операцию nривеiJения ти па ух:азателя (тиn*) имя Здесь имя есть имя указателя. Для указателей, адресующих один и тот же тип, определена onepa ция nрисваивания одноrо указателя друrому. Например, int 1 == 123, *1ptr, *Jptr; 1ptr == &1; Jptr == 1ptr; Если указатели адресуют общий объект (переменную, строку или массив), то два указателя можно сравнивать на равенство, Hepa венство и т. п. Над указателями можно выполнять операции инкремента, дeKpe мента, сложения и вычитания. Если к указателю применяется опера ция ++ (), ТО он увеличивается (уменьшается) на размер объек та, который указатель адресует (например, значение указателя Ptr, объявленноrо как тип *Ptr;, увеличивается оператором Ptr++; 
ЗЗ7 на величину sizeof( тип); тем самым указатель "перемещается" к соседнему объекту с большим адресом; здесь типо-м может быть основной тип, тип структуры или объединения). Коrда к указателю, объявленному как тип *Ptr;, добавляется или из указателя вычитается константа п, значение Ptr изменяется на величину nхsizеоf(тип). Для примера представим текст проrрам мы Pointer2: #include <iostream.h> void main (void) jj Pointer2 { char *5 == "if  маленькое слово с большими возможностями."; int 1 == о; jjchar 5[ ] == "if  ... "; while (*(5 + 1)! == '\0') cout « *(5 + 1 ++); jjwhile (5[1]) cout « 5[1 ++]; jjfor (int 1 == о; *(5 + 1) ! == '\0'; cout « jjfor (int 1 == о; 5[1]; cout « 5[1 ++]); } *(5+1++)); и т. д. jj ео program Два указателя (тип *ptr1, *Ptr2;) сложить нельзя, зато разность двух указателей равна разности их значений, поделенной на вели чину sizeof( тип). Вычитая указатели, мы находим "расстояние" Me жду областями памяти. Оно определяется в единицах, кратных раз меру (в байтах) объекта Toro типа, к которому отнесен указатель. Разность же однотипных указателей, адресующих два смежных объ екта любоrо типа, по модулю всеrда равна 1. В частности, арифметические операции над указателями типа char * (длина типа равна 1 байту) выполняются как над целыми числами с той лишь разницей, что значения, участвующие в операции,  это адреса в оперативной памяти. Но для друrих типов указателей это не так. Например, для указателя типа int * (длина типа  2 бай та) "единица изменения" указателя и "единица измерения разности" равна двум байтам. Без указателей не обойтись при дина-ми'ЧеС1l:0-М раз-мещении обзе1l: тов. Ниже при выделении памяти одному объекту в процессе BЫ полнения проrраммы применяется ФУН1I:ЦИ.я mаllосО вида (тип * )mаllос( 'Число баi1тов) rДе 'Число баi1тов можно задать константным выражен'ием или опре делить посредством функции sizеоf(тип). Для при мера приведем 
338 проrрамму Pointer3: #include <stdio.h> #include <alloc.h> void main(void) // Pointer3 { int *А; А == (int * )mаllос( sizeof(int)); *А == 123; printf(" Значение А: %р \п" " Значение, на которое указывает А: } %d \п", А, *А); // ео program Результаты выполнения проrраммы: Значение А: 07ВА Значение, на которое указывает А: 123 в момент присваивания указателю А значения функции mаllос() создается целочисленная переменная *А. Теперь этой переменной можно присвоить значение (т. е. записать 123 по адресу). При динамическом выделении памяти нескольким объектам можно пользоваться фу'l-t'/щuеf1 саllос(): (тип * )саllос( "iuсло обе"..тО6, "iuсло баf1тО6 для од'l-tО20 обе"..та) К примеру, дадим проrрамму Pointer4: #include <stdio.h> #include <alloc.h> const int N == 3; void main(void) { int *А, 1; А == (int *)calloc(N,sizeof(int))j //А == (int *)malloc(N*sizeof(int)); или, лучше, А ==new int[N]j *А == 123; *(А + 1) == 456; *(А + 2) == 789; printf("\n Адреса перемеННЫХ:")j for(J == о; 1 < N; 1 ++) printf("%7p", (А + 1)); printf(" \ n Значения переменных:") j for(J == о; 1 < N; 1 ++) printf("%7d", *(А + 1)); printf("\n Адреса элементов:"); for(I == о; 1 < Nj 1 ++) printf("%7p", &A[I]); printf("\n Значения элементов:"); for(J == о; 1 < N; 1 ++) printfC'%7d", A[I])j } // Pointer4 // Указатель: // Массив: // &I[A] // I[A] // ео program 
339 Результаты выполнения проrраммы: Адреса Значения Адреса Значения переменных: переменных: элементов: элементов: 07ЕА 123 07ЕА 123 07ЕС 456 07ЕС 456 07ЕЕ 789 07ЕЕ 789 Она состоит из двух частей. В первой части обрабатывается YKa затель А. Оператор *А == 123; помещает число 123 в область па мяти, адрес первоrо байта которой хранит переменная А. Оператор * (А + 1) == 456; записывает число 456 в область памяти, первый байт которой отстоит от начала первой области на длину, равную двум байтам, т. е. размеру области хранения объекта типа int, и т. д. В общем случае, если А указатель на данное HeKoToporo тиnа, то выражение (А + 1) означает адрес памяти, равный значению BЫ ражения (А + (Ixsizeof(mun)). Вторая часть проrраммы Pointer 4 подтверждает факт существова ния прямой связи между указателями и массивами (см. результаты работы проrраммы). К примеру, по объявлению int А[3], *Р; не только выделяется память для трех элементов целочисленноrо массива А, но и имя массива определяется как константный указа- тель на первый элемент массива (ero адрес &А[О]). Так как имя массива есть адрес, то законным является присваивание Р == А;. Здесь указатель Р устанавливается на адрес первоrо элемента мас- сива А. Таким образом Р становится указателем на массив и ero можно использовать для ссылки на элементы массива. В силу то- ждества А = &А[О] оператор Р == А; можно представить в эквива лентной форме Р == &А[О];. На практике допустима любая форма записи. Для обращения к элементам массива тоже существуют два способа. Первый способ предполаrает использование индексных выражений 5 вида A[I] (например, выражение А[2] ссылается на третий элемент массива А, при этом законна и такая форма записи: 2[А]). Индексное выражение А[ 1] является выражением с двумя операндами: первый из них, т. е. А, есть константный указатель (адрес начала массива в памяти); второй, индекс 1, это целочисленное выражение, за 5Напомним, что скобки [] являются операцией индексации.
340 дающее смещение от начала массива. Таким образом, операндами операции [] служат имя массива и индекс. Второй способ доступа основывается на использовании адресноrо выражения (или выраже ния с указателем на массив) вида *(Р + 1) (к примеру, адресное выражение *(Р + 2)  ссылка на третий элемент массива А). По определению индексноrо выражения Си любой указатель можно задать с индексом. Следовательно, выражения Р[2] и 2[Р] отсылают все к тому же, третьему элементу массива А. Если расписать ин дексное выражение Р[2], то получим адресное выражение *(Р + 2). Значит, любое индексное выражение можно представить в форме выражения с указателем и смещением, и наоборот. Компилятор же всеrда трансформирует индексные выражения в адресные (А[ 1] в *(А + 1), P[I] в *(Р + 1)). Таким образом, для доступа к (i + l)MY элементу массива А можно в одной проrрамме пользоваться OДHO временно любым из выражений A[I], I[A], *(А + 1), *(1 + А), P[I], I[P], *(Р + 1) и *(1 + Р). Обладая правами объекта, как именованной области памяти, YKa З<;l.тель имеет адрес, длину и значение. Законны переменные типа "указатель на указатель и т. д., сколько уrодно раз" (они позволя ют добиваться лаконичности и выразительности Сипроrраммы) и даже массивы указателей ( тоrда удобно манипулировать не самими элементами, а только их адресами). Например, одномерный массив указателей типа char * char *Pptr[ ]=={"В ", "зыбком ", "мире ", "вещественных ", "чисел ", "осторожность ", "не ", "может ", "быть", "лишней. ,,}; позволяет сэкономить память. Здесь число строк массива равно sizeof(Pptr)jsizeof(Pptr[O]), а имя первой строки есть Pptr[O]. Для матрицы А[3][3] указателямиконстантами на нулевую, первую и вторую строки будут А[О], A[l] и А[2]. Тождественны следующие выражения: А[О] и &А[О][О], A[l] и &A[l][O), А[2) и &А[2][О). К эле менту массива aik можно обратиться по индексу A[I][K), посредством адресноrо выражения *(A[I] + К) (используется указатель на пер вый элемент строки) или с помощью выражения *(*(А + 1) + К) (используется имя массива как адрес начала массива указателей). В случае "куба" А[3][3][3] синонимами имени A[I][J][K] являются: 
341 *(A[I][J] + К), *(*(A[I] + J) + К) и *(*(*(А + 1) + J) + К). Использование указателей полезно и необходимо еще и в следующих случаях: LJ указатель в роли формальноrо параметра функции позволяет вызываемой функции изменять данные вызывающей функции, в частности  реализовать "передачу массива" в вызываемую функцию и обратно; LJ указатель на функцию позволяет "передавать функции" в функ ции; LJ при работе с файлами. Массивы в Фортране Объявление массивов в Фортране имеет две формы  простую (как в Фортране 77) и расширенную (введенную в Фортране 90). Пусть слово тип представляет собой описатель типа integer*l, integer*2, integer*4, integer, real*4, real, double precision, real*8, complex*8, complex, complex*16, logical*l, logical*2, logical*4, logical, character*l, character, character[*zj, имя оператора объ явления массивов dimension или оператора задания общих данных соmmоп. Тоrда простая форма объявления массивов Vl, V2, . . ., V N имеет вид тип Vl(fl1J B l1' f12JB12' ..., flPJBlP)' V2(f21JB21' f22JB22' ..., f2QJB2Q), ..., V n (fnlJ B nl' fn2JBn2' ..., fnrJBnr) rде Hl1, Н12, ..., Нnт  нижние, а Bl1, В12, ..., Вnт  верхние rраницы индексов (целые константные выражения; нижнюю rраницу, равную единице, можно в rраничной паре не писать). Значения размерностей р, q, ..., т' не должны превосходить семи. К примеру, объявим KBak ратные матрицы А, В и С TpeTbero порядка: real*8 А(З,З), В(З,З), С(0:2,0:2) К элементу aik матрицы А можно обратиться посредством иHдex;cи роваННО20 имени A(I, К). Индекс  любое арифметическое Bыpa жение, значение KOToporo должно быть целым. Если теперь словом тип назвать оператор объявления типа inte 
342 ger(l), integer(2), integer(4), integer, real(4), real, double precisi оп, real(8), complex(4), complex, complex(8), logical(l), logi cal(2), logical( 4) или logical, то одна из расширенных форм оббявле нuя массивов Vl, V2, ..., V N может выrлядеть так: тип, dimension(prlJBl' pr2JB2' ..., prpJBp) :: Vl, V2, ..., v n Например: real(8), dimепsiоп(З,З) :: А, В, С(О:2,О:2) Заметим, что матрицы А, Б и С имеют одинаковые тип, размер ности, размер и конфиrурацию. Они называются со2ласованныи.. В объявлении массива  формальноrо параметра  верхние rрани цы MorYT быть переменными. Но при использовании общих областей памяти common rраницы должны быть константами. Массиву можно присвоить на'Чалъные зна'Ченuя. Делается это He сколькими способами, например, так: сhаrасtеr*З T ( 12 )! 'Dec' , Jan' 'Feb' 'Mar' , A p r' 'Ма у ' , , , , , , + 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov'! или с помощью конструктора массива: character(9), dimension(12) :: т=и'Студень', 'Сечень', 'Лютый', + 'Берёзозол', 'Цветень', 'Травень' , 'Червень' , 'Липец', + ' Серпень' , 'Вересень' , , Листопад' , Трудень' !) Можно задать массив строковых констант: character( *), parameter :: T(12) !'Dec', , Jan', 'Feb', 'Mar', , Apr', + 'Ма у ' , Jun' , Jul' , Au g ' 'Se p ' 'Oct' 'Nov' ! , , , , , , Элементы массива  символы character Не ( б )! ' А' 'r' 'а' ' ф ' '0' 'н' ! , , , , , , She ( lO )! 'K' '0' 'н' 'с' 'т' 'а' 'н' ' ц ' 'и' 'я' ! , , , , , , , , , + и снова строки character*8 Р(4)!'Семь', 'бед, ','один', '[RESET].'! заданные еще и так: character(8) :: Р( 4)!'Семь " 'бед, " 'один " '[RESET].'! ДЛЯ дублирования константы можно перед нею через звездочку за- дать коэффициент повторения. MHoroMepHbIe массивы в памяти размещаются" по столбцам" (пер 
343 вый индекс возрастает наиболее быстро, а последний  наименее быстро). Например, объявление "куба" А размера 2 х 2 х 2 real*8 А(2, 2, 2) определяет такой порядок следования элементов в памяти: А(l,l,l), А(2,1,1), А(1,2,1), А(2,2,1), А(1,1,2), А(2,1,2), А(1,2,2), А(2,2,2). ДЛЯ примера зададим 'НД'чдлыtые зна'iения элементам матрицы А = (  ;  ) 789 и единичной матрицы Е: real*8 A(3,3)/ldO,4dO,7dO,2dO,5dO,8dO,3dO,6dO,9dO/, + Е(3,3) / 1dO,OdO,OdO,OdO,ldO,OdO,OdO,OdO,ldO / Передача массива может быть массивовой и скалярной (поэлемент ной). Дадим пример массивовО20 ввода/вывода матрицы А (см. по следнее объявление): program /npuCoutpuCarray implicit попе real*8 А(3,3) read( *,*) А write(*,*) А end В вводном файле элементы матрицы А должны быть набраны по столбцам. При вывще элементы будут упорядочены также по столб цам. Реализуем теперь поэлементную nepeaa'iY массива, выполнив, Ha пример, ввод/вывод матрицы А по строкам. Применим ци'/Сли'iес'/Сиii сnисо'/С. Так называются взятые в круrлые скобки и разделенные за пятой список ввода/вывода и заrоловок цикла вида nеременная=на'iало, '/Сонец(, шаv Этот заrоловок работает точно так же, как в операторе do цикла с параметром (см. nодразд. "Операторы ци'/Сла в Фортране" разд. "Операторы ци'/Сла" ранее в этоii 2лаве). Вот фраrмент необходимо ro решения: read(*,*) ((А(I,К), /{=l,з,l), /=1,3,1) 
344 write(*, *)((А(I,К), К==1,3,1), 1==1,3,1) Здесь представлен двойной цикл: внешний управляется счетчиком 1, а внутренний  счетчиком К. И, наконец, приведем универсальную проrрамму ввода/вывода Ma трицы А: program GeCpuCmatrix ! implicit попе integer*2 Lim, N, 1, К parameter(Lim == 80) real*8 A(Lim,Lim) ! write(*,/(/ / /а\)') / N<==80 ======> / read(*, *) N do 1 == 1, N, 1 do К == 1, N, 1 write(*,/(/a,i3,a,i3,a\)') , А(', 1, ',', К,') ======>' read(*,*) А(I,К) end do end do ! write( *,'(/ /4х,2( a,i3),a/)') do 1 == 1, N, 1 do К == 1, N, 1 write( *,/(lpg24.15\)') А(I, К) end do write( *, *) end do ! end! Declarations: Instructions: ео GeCmatr , Матрица А(l:', N, " 1:/, N, ') :' ео PuCmatr ео program Можно сэкономить память, если обб,я,вuтъ размещаемый массив А: program GetpuCmatrix ! Declarations: implicit попе integer*2 N, 1, К real*8 A[allocatable](:,:) ! write(*,/(/ / /а\)/) / N<==80 ======> / read(*, *) N allocate( А( N, N)) do 1 == 1, N, 1 Instructions: 
345 end do ! deallocate( А) end! ео PuCтatr ео program Здесь MaCCB А сначала заявляется оператором [allocatable](:,:). После считывания значения N оператор allocate(A(N, N)) вычи сляет rраницы индексов и массиву А выделяется память. В конце проrраммы оператор deallocate(A) эту память освобождает. Можно работать с частями массива (сечениями), объявлять массивы с предполаrаемыми размером и конфиrурацией, выполнять присва ивание where по маске, применять циклический список при зада нии начальных значений, использовать массивоподобные функции и т. д. Кроме массивоrо ввода/вывода определены массивовые присва ивание, арифметические, лоrические операции, операции отношения над соrласованными массивами и стандартные массивовые функции (таких функций 24; см. [4,6,42, 62]). Вот некоторые из них: (] функция maxval( v) находит максимальный элемент массива v; (] функция minval( v) определяет минимальный элемент v; (] функция product( v) вычисляет произведение элементов масси ва v; (] функция sum( v) находит сумму элементов массива v; (] функция dotproduct(Vl, V2) вычисляет скалярное произведение векторов Vl и v2; (] функция matmul(vl' V2) перемножает матрицы vl и V2, или Ma трицу Vl и вектор V2, или вектор Vl и матрицу V2; (] функция transpose (v) транспонирует матрицу v. Контрольноезцдание Получите платежную ведомость (payroll) "бриrады" из сказки "Репка". Подсчитайте, сколько Bcero (total) ефимков получит каж дый член бриrады, исходя из доrовореНIЮСТИ: зарплата (wage)  по три ефимка за каждое "тянемпотянем" плюс премия (prize)  200 % от зарплаты. Ведомость должна иметь вид: uuuuuuuuuuuuuПлатежнаяuведомостъ u=========================================== 
346 uuuЧлеНЫuuЗарплатаuuПремияuuВсеrоuuuuПодпись uuбриrадыuuuuuuuuuuuuuuuuu(ефимков) u=========================================== uДедкинuuuuuu18uuuuuuu36uuuuuu54  u uБабкинauuuuu15uuuuuuu30uuuuuu45  u uВнучкинаuuuu12uuuuuuu24uuuuuuЗ6 u uЖучкинаuuuuuu9uuuuuuu18uuuuuu27  u uКошкинauuuuuu6uuuuuuu12uuuuuu18  u uМышкинauuuuuuЗuuuuuuuu6uuuuuuu9  u uuuuuuuuuuuuCYMMauuuuuuuuuuuu189 u=========================================== Ответ program Payroll; { uses crt; const Lim == 20; Nlim == 40; Nl == #13#10; Оnе =='u Two =='u type Ind == l..Lim; Name ==string[Nlim]; Surname == array[Ind] of N ате; var Form: Surname; N, 1, Nl: Ind; Sum, Wage, Prize, Total: word; begin { clrscr; write (NI,NI,NI, , N ======> '); readln (N); writeln (Nl, , Список бриrады ======> '); for 1 :== 1 to N do begin write (Nl, 1, 'ю фамилию ======>'); end; clrscr; writeln (NI,NI, , ПАСКАЛЬпроrрамма: } '. , '. , } readln (Form[I]) { ео ввода} Ответ:'); 
347 { Выведем "шапку" ведомости: } write(NI, 'u': 12, 'Платежная ведомость', Nl, Тшо, Nl, 'uuu ЧленыuuЗарплатаuuП ремияuuВсеrоuuuuПодпись', Nl, 'uuбриrады', 'u' : 17, '(ефимков )' , Nl, Тшо, Nl); { Подсчитаем зарплату, премию, Bcero, } { сумму и выведем "тело" ведомости: } N1 :== succ(N); Вит:== о; for 1 :== 1 to N do begin Wage :== (N1  1) * 3; Prize :== Wage * 2; Total :== Wage + Prize; Sum:== Sum + Totalj writeln('u', Form[I]: 8, Wage: 6, Prize: 9, Total: 8, Nl, Оnе) end; { ео 1 } { Выведем сумму и "основание" ведомости: } writeln ('u': 12, 'Сумма', Вит: 15, Nl, Two, NI,NI,' Все... " NI,NI) end. { ео Payroll } #include <stdio.h> // СИпроrрамма: #include <conio.h> const unsigned int Lim == 20, N lim == 9; / / 9 == 8 + 1 const char *Оnе == "u", *Two == "u "; void main (void) // Payroll { char Form[Lim][Nlim]; unsigned int N, 1, Sum, Wage, Prize, Totalj clrscr(); printf("\n \п \п N ======> ,,); scanf("%u", &N); printf("\n Список бриrады ======> \п"); for (I == о; 1 < N; 1 + + ) { printf("\n %3uю фамилию ======> ", 1 + 1); scanf("%s", Form[I]); } // ео ввода 
348 clrscrO; printf("\n\n Ответ:"); // Выведем "шапку" ведомости: printf("\n\n%12s%s \n%s \n%s \n%s%17s%s \n%s \п", "u", "Платежная ведомость", Two, "uuu ЧленыuuЗарплатаuuПремияuuВсеrоuuuuПодпись" , " uu бриrады", " U ", "(ефимков)", Two); // Подсчитаем зарплату, премию, Bcero, / / сумму и выведем "тело" ведомости: for(Sum == 0,1 == о; 1 < N; 1 ++) { Wage == (N  1) * 3; Prize == Wage * 2; Total == Wage + Prize; Sum + == Total; printf(" %8s%6u%9u%8u \n%s \п", Form[1], Wage, Prize, Total, Оnе); / / ео 1 // Выведем сумму и "основание" ведомости: printf("%12s%s%15u \n%s \n\n%s \п\п", "u", "Сумма", Sum, Two," Все. .. ,,); ео Payroll } } // + + include 'fgraph.fi' ! program Payroll implicit попе integer Lim, N, 1, N1, Summary, Wage, Prize, Total character*( *) Оnе, Two parameter(Lim == 20, Оnе =='u Two =='u character Form * 8(1 : Lim) саН clearscreen(O) write(*,'(j//a \)')' N ======>' read (*, *) N write (*,'и а)') , Список бриrады ======> ' do 1 == 1, N, 1 write (*,'(ji3, а \)') 1, 'ю фамилию ======> ' ФОРТР АНпроrрамма: , , ') 
349 read (*,'( а)') Forт(I) _ end do ! ео ввода саН clearscreen(O) write (*,'(/ j j а)')' Ответ:' c Выведем "шапку" ведомости: write(*,'(/t13,a ja ja ja,17x,a ja)') + 'Платежная ведомость', + Тшо, + 'uuu ЧлеНыuuЗарплатаuuПремияuuВсеrоuuuuПодпись', + 'uuбриrады', '(ефимков )' , + Тшо c c N1 == N + 1 Suттary == О do 1 == 1, N, 1 Wage == (N1  1) * 3 Prize == Wage * 2 Total == Wage + Prize Suттary == Suттary + Total write (*,'(lх, а, i6, i9, i8 ja)') Forт (I), Wage, Prize, Total, Опе end do ! ео 1 c Выведем сумму и "основание" ведомости: write (*,'(12х, а, i15 ja j ja j)') 'Сумма', Suттary, Тшо,' Все... ' end ! ео Payroll Подсчитаем зарплату, премию, Bcero, сумму и выведем "тело" ведомости: Строковые функции По оценкам специалистов до 70 % времени компьютер расходует на обработку текстовых строк: копирует их, проверяет наличие в CTpO ках определенных слов, сцепляет и усекает строки, выделяет их ча сти и т. п. Для работы с символами и строками языки проrрамми рования предлаrают специальные средства. СТРОКОБые функции Паскаля 1..... символам Паскаля применимы функции ord( символ), chr( к:од), rдe к:од имеет тип byte, succ( си.мвол), pred( символ), а также функ 
350 ция upcase( стро'Чна.я латuнсх:а.я бух:ва), возвращающая прописную латинскую букву. Любой друrой символ upcase не обрабатывает, а предлаrает ero своим значением. !{ строх:а.м можно применять операцию сцепления + (например, 'Репка, '+'дедка, , + 'бабка, , + 'внучка и т. д.') И функцию кон- катенации сопсаЦстрох:аl, строх:а2, ..., строх:а n ) (к примеру, зна- чением функции сопсаt('буй', 'вол') будет 'буйвол'). Длина строки- результата этой функции не должна превосходить 255 символов. Используя функцию length( строх:а), можно найти текущую длину строх:и. Тип результата  integer. Например, значение функции length(' April fool"s day.') равно 17. Из строх:и посредством функции сору( строх:а, n, 1) можно вы- резать 1 символов, начиная с n-ro символа строх:и. К примеру, функция сору('ТЯНИТОЛКАЙ', 2, 2) даст 'ЯН', а функция co ру('ТЯНИТОЛКАЙ', 8, 3)  'КАЙ'. Функция pos( nодстрох:а, строх:а) определяет первое вхождение под. строх:и в строх:у. Результатом ее выполнения будет номер позиции, с которой nодстрох:а начинается в строх:е. Например, значение функ- ции pos('pOM', 'бром') равно 2. Процедура insert(noacтpox:a, строх:а, n) вставляет nодстрох:у в строх:у, начиная с n-ro символа строх:и. Например, после выпол- нения фраrмента проrраммы var 5 : string; ... , 5:== 'Казнить нельзя помиловать.'; insert (',', 5, 15); значение 5 станет равным 'Казнить нельзя, помиловать.'. Процедура delete( строх:а, n, 1) удаляет 1 символов строх:и, начиная с n-ro символа. К примеру, в результате выполнения операторов 5 :==' АЙСЕДОРА'; delete(5, 1, 4); значением 5 станет строка 'ДОРА'. Процедура str(x[: w[: d}}, строх:а) преобразует число х целоrо или вещественноrо типа в строх:у так, как это делает процедура write перед выводом (с.м. nодразд. "Ввод/вывод в Пасх:але" разд. "Стандартныи ввод/вывод" zлавы 5). Например, оператор про- цедуры str(123, 5) даст 5 значение '123'. 
351 Процедура val(cmpo1\:a, х, флаЖО1\:) трансформирует стРО1\:У во BHY треннее представление целочисленной или вещественной перемен ной х. Если преобразование прошло успешно, флаЖО1\: равен нулю; в противном случае он содержит номер ошибочноrо символа стРО1\:и, а значение х не определено. К примеру, при выполнении оператора процедуры val('123', N, Code) переменная N получит значение 123, а Code  О. И, наконец, в качестве примера работы со строками приведем про rpaMMY Stringl , которая на месте исходной строки (например, CTpO ки 'Натан Отто Тит') строит инвертированную строку ('тиТ оттО натаН'): program Stringl; const Lstr == 80; Nl == # 13# 1 о; var 5: string[Lstr]; R: char; L, 1: byte; begin write(Nl, Nl,Nl,' S =====> '); readln(5); writeln (Nl, Nl, , Исходная строка:', Nl, 5); L :== ord(S[O]); { L :== byte(length(5)); } 1 :== 1; while 1 <== (L div 2) do begin R :== 5[1]; 5[1]:== 5[L  1 + 1]; 5[L  1 + 1] :== R; inc(1) end; writeln (Nl, , Реверсированная строка:', Nl, 5) end. Здесь после ввода строки сначала определяется ее длина L, а затем строка "переворачивается". СТРОКОБые функции Си в Си строковая константа в памяти компьютера представляется массивом элементов типа char, в конце KOToporo находится нуль терминатор '\0'. с константой связан указательконстанта на первый элемент массива. Адрес первоrо символа в зависимости от предна значения строковой константы используется поразному [24]. Так, если она при меняется при задании начальных значений (по друrому, инициализации) сhаrмассива, то адрес первоrо символа становится синонимом имени массива. Например, эквивалентны следующие три 
352 объявления: char 5[] == "Ура!"; char 5[5] == "Ура!"; char 5[5] == {'У', 'р', 'а', '!', '\О'}; Коrда строковая константа участвует в инициализации указателя типа char *, адрес первоrо символа константы есть начальное зна чение указателя. К примеру, объявление char *5 == "Разрешить, нельзя запретить. "; представляет переменнуюуказатель 5. Она получает начальное значение, равное адресу символа 'Р'. Сама же константа находит ся в cerMeHTe данных заrрузочноrо модуля проrраммы [24]. И, наконец, коrда строковая константа используется в тех местах выражения, rде разрешен указатель, компилятор подставляет в BЫ ражение вместо константы адрес первоrо ero символа. К примеру дано: char *5; 5 == "Тайцы  rород контрастов."; Здесь при выполнении присваивания в область памяти, зарезерви рованную для указателя 5, передается не массив символов, а YKa затель на ero начало, т. е. адрес символа 'Т'. Имя массива  пример указателяконстанты, поэтому ошибкой бу дет использование ero в некоторых операциях адресной арифметики. Например, невозможна следующая "пересылка" строки символов в массив: char 5[81]; 5 == "It is easy!"; Забеrая вперед, приведем одно из правильных решений, в котором задействована фунцuя копирования: strcpy(5, "Леrко!II); Си боrат строковыми функциями. Их прототипы находятся в заrо ловочном файле <string.h>. Функция в роли aprYMeHToB получает, как правило, указатели н-а строки. Коrда строковая константа не завершается символом '\0', обработка строки может длиться сколь уrодно долrо. Если при выполнении некоторой функции будут передаваться сим волы от строкиисточника строкемишени, перед назначением нуж 
353 но позаботиться о резервировании места в памяти для мишени, не забывая о нультерминаторе. Даже опытные проrраммисты делают ошибки, связанные с неинициализированными указателями, двой ственными ссылками и неосвобождением памяти, запрошенной pa нее посредством функций mаllос или саllос, коrда указатель уже больше не нужен: frее(ух;азатеЛЪ)j. Поэтому, работая со строками, "не отмахивайтесь" от системных предупреждений вида "Suspicious pointer conversion" (Подозрительное преобразование указателя) и "Possible use of . .. before definition" (Возможное использование YKa зателя до определения, инициализации). Для обработх;u сuмволов и строх; Си предлаrает более 40 функ ций. Рассмотрим кратко некоторые из них. Сначала определим код какоrонибудь символа: printf("\n Код '%с' есть %d.\n", '@', '@'); Функция strlwr() преобразует прописные латинские буквы в латин ские строчные. Например, значением функции strlwr ("ClrScr") бу дет строка "clrscr t '. Функция strupr()  антоним функции strlwr(). К примеру, strupr("file") даст строку "FILE". Операндами отношений MorYT быть символы. Например, следующее отношение "Т">"Д" истинно, так как код буквы Т  146, а Д  132. Функция strcmp() сравнивает Cmp0X;Yl со строх;ой 2 , различая про писные и строчные буквы. Она возвращает ноль типа int, если CTpO ки идентичны; положительное число, если CmpOX;al>Cmp0X;U2 и отри цательное число, если CmpOX;al <строх;и2. К примеру, 14  значение функции strсmрС'Тиrода", "Днепр ,,), так как 146  132 == 14. Функция stricmp() сравнивает две строки, не различая реrистры. Например, значение функции stricmpC'Russia", "RUSSIA ") есть о. Функция strncmp() сравнивает заданное число символов двух строк, различая прописные и строчные буквы. К примеру, значение функции strпсmр("Афиноrен", "Афины", 4) равно о. Функция strnicmpO сравнивает заданное число символов двух строк, не различая реrистры. Произвольное число строк можно "склеить" так: 
354 "конь" "як" или так: "мышь\ як". Функция strcatO присоединяет стРО'К:У2 в конец стро'К:иl' Например, функция strcat("MAPK", "ШЕЙДЕР") сцепляет две строки в одну "МАРКШЕЙДЕР". Фу'Нхцu-я strncatO присоединяет заданное число символов стро'К:и2 в конец сmРО'К:Иl' Например, результатом работы следующеrо фраr мента проrраммы S == strncat('"I, "политехник", 4); puts(strncat(S, "шинель", 6)); будет слово "полишинель". Функция strlenO возвращает текущую длину стро'К:и. К примеру, 17  значение функций strlen("April fool's day.") и strlen("April fool\"s day."). Функция strcpyO копирует стРО'К:У2 в стРО'К:Уl, возвращая YKa затель на начало скопированной в стРО'К:Уl строки. Например, strcpy(S, "ДЛИННОШЕЕЕ") и strcpy(S1, "rеорrий"). Функция stpcpyO копирует стРО'К:У2 в стРО'К:Уl, возвращая указа тель на конец скопированной в стРО'К:Уl строки. Функция strncpyO копирует заданное число символов сmРО'К:И2 в стРО'К:Уl' К примеру, после выполнения операторов strncpy(S, S1, 5); S[5] == '\0'; puts(S); будет выведено имя ''reopr''. Если же не вставить в конец новой CTpO ки нультерминатор, то результатом вывода будет ''rеорrОШЕЕЕ''. Функция strchrO возвращает позицию первоrо вхождения символа в стро'К:у. Функция strrchrO отыскивает последнее вхождение символа в стро'К:е. Функция strspnO возвращает позицию первоrо символа в стро'К:е, который не принадлежит заданному набору символов. Функция strcspnO находит позицию первоrо вхождения символа из заданноrо набора символов. 
355 СРункция strpbrkO определяет место первоrо вхождения любоrо символа из заданноrо набора. Функция strstrO находит место первоrо вхождения cтpoи2 в cтpo Yl' Например: puts (strstr("ИСИДОРА", "СИДОР")); и результат: "СИДОРА". Функция strsetO помещает символ во все позиции cтpoи. Функция strnsetO помещает заданный символ в заданное число по зиций cтpoи. Функция strrevO реверсирует cтpoy, т. е. создает прочитанную с последнеrо символа cтpoy. Например, функция strrеv("хорош") и ее значение "шорох". Функция strtokO выделяет лексему в строке, на начало которой указывает cтpoal (лексема  фраrмент cтpoиl, оrраниченный с обеих сторон любым из символов в строке, на начало которой YKa зывает cтpoa2)' Функция strerror() по заданному номеру системной ошибки возвра щает указатель на строку текста сообщения об ошибке. Например, оператор fprintf(stderr, "\п *** errror: %s\n", strerror(errno)); посылает сообщение об ошибке на стандартное устройство вывода ошибок. Функция strerrorO возвращает указатель на строку, образованную объединением произвольной строки и сообщения об ошибке в библио течной функции. Фунжции nреобразованuя данных служат связующим звеном между двумя формами представления чисел. Их прототипы описаны в фай ле <stdlib.h>. Функции itoaO, ItoaO и ultoaO преобразуют соответственно int, long int и unsigned long iпt'Число в cтpoy символов. Например, функции itoa(l23, 5, 10), Itoa(123L, 51, 10) и ultoa(123UL, 52, 10) дают строку "123". Функции atoiO, atolO и atofO преобразуют cтpoy в число. К при меру, функции atoi("123") и atol(1123") выдают число 123, а функ 
356 ция atof(" 123")  число 1.230000е+02. Кроме Toro, в Си определены функции ecvtO, fcvtO, gcvtO, strtodO, strtolO и strtoulO (см. [28,24,48,67,55,50]). Приведем Сипроrрамму Stringl реверсирования строки В: #include <stdio.h> const unsigned L8tr == 81; void main (void) / / Stringl { char S[L8tr], R; unsigned L, 1; printf("\n\n\n S ======> "); gets(S); printf("\n\n Исходная строка:\п %s\n", В); for (L == о; S[L]!== '\0'; L ++); / / L == strlen(S)j for(I == о; 1 < L/2; 1 ++) { R == S[I]; S[I] == S[L  1  1]; S[L  1  1] == R; } printf(" Реверсированная строка:\п %s\n", В); } Теперь применим функцию strrev реверсирования строки. Полу чим лаконичную и эффективную проrрамму String2: #include <stdio.h> #include <string.h> void main (void) / / String2 { char *В; printf("\n\n\n S ======> ,,); gets(S); printf("\n\n Исходная строка:\п %s\n", В); strrev (В); printf(" Реверсированная строка:\п %s\n", В); . } Строковые функции Фортрана J( символам и строх;ам в Фортране применимы все операции OTHO шения и четыре функции сравнения 1ge(81,82), 19t(81, 82), llе(81,82) и llЧ81,82), rде 81, 82  либо символы, либо строки 6 . Например, значение функции 19t('MocbKa', 'Слон') равно F. Функция iachar( символ) возвращает целое число, равное ASCII коду символа. бв имени функции первая буква 1 от logical. 
357 Функция ichar( сuлt60Л) возвращает целое число, равное коду СИМ вола из поддерживаемой ОС таблицы символов. Функция achar(i) возвращает символ, код KOToporo в таблице ASCII кодов равен z. Функция char(i) подобна функции achar(i). Сцепить символы и строки можно посредством операции KOHKaTeHa ции //. К примеру, в результате выполнения фраrмента проrраммы character 5*13 5 == 'Pora' //' & '//'Копыта' переменная 5 получит значение 'Pora & Копыта'. Функция lentrim( строх:а) находит длину строх:и. Например, 1 О  значение функции lепtrim('Пост' //'факт' //'ум'). Из строки v можно выделить подстроку, если воспользоваться син таксической конструкцией вырезки v (f ] : (J J) Здесь i задает номер позиции первоrо символа подстроки, а J номер последнеrо. Например, 5(1 : 4) == 'Pora', 5(8 : 13) == 'Копыта', 5 (:) == 'Pora & Копыта', 5(8 :) == 'Копыта & Pora'. Функция index( строх:а, nодстрох:а (, флаJfCОХ: J) возвращает номер позиции, с которой в строх:е начинается первое вхождение noдcтpo х:и. Если флаJfCОХ: отсутствует или равен .false., поиск ведется в Ha правлении слева направо, и в обратном направлении,  если фла JfCox: есть . true. Кроме Toro, Фортран имеет функции adjustl, adjustr, repeat, всап, trim и verify (см. [4, 42, 62, 6]). В заключение дадим Фортранпроrрамму Stringl, реверсирующую строку 5: program 5tring1 implicit попе integer L, 1, J character 5*80, R write(*,'(///a\)') , S ======>' read (*,'(а)') 5 write(*, '(/ /а /lх,а)') , Исходная строка:', 5 
358 L == lentrim( 5) 1 == 1 do while(/ .le. L/2) R == 5(/:1) J==LI+1 5(/:1) == 5( J:J) 5( J:J) == R /==1+1 end do write( *,'( а /lх, а)') , Реверсированная строка:', 5 end Упражнения Решите приведенные ниже задачи. 1. Сцепите два слова (например, лом и бард, бакен и барды). В HO вом слове подсчитайте число rласных и соrласных букв. 2. В некотором тексте (например, Нет плохих языков проrраммиро вания) буквы а, и, е, у, л, с, Ш, т, х, ф, п замените соответственно буквами о, ы, Э, Ю, р, з, ж, д, т, в, б и наоборот. 3. Проверьте, является ли частью данноrо слова некоторое подсло во (например, если подсловом является Рина, то для слов Арина, Викторина, Дарина, Екатерина, Зарина, Ирина, Карина и Марина ответ будет Да, а для слов Азарий, Валерий, Триrорий, Турий, Дa рий, Дмитрий, Иларий и Порфирий  Нет). 4. Проверьте, есть ли в некотором слове повторяющиеся сочетания букв (список слов: Ананий, Архип, Барбара, Варвара, Вахтант, Be вея, Теракл, Кондрат, Лайма, Лилия, Мамука, Нана). 5. В некотором тексте (например, Требование объявлять явно типы всех объектов приводит к избыточности в Фортранпроrрамме, KOTO рая, однако, делает ее надежнее) найдите rлаrолы внеопределенной форме. 6. В некотором тексте (например, За все надо платить, ничто не дa ется даром, или, подруrому, бесплатный сыр бывает только в MЫ шеловке) найдите непроизводные предлоrи без, в, до, для, за, из, к, на, над, о, об, от, по, под, пред, при, про, с, у, через. 
359 7. В словах HeKoToporo текста (например, Спешите кодировать, OT лаживайте в часы досута) найдите приставки над, о, от, пере и под. 8. В словах HeKoToporo текста (например, Тот, кто использует про трамму, не ясновидец) выделите суффиксы aK, ач, ение, eц, иц, ица, ист, лец, OK, OCTЬ, ние, ниц, ница, тель, чик и щик. 9. В некотором тексте (например, Ваша проrрамма коrданибудь MO жет стать проrраммой, написанной друrим человеком) найдите при тяжательные местоимения мой, твой, ваш, наш, свой, ею, ее, их. 10. В некотором тексте (например, Мыслители встречаются редко, деятели  реже, а мыслителидеятели  совсем редко) выделите противительные союзы а, но, да, однако же, зато. 11. В некотором тексте (например, Ни одна система не остается He изменной) определите отрицательные частицы не и ни. 12. В некотором тексте (например, Эй, проrраммист, rотовься к OT ладке!) выделите междометия ах, ай, ба, о, ох, эх, эй. 13. Составьте Проrрамму, формирующую идентификаторы вычерки ванием rласных букв из заданных n слов. 14. Из списка имен выберите палиндромические имена (например, Ada, Алла, ВаЬ, ВоЬ, Nал, Pip, Аза, Алла, Аскольд, Йоко, Ирма, Лука, Она, Пантелеймон, Эдвард); палиндром, т. е. перевертыш. 15. В некотором тексте (например, Первое  учиться. Второе  учиться. Третье  учиться. Паисий Лиrерид. ХУIII век) замените прилаrательные по правилу "числое". 16. Подсчитайте, сколько раз в некотором слове х встречается ПОk слово У (например, х == Титикака, у == ти, х == Макака, у == ка). 17. Прочитайте текст, заканчивающийся тильдой  (например, Про rраммирование  это способ связи человека с компьютером. Оно, в известной мере, является неизбежным злом, поэтому нужно сделать ето насколько возможно малым). Подсчитайте в нем число букв и символов, процентное содержание rласных и соrласных букв. 18. В некотором тексте (например, Ничеrо не принимайте на Be ру. Проrрамма, свободная от ошибок,  абстрактное теорети ческое понятие) уменьшите число пробелов между словами до OДHO ro. Подсчитайте число слов. Найдите самое короткое и самое длин ное слово. 
360 19. В некотором тексте (например, После тщательноrо проектирова ния мотут оставаться только простые, "rлупые" ошибки) выясните распределение слов по длине (сколько слов, состоящих из одной бук вы, сколько  из двух и т. д.). 20. В некотором тексте (например, Котда отладка завершена, KOM пьютер, несомненно, решает какуюто задачу) подсчитайте число сдвоенных символов. 21. Напишите проrрамму посимвольноrо преобразования "кирилли цы" в "латиницу" (например, Никодим  Nikodiт, rерасим  Gera siт, Инrа  Iпgа, Клим  Кliт, Флор  Fl0r, Ярослав  Yaroslav, Адам  Adaт, Ева  Eva). 22. Введите некоторый текст (например, Все жалуются на свою па мять, но никто не жалуется на свой разум) и выведите ero в коде Морзе: Условная телеrрафная азбука Сим Знак Сим Знак Сим Знак Сим Знак вол Морзе вол Морзе вол Морзе вол Морзе А Н Ы ........... 9 .................... Б О ЬЪ о .................................................. В П Э r р ю ...................... ......... д С Я ..................... ........... ЕЕ Т 1 ..................................... .............................. . ж у 2 . ............................... ? . ....................... З Ф 3 .. ..................... N ...................... . и х 4 ..................................... . й ............................. ц 5 () .......... .............................. к ч .............................. . 6 , .................... ...................... л ш .................................. 7 ...................... . М Щ .................... ........... 8 .......................... .. / .................... . 23. Составьте Проrрамму, которая к каждому слову HeKoToporo TeK ста (например, Большую систему полностью оттестировать невоз можно) добавляет сочетание TO. 24. Проверьте, можно ли из букв, входящих в х, составить у (напри 
361 мер, х есть 3венислава, а у  Слава). Буквы можно переставлять, но любую букву разрешается использовать не более одноrо раза. 25. Составьте проrрамму, утраивающую каждое слово в заданном тексте (например, было НипаЫ, должно получиться Hurrah! Hur rah! НипаЫ). 26. Напишите проrрамму, которая бы ВВОДИла, выводила шестнадца теричные числа и переводила их в десятичную систему счисления. 27. Напишите проrрамму преобразования n целых чисел в строку символов (например, 273 есть минус двести семьдесят три). 28. Дано n чисел, представленных в фиксированной форме. После каждоЙ тройки цифр вставьте в последовательность цифр пробел, начиная от точки и двиrаясь влево и вправо. 29. Дано n чисел, записанных в экспоненциальной форме (в науч ной нотации). После каждоЙ пятерки цифр вставьте в запись числа пробел. 30. Начертите окружность радиуса R (rрафический пакет использо вать нельзя). 
362 r лава 8 Кодирование подчиненных алrоритмов Все языки проrраммирования имеют средства для записи подчинен ных алrоритмов (см. славу 4) в форме подпроrрамм  функций и процедур. Подпроrрамма Паскаля Подпроrрамма Паскаля объявляется в декларативной части блока. Она по своей структуре подобна rлавной проrрамме, т. е. тоже co стоит из заrоловка и блока (см. подразд. "Пасх:альпросрамма" разд. "Струх:тура и запись просраммы" славы 5). Рассмотрим сначала, как в Паскале определяется функция. ФУНКЦИЯ Функция  это представленный Паскалем подчиненный алrоритм функция, задающий правило вычисления простоrо, CTpoKoBoro зна чения или типа указатель. Она устроена следующим образом: function f [( списох: формаль'Н-ых параметров )}: тип; [дех:ларатив'Н-а.я часть} begin операторы end; 
363 Имя 1 в заrоловке function есть имя функции. Здесь же определя ются возможные формальные параметры и тип результата выпол нения функции. Список фор.малыtыlx пара.метров состоит из разделенных точкой с запятой подсписков, в каждом из которых перечисляются через запятую (если параметров несколько) параметры шести допусти мых видов  значения (V1, V2, ..., Vk: типпара.метра), перемен ные (var Vi, Vi+1, ..., v[:munnapaMempa), нетипизированные пере менные, константы (const С1, С2, ..., С т : типпара.метра), функ цИИ (Л, 12, ..., In: функционалыtыl1 тип) и процедуры (jj, Ij+1, . . . , I p : процедурныl1 тип), причем тип пара.метра, Функционалъныi1 тип, npov,eaYPHtli1 тип есть имя типа, т. е. просто имя, что, к при меру, означает следующее. Пусть в строковую функцию F переда ется строка 5. Тоrда типами параметра и результата должен быть стандартный тип string и/или типы, определенные пользователем, скажем, так: . . .; type 5tr13 == string[13]; 5tr28 == string[28]; ...; function F (5 : 5tr13) : 5tr28; ... Точно так же, если параметром является составной объект (напри мер, массив), то следует первоначально определить ero тип. Замена формальных параметров фактическими (параметрами, за данными в точке вызова функции) производится либо по зна 'Чению, либо по ссыlке.. Если перед rруппой формальных пара метров Vl, V2, ..., Vk ключевое слово var или const отсутствует, то речь идет о пара.метрахзна'Ченu.ях. Они представляют входные дaH ные. Б этом случае соответствующие фактические параметры (COOT ветствие устанавливается по числу, положению в списках и типу) суть выражения. При обращении к функции каждому параметру значению выделяется область памяти (некоторая внутренняя пере менная), куда и копируется текущее значение фактическоrо пара метра. Так как все операции в теле функции выполняются только над переменнойкопией, то значение фактическоrо параметра изме ниться не может. Значит, параметрзначение нельзя использовать в роли результата. Б rруппу параметровзначений MorYT попасть и параметры, имена которых находятся слева от знака присваивания, но при этом изме нение их входных значений в результате побочноrо эффекта нежела 
364 тельно (например, если система линейных алrебраических ypaBHe ний решается методом [аусса [21], то матрица коэффициентов систе мы и векторстолбец ее свободных членов "портятся", а эти объекты должны еще участвовать в контроле решения). С друrой стороны, в случае параметра cocTaBHoro типа, например, массива, не peKOMeH дуется включать ero в rруппу параметровзначений, поскольку при большой длине массива операция копирования cocTaBHoro объекта потребует весомых затрат времени и памяти компьютера. Рассмотрим теперь замену параметров по ссылке (по друrому, по адресу). Если перед rруппой формальных параметров указано сло во var, то речь идеТ о napaMeтpaxпepeMeHHЫX. Они, как правило, именуют выходные данные (для функции это побочный результат). Такие фактические параметры должны быть переменными (с разны ми именами). При вызове функции вычисляются их адреса (напри мер, подсчитываются значения индексов). Именно они (а не копии переменных) передаются в тело функции. И тоrда любое действие над формальным параметром переносится на соответствующий фак тический параметр. Существуют такие алrоритмы, коrда параметрпеременная будет входным и одновременно выходным формальным параметром. Подсписок файловых параметров всеrда должен начинаться словом var, т. е. файл или составная переменная с файловыми компонента ми не может быть параметромзначением. Проблема передачи одномерноrо массива произвольной длины pe шается посредством от1'ёрытосо массива. Последний представля ет собой формальный параметр, специфицированный как array of тип элементов, например: . . .; А : array of extended; . . . в теле функции такой параметр трактуется как одномерный Mac сив с нулевой нижней rраницей индекса и с верхней rраницей, paB ной значению функции high(A). Массив переменной длины большей размерности можно передать, если в определении типа массива YCTa новить максимально возможные верхние rраницы индексов. Универ сальным приемом в этом случае будет, очевидно, использование YKa зателей и индексной арифметики. Нетипизированные параметры здесь не рассматриваются [58, 59]. 
365 в случае napaMeтp061COHcтaHт в функцию передаются адреса областей памяти, содержащих значения выражений. Компилятор блокирует присваивание таким параметрам новых значений в теле функции. Подсписок nараметРО6фУН1С'I.{иl1 (фактические параметры в этом случае  имена функций) специфицируется фУН1С'I.{ионалъным ти nом, а napaMeтp06npO'l.{eдyp (фактические параметры  имена про цедур)  nрО'l.{едурнъtМ типом. Для объявления подпроrраммноro типа используется заrоловок подпроrраммы, в котором опускается ее имя: type им,я фУН1С'I.{ионаЛЪНО20 типа == function[( сnисо1С формалъных nараметРО6)}: тип; им,я nРО'l.{едУРН020 типа == pr,ocedure[( сnисо1С формалъных nараметРО6)}; Например, объявление функциональноro типа и заrоловок функции Ralston (см. разд. 11 ФУН1С'I.{ионалъна.я схема" и "АЛ20ритмфУН1С'I.{и,я и аЛ20ритМnРО'l.{едура" 2ла6Ы 4) MorYT быть такими: {$F+, N+} .., , type Риnс == function (Х: extended): extended; ...; function Ralston (А, В, Eps: extended; N: word; Р: Риnс): extended; Переменным подпроrраммных типов можно присваивать имена функций и процедур. После TaKoro присваивания имя переменной становится синонимом имени подпроrраммы. Из имен подпроrрамм можно сформировать, к примеру, константный массив подпроrрамм Horo типа и использовать ero элементы для орrанизации обращений к подпроrраммам в соответствии с заданным законом вызовов: program ArTaysubprogram; {$F+} const N == 3; type Ind == 1. .N; Риnс == function ( . .. ): тип; var 1: Ind; function Рl ( . .. ): тип; ... end; 
366 function F2 ( ... ): тип; ... end; function F3 ( ... ): тип; ... end; const Arrf: array[Ind] of Func == (Fl, F2, Р3); begin ... ArrJ[I](... ) ... end. Заканчивается заrоловок функции объявлением ее типа: тип pe зультата выполнения функции может быть порядковым, веществен ным, строковым или указатель. За заrоловком функции следует блок, состоящий из разделов объ явления меток, констант, типов, переменных, подпроrрамм (их коли чество и порядок следования произвольный) и раздела операторов. Все имена, объявленные в блоке, а также формальные параметры локальны по отношению к объявлению функции, которое является областыо деi1стви-я этих имен. Вне этой области они неизвестны. Значит, значения локальных объектов в начале раздела операторов не определены. Внутри же раздела локальные переменные получат какието значения, которые после выхода из блока теряются. По скольку (по определению блока) подпроrраммы MorYT вкладывать ся друr в друrа, то вложенными будут и области действия. Каждой такой области можно приписать соответствующий уровень вложе ния. Самый внешний блок, задаваемый rлавной проrраммой, имеет уровень О (он не входит ни в какой друrой блок и поэтому называ ется 2лобалъным); следующий (уже вложенный) блок имеет уровень 1 и т. д. При этом объекты, объявленные на уровне k, локальны на этом уровне и rлобальны для уровней с более высоким номером. rло бальные переменные известны везде, кроме тех внутренних блоков, в тексте которых используются формальные параметры или объ являются переменные с точно такими же именами, что и rлобальные переменные, т. е. коллизия имен всеrда разрешается в пользу имен локальных объектов. к онтр оль ныИ вопрос Чем похож и чем отличается формальный параметр от локальной переменной? Ответ Параметр схож с локальной переменной: он создается при входе в функцию, может использоваться в ее теле и исчезает при выходе 
367 из функции. Первое отличие состоит в том, что параметрзначение имеет начальное значение (оно равно значению фактическоrо па раметра), тоrда как начальное значение локальной переменной не определено. Второе отличие  типом параметра может быть только имя типа (стандартноrо или определенноrо пользователем), а в роли типа локальной переменной допускается и неименованный тип. Раздел операторов задает действия, которые нужно произвести при вызове функции. Этот раздел должен содержать хотя бы один опе ратор присваивания вида f :== а rде f  имя функции, а  выражение. Именно это присваивание определяет результат выполнения функции. Присваивание значений rлобальным переменным и/или параметрампеременным также MO жет быть результатом работы функции, но уже дополнительным. Такой результат выдачи информации во внешнюю среду является побочным (волновым) эффектом выполнения функции. Как прави ло, за оператором f:== а следует оператор возврата exit, пере дающий управление и значение функции в точку вызова. Роль exit выполнит и последняя концевая скобка тела функции, если на end попадет управление. Для вызова Фунх:'Ции (подруrому, для активизации ее объявления) применяется первичное выражение, состоящее из имени функции f и возможноrо списка фактических параметров: f [(и1, и2, ..., и п )} Здесь любое и1, и2, ..., и п  выражение, переменная cocTaBHoro типа и (или) имя подпроrраммы. Так как фактические параметры "подставляются" вместо соответствующих формальных параметров, то списки параметров должны быть соrласованы. После отработки механизма передачи параметров образуется модифицированное тело функции, которое и выполняется. Например, обращение к функции Ralston может быть таким: L:== Ralston (1.0, 2.0, 1e6, 10, Р); Приведем решение задачи нахождения остатка посредством функ ции Modulo (с,м. разд. "Алсорит'мфУНХ:'ЦU.я u алсорит'мnро'Цедура" славы 4): 
368 program Риnс; { Паскаль: } const NI : string == #13#10; var 1, J, L, К : longintj function Modulo(M, N: longint): longintj { } begin Modulo:== М  (М div N) * Nj exit endj { ео Modulo } begin write(NI,NI,NI, ' Положительные 1, J, L ======> '); readln(l, J, L)j К:== Modulo(13, I) + Modulo(J + 1, L); writeln(NI,' 1==', 1,' J==', J,' L==', L,' Ответ: К==', К) end. { ео program } Теперь дадим рекурсивную функцию Fact, вычисляющую значение n! (см. разд. "Рекурсu,я" 2лавы 4): {$5+ } { контроль переполнения стека} program RecursiveFact; { Паскаль: } var N: longint; function Fact(N: longint): longint; { } begin if (1 < N) and (N < 13) then Fact:== N* Fact(N  1) else if(N == 1) or (N == О) then Fact :== 1 else begin writeln(#13#10' *** error: arg==', N,' Fact.'); halt end; { ео N <О или N>==13 } exit endj { ео Fact } begin repeat 
369 write( #13#10' O<==N <==12 ======> '); writeln(#13#10,N, '!==', Fact(N)) until eof end. { readln(N); { (Ctrl) + (z) } ео program } Процедура Процедура  это записанный Паскалем алrоритм вычисления He скольких значений (в частности, одноrо или ни одноrо). Она во MHO rOM подобна функции. Вот ее структура: procedure f [( сnисо'!'; фОрМальных nараметрО6 )}; [де'J';ларати6ная 'Часть} begin операторы end; Но в отличие от функции заrоловок процедуры начинается словом procedure и не содержит объявления типа результата. Кроме TO ro, в разделе операторов не может быть операторов присваивания, в левой части которых написано имя процедуры f. Есть отличие и в способе вызова  обращение к процедуре производится оператором процедуры вида: f [(и1, и2, ..., И п )} rде и1, и2, ..., и п  возможные фактические параметры. Заме тим, что результат работы процедуры есть действие волновоrо (по друrому, побочноrо) эффекта. Например, объявление функциональ Horo типа, заrоловок процедуры Ralston и обращение к ней теперь будут выrлядеть так: {$F+,N+} ...; type Риnс == function (Х: extended): extended; ...; procedure Ralston (А, В, Ерв: extended; N: word; Р: Риnс; var 1: extended); ... , Ralston (1.0, 2.0, 1e6, 10, Р, L); ... Снова решим задачу вычисления остатка, но сделаем это с помощью процедуры Modulo: program Proc; { Паскаль: } const Nl == #13#10; var 1, J, L, 10, К2, К : longint; 
370 procedure Modulo(M, N: longint; var К: longint); { begin К:==М  (М div N) * N; exit end; { begin write(NI,NI,NI, , Положительные 1, J, L ======> '); readln(l, J, [); Modulo(13,1,/0); Modulo(J + 1, L, К2); К :== К1 + К2; writeln(NI, , 1==', 1,' J==', J, , L==', L, , end. { } ео Modulo } Ответ: К==', К) ео program } А теперь приведем фраrмент объявлений, заrоловок и оператор про цедуры ввода матрицы А размера т х п: ... , const Lim == 80; . . . , type Ind == l..Lim; Matr == array[/nd,lnd] of extended; var А: Matr; .. . , procedure GeCmatr (var А : Matr; М, N : Ind); '.' , GeCmatr (А, N, N); .. . Обращение к любой подпроrрамме можно написать раньше ее объ явления, если приведено оnереJfCающее обо,я,вленuе подпроrраммы. Оно состоит из ее заrоловка, который дополняется стандартной ди рективой forward;. А собственно заrоловок подпроrраммы будет Te перь состоять из слова function или procedure, имени f и точки с запятой. Таким образом, подпроrрамму Паскаля можно уподобить ящику с непрозрачными стенками [58], непрозрачным днищем, возможными окнами в нем и зеркальной крышкой: снаружи подпроrраммы не видна ее внутренность, но попав в подпроrрамму, можно наблюдать все, что делается наверху (подпроrрамме доступны объекты BepXHe ro уровня, они определены до объявления данной подпроrраммы). Правда, приоткрыв какоенибудь окошко (применив опережающее объявление forward), можно заrлянуть еще и вниз, под днище, и вызвать предварительно объявленную подпроrрамму. 
371 к онтрольныJl вопрос Какие значения А, В, С и D будут выведены следующей GlobalLocal проrраммой: program GlobalLocal; { const W == 2; var А, В, С, D, Е : longint; procedure F(D: longint; var Е: longint); { var С: longint; begin В :== 6; С:== 7; D:== 8; Е:== 9; writeln(' 2)', А : W, В : W, С : W, D : W, Е : W); exit end; { begin А :== 1; В:== 2; С:== з; D:== 4; Е:== 5; writeln(' 1)', А: W, В: W, С: W, D: W, Е: W); F(D, Е); writeln(' З)', А : W, В: W, С : W, D : W, Е : W) end. { Паскаль: } } ео F } ео program } Ответ 1) 1 2 3 4 5 2) 1 6 7 8 9 3) 1 6 3 4 9 Подпроrрамма без (формальных) параметров, использует, наверное, rлобальные объекты. В заключение отметим, что в Паскале допускаются внутренние и внешние подпроrраммы. Носителем внутренних подпроrрамм явля ется rлавная проrрамма: они вложены в ее декларативную часть и, возможно, еще и друr в друrа. В роли внешних подпроrрамм допуска ются процедуры и функции, представленные Ассемблером (см. [58]). Как правило, на Ассемблере пишут фраrменты проrрамм, в которых используются недоступные для Паскаля особенности архитектуры компьютера. 
372 Подпроrрамма Си Сипроrрамма состоит из одной или нескольких функций  обыч ных (рассматриваются ниже), функцийчленов, дружественных функций и шаблонов функций (см. [28,24,48,67,55,50]). Обычная функция Обычная функция подобна функции main (с-м. nодразд. "Cиnpo 2ра-м-ма" разд. "Структура и запись nP02pa-м-мы" 2лавы 5). Ее объ явление имеет вид [тип} f ([список фор-маль'Н,ых nара-метров}) { [декларатив'Н,ая 'Часть) операторы; } Первое предложение объявления является заrоловком функции, а совокупность предложений в фиrурных скобках  телом. Встретив объявление функции, компилятор создает самостоятельную секцию кода проrраммы. На этапе компоновки она объединяется с друrими функциями. В заrоловке функции слово тип задает тип возвращаемоrо функ цией f значения  основной или типа указатель (функция может возвращать указатели на любой тип, включая массивы и функции). По умолчанию (тип не написан) результатом работы функции будет int данное. Каждая функция rлобальна (по умолчанию имени f назначается класс памяти extern 1 ). Внутренних функций в Си нет. Имя f  это особый тип указателя, называемоrо указателе-м 'Н,а Фу'Н,кцию. Ero значение  адрес точки входа в функцию. Список фор-маль'Н,ых napa-метРО6 либо не содержит таковых (и тоrда он пуст или включает слово void), либо состоит из разделенных за пятой спецификаций параметров, каждая из которых представляет собой конструкцию вида mUni Vi, rде mUni (i == 1,2, ..., п)  тип параметра и Vi  ero имя. Формальным параметром может быть пе ременная OCHoBHoro и перечисляемоrо типов, типа указатель и Mac 1 Можно явно задать класс памяти extern или static. 
373 сив, структура и объединение. Тело функции  блок или (реже) составной оператор. Обязатель ным оператором тела является оператор возврата вида return выраженuе; Он прекращает выполнение функции и передает значение ВЫраже НUЯ и управление в точку вызова. Вызов функции Л[Иl, и2, . .., И n })  это первичное выражение. Операция в нем обозначается круrлыми скобками. Операндами слу жат имя функции (вычисляется как адрес) и фактические параме тры Ui (i == 1,2, ..., п). Здесь любое Ui  выражение, тип значе ния KOToporo основной, структура, перечисление, объединение или указатель. Формальные и фактические параметры нужно соrласо вать. Контроль соответствия числа и типа параметров компилятор выполнит только тоrда, коrда до первоrо обращения к функции бу дет помещено либо ее объявление, либо прототип, т. е. опережаю щее объявление. Прототun почти полностью совпадает с заrолов ком функции: первое отличие  присутствие точки с запятой в KOH це заrоловка, второе  необязательность имен формальных пара метров. Общепринятая практика  размещение прототипов функ ций И объявлений внешних объектов (переменных, массивов и пр.) в заrоловочном файле, подключаемом к тексту проrраммы директи вой #include "UМЯ фаi1ла.срр". Все параметры функции, за исключением параметров типа указа тель и массив, передаются по значению (на это тратится и ДОПОk нительная память, и время). Так как функция будет работать с копиями фактических параметров, параметрызначения нельзя ис пользовать для возврата результатов. Обрабатывая вызов функции, компилятор вставляет в код проrраммы последовательность команд, выполняющих следующие действия. 1. Подсчитывается значение выражения Ui (i == 1, 2, . . . , п). Ero тип сравнивается с типом соответствующеrо формальноrо параметра, за данным в прототипе функции. Если они не совпадают, то либо про изводится преобразование типа, либо выдается диаrностическое co общение. 2. Компилятор в точке вызова размещает команды заrрузки в стек значений фактических параметров. Происходит замена формальных 
374 параметров на фактические: первый фактический параметр всеrда соответствует первому формальному пар,;},метру, второй  второму и т. д. 3. Здесь же, в точке вызова, компилятор поместит команду вызова функции с возвратом. В результате ее выполнения управление пере дается к точке входа в функцию, на первую ее команду. Код функ ции всеrда содержит команду возврата. Она располаrается на месте оператора return, а при ero отсутствии Ha месте последней фиrур ной скобки тела функции. Ее выполнение возвращает управление и, возможно, значение в точку вызова. Память в стеке освобождается. На этом работа функции завершается. Например, для нахождения остатка от деления двух целых чисел предложим следующую ниже функцию Modulo (см. разд. IЛ20рuтм фу1t"'"'ЦU.я u аЛ20рuтмпро'Цедура 11 2лавы 4): #include <iostream.h> j j Си: long Modulo(long М, long N); void main (void) jj Function { long 1, J, L, К; cout «"\п\п\п Положительные 1, J, L ======> "; cin »1» J »L; К == Modulo(131,I) + Modulo(J + 11, L); cout« "\п 1==" «1«" J=="« J« 11 L=="« L «" Ответ: К ==" « К; } jj long Modulo(long М, long N) j j { return М  (MjN) * N; } jj ео mаш ео Modulo Имя функции f  это указательконстанта на функцию, равный адресу точки входа в функцию (адресу первой машинной команды). Объявление указательпеременной на функцию имеет вид тип (* J) ([сnисо"," типов формаЛ'Ь1tых параметров}); Здесь тип  тип значения функции, f  имя переменнойуказателя на функцию. Вместо спис","а типов можно использовать (для боль шей наrлядности) списо"," формаЛ'Ь1tЫХ параметров. Указатель на функцию необходим, вопервых, при вызове HeKOTO 
375 рых стандартных функций (к примеру, функций поиска bsearch, lsearch, lfind и сортировки qsort), BOBTOpЫX, для KocBeHHoro BЫ зова резидентных проrрамм [24] и, втретьих, при построении уни версальных функций. К примеру, дадим фраrменты объявления и использования универсальной функции численноrо интеrрирования с именем Ralston (см. разд. /1 Фун,'/С'Цио1tалъ1tа.я схема /1 и I}1Л20ритм фуюс'Ци.я и аЛ20ритмпро'Цедура /1 2лавы 4): #include <iostream.h> #include <math.h> // double Ralston (double А, double В, double Eps, unsigned N, double(*F)(double Х)) {double ...;... Р(...) ...; return . . . ; } / / ео Ralston // double F (double Х) { return MSQRT2; } // void main(void) { double L; L == Ralston (1., 2., 1е  6, 10и, Р); cout « "\п \п \п L == 11 « L; } // / / ео main ео program Если применить определение типа typedef тип (*им.я) ([список типов формалъ1tых параметров}); то можно несколько улучшить читаемость Сипроrрамм. Здесь им.я  указатель на функцию, возвращающую значение типа тип. Например, // // typedef double( *PtrJunc)( double Х); double Ralston (double А, double В, double Eps, unsigned N, PtrJunc Р) { double . . . 
376 Пятым параметром функции Ralston является функция F типа PtrJunc. Это означает, что F  указатель на любую функцию с oд ним параметром типа double, возвращающую значение типа double. Указатели на функции можно объединять в массивы, например: #include <iostream.h> const unsigned N == 3; тиn Р1( ...), Р2(...), рз(...); // прототипы функций void main (void) // ArraypointerJunction { unsigned 1; тиn (*ArrJ[N])( ... ) == {Р1, Р2, Р3}; . .. А rr J [1]( ... ) ...; } тиn Р1(... ) {...; return...;} тиn Р2(... ) {...; return...;} тиn Р3(... ) {.,,; return...;} Приведенный прием удобен при разработке проrраммы, управляе мой посредством меню. Добавление в нее новых возможностей Tpe бует лишь включения в массив указателей имен новых функций. Теперь представим рекурсивную функцию Fact, вычисляющую зна чение факториальной функции (см. раза. 11 Рех;урсuя 11 2ла6ы 4): #include <stdio.h> // #include <process.h> long Fact(long N) // { if(l1 < N && N < 131) return N * Fact(N  11); else if(N ==== 1111 N ==== 01) return 11; else {printf("\n *** error: arg==%ld Fact.", N); exit; } } // void main (void) { long N; do { printf("\n О <==N<== 12======> ,,); scanf("%ld", &N); // ео main Си: // ео N < О или N>==13 ео Fact / / RecиrsiveFact 
377 printf("\n %ld!== %ld \Пll, N, Fact(N)); } while (!feof(stdin)); } // // (Ctrl) + (z) ео program Функция void Если в заrоловке функции указан тип void, функция 2 явно не воз вращает никакоrо значения. Неявно же любая функция может пере дать в вызывающую функцию результаты своей работы посредством указателей (вызов функции с передачей адресов переменных) и/ или rлобальных переменных (обмен данными через общую память). В теле vоidфункции может содержаться сокращенный оператор возврата return;. Он прерывает выполнение функции и передает управление к точке вызова. Так как на орrанизацию возврата Tpa тится несколько команд, использование void в роли тиnа функции позволяет получить более эффективный код проrраммы. Если в качестве параметра используется указатель переменной, нужно применить операцию разадресации * этой переменной для дo ступа и изменения ее значения. К примеру, для нахождения остатка от деления целых чисел теперь применим vоidфункцию Modulo: #include <iostream.h> // Си: void Modulo(long М, long N, long *К); void main (void) / / Procedure { long 1, J, L, I<l, К2, К; cout «II\П\П\П Положительные 1, J, L ======> 11; cin »1» J »L; Modulo(131,I, &l{l); Modulo(J + 11, L, &К2); I< == I<l + К2; cout « II\П 1 ==11 « 1 « " « " J ==" « J «11 L ==11 « L Ответ: К == 11 « К; } // void Modulo(long М, long N, long *К) // { *I<==M(M/N)*N; return; } // ео таш ео Modulo в заrоловке vоidфункции "сказано", что I<  указатель на данное 2 Аналоrом vоidфункции в Паскале и Фортране является процедура. 
378 типа long, т. е. передаче подлежит адрес (а не значение) переменной целочисленноrо типа. В теле функции при этом используется опера ция разадресации (см. оператор *J{ ==... ;), а фактическим парамет ром должен быть адрес переменной (см. вызовы функции Modиlo). Массив может быть параметром функции, и функция может возвра щать указатель на массив в роли результата. При этом возникает задача определения в теле функции длины массива. При переда че строки (т. е. массива типа char [ ]) все просто, так как известен конец строки (задан нультерминатор '\0'). Например, так выrля дит функция, копирующая строку аналоrично стандартной функции strcpy [24]: void Strcpy (char *Dest, char *Src) { while (*Dest++ == *Src++) ; } Если же проrраммисту привычнее работать с массивом, то предыду щую функцию можно представить так: void Cpystr (char Dest[], char Src[J) { unsigned 1 == о; while (Dest[I] == Src[I]) 1 ++; } Время работы обеих функций примерно одинаковое, но код функции Strcpy на пару десятков байтов короче. Если в функцию передается одномерный массив А, то в ее заrо ловке достаточно указать адрес начала массива А[] а в роли пара метра  ero длину. В функцию можно передавать и MHoroMepHbIe массивы. Для примера приведем фраrмент объявления, заrоловок и вызов "универсальной" функции ввода матрицы А размера т х п: const unsigned Lim == 80; void GeCmatr (double А[ ][Lim], unsigned М, unsigned N) .,. , double A[Lim][Lim]; ..., Getmatr (А, N, N); ... В заrоловке функции константой Lim задается максимально воз можное число столбцов матрицы. Параметры М и N представляют собой соответственно текущее число строк и число столбцов матри 
379 цы. Лучшим решением проблемы передачи MHoroMepHoro массива произвольной длины будет использование массива указателей (см. разд. "Модуль" данной 2лавы и [48]). С функциями связано понятие "видимости" переменных и функ ций [24]. Сипроrрамма (mаiпфункция и все друrие функции, если они есть) может находиться целиком в одном сррфайле. Но это не всеrда удобно, а иноrда и просто невозможно. Тоrда проrрамму раз мещают в нескольких сррфайлах, каждый из которых содержит ok ну или несколько функций. Для объединения в одну проrрамму они компилируются совместно. Компилятор для каждоrо файла поро ждает отдельный объектный файл. Затем эти файлы объединяются компоновщиком в один заrрузочный модуль (ехефайл). Компилятору для успешной работы требуется, чтобы каждому име ни объекта проrраммы были приданы, как минимум, два атрибута: тип и класс памяти. Тип определяет размер памяти, выделяемой компилятором для объекта, и способ ее интерпретации (например, как адрес памяти для указателей). Класс памяти устанавливает место размещения объекта (внутренние реrистры процессора, cer мент данных, cerMeHT стека) и одновременно время ero жизни (все время выполнения проrраммы или KaKoroTo ее фраrмента). Класс памяти определяется либо явно, либо по контексту. С точки зрения времени существования различают три типа объектов; статические, локальные и динамические. С классом памяти связано понятие видимости, или, подруrому, области определения имени,  той части проrраммы, в пределах которой имя можно использовать для доступа. Область определе ния нужна компилятору, чтобы сrенерировать корректный машин ный код. Различают три вида области определения имени; в преде лах блока (локальная видимость), в пределах функции и в преде лах сррфайла (или сррфайлов). Если имя объявлено внутри бло ка, оно имеет ЛО1\,альную область определения, оrраниченную пре делами блока. Следовательно, все переменные, объявленные внутри функции (в том числе и формальные параметры ), известны толь КО в теле функции. Два блока независимы, если ни один из них не является подблоком друrоrо. Естественно, что имя, объявленное в некотором независимом блоке, не существует в друrом независимом блоке. Если же имя объявлено вне какихлибо блоков, оно является 
380 2лобалъ1tЫМ и имеет область определения, начинающуюся с точки объявления и продолжающуюся до конца файла. Такое имя будет видимо из всех функций ниже точки объявления переменной. Что бы имя стало видимым в функциях выше точки объявления или в функциях, описания которых находятся в друrих файлах, объявле ние имени начинают словом extern. Рекомендуемое местоположение этоrо объявления  в начале файла, перед первой функцией. OTMe тим, что объявление видимости объекта никак не связано с резерви рованием компилятором памяти (к примеру, предложение extern int К; является объявлением переменной J{ только как внешней ссылки; значит, в этом предложении ехtеrппеременной нельзя при своить начальное значение). Использование внешних переменных  один из способов обмена данными между функциями. Применять ero следует в крайнем случае З . Правда, этот способ имеет и ДOCTO инство, ибо отпадает необходимость в записи копий фактических параметров в стек, в сохранении и восстановлении некоторых реrя- стров процессора. Как следствие, компилятор, обрабатывая общую память, создает эффективный код проrраммы. Имя функции видно (по умолчанию) из всех файлов проrраммы, но прототип функции действует только в rраницах одноro файла 4 . При ведем, к примеру, Сипроrрамму, состоящую из файлов filel.cpp и file2 .срр. В ней для связи функций применяется внешняя перемен ная К: #include <iostream.h> // filel.cpp extern int К; // объявление переменной J{ как внешней ссылки int J{ == 1; // объявление rлобальной переменной J{ void main (void) // Exaтpleexternal { void Tip (void); // прототип Tip cout « "\п в main К ==" « J{ ++; Tip (); } / / ео mаш void Tip (void) { void Тор (void); // прототип Тор ЗОн не должен превращать Сипроrрамму в ВSпроrрамму. 4 Поэтому приходится размещать во всех совместно компилируемых файлах директивы препроцессора для подключения файлов заrоловков, содержащих прототипы библиотечных функций. 
381 cout « "\n В Tip К ==" « J{ ++; Тор (); } // .......................................................... ео Tip #include <iostream.h> / / file2 .срр extern int К; / / объявление переменной J{ как внешней ссылки void Тор (void) { cout « "\n В Тор К==" « J{ ++; } // // ео Тор ео program В результате выполнения проrраммы Exaтpleexterпal получены следующие сообщения: в main К = 1, В Tip К = 2 и В Тор К = З. Все переменные, объявленные внутри функции или блока, по YMOk чанию относятся к авто.матu'Чес'К:о.му 'К:лассу памяти. Класс auto можно установить и явно. Переменные этоrо класса всеrда локаль ны. Они размещаются в стеке и должны обязательно получить зна чения (в противном случае содержимое ячеек памяти, зарезерви рованных для переменных, не будет определено). Время их суще ствования оrраничено временем выполнения функции или блока, в котором эти переменные объявлены. Контрольныil вопрос Какие значения А, В, С и D будут выведены следующей GlobalLocal проrраммой: #include <iostream.h> // void F(long D, long *Е); long А, В; void main (void) { long С, D, Е; А == 11; В == 21; С == 31; D == 41; Е == 51; cout « "\n 1) " « А « 'u' « В « 'u' « С « 'u' « D « 'u' « Е; { long С == 31, D == 41, Е == 51; / / cout « "\n 2) " « А « / u' « В « / u' « Си: // GlobaCLocal } F(D, &Е); cout « "\n 4) " « А « 'u/ « В « 'u' « С « 'u' « D « 'u/ « Е; с « 'u' « D « 'u' « Е; // ео BHYTpeHHero блока 
382 } // ео mаш void F(long D, long *Е) // { long с; В == 61; С == 71; D == 81; *Е == 91; cout « I'\n 3) " « А « 'u' « В « 'u' « С « 'u' « D « 'u' « *Е; ret urn; } / / ео F Ответ 1) 1 2 345 2) 1 2 з 4 5 3) 1 678 9 4) 1 6 3 4 9 Простые целочисленные переменные и указатели можно отнести к классу памяти register. РесистРО6ые nере.меюtые  частный слу чай автоматических переменных. Задание в объявлении переменных слова register есть указание компилятору выделить для хранения значений этих переменных внутренние реrистры процессора, что по зволяет повысить скорость выполнения проrраммы. В противоположность автоматическим статu'Чес'Х:uе nере.мен,н:ые cy ществуют все время, пока проrрамма выполняется. Им выделяется память в cerMeHTax данных. По умолчанию статическими являют ся строковые константы и rлобальные переменные. Используя пре фикс static, любую переменную можно объявить явно как стати ческую. При этом она локальна, если объявление находится BHY три функции. Итак, rлобальная переменная имеет (по умолчанию) класс памяти static, но вовсе не обязательно, что статическая пе ременная есть rлобальная переменная. По умолчанию все стати ческие переменные получают нулевые значения. Приведем пример 1nstаnсеstаtiспроrраммы обработки статической локальной пере менной: #include <iostream.h> void Static (unsigned); void main (void) // 1nstancestatic { unsigned 1 j for(I==l; 1<4; 1++,Static(I))j 
383 } // void Static (unsigned 1) { unsigned J == 1; static unsigned J{ == 1; cout«"\n 1=="«1«", J=="«J<к", } // // ео таш к ==" « J{ ++; ео Static ео program А это результат выполнения проrраммы lnstancestatic: I=2, I=3, I=4, J=l, J=l, J=l, К=l К=2 к=з Заметьте, что значение статической переменной J{ после возврата из функции Static не забывается. Присваивание J{ начальноrо зна чения, paBHoro единице, совершается только один раз  при заrруз ке проrраммы. Друrое дело, автоматическая переменная J. Ей при каждом вхождении в функцию Static назначается единица. Так как статическая локальная переменная невидима из друrих функций, то можно создавать функциименеджеры ресурса: MeHe джеры очередей, менеджеры памяти и т. п. [24]. Переменная, объ явленная вне функции с префиксом static, недоступна из друrоrо файла. И, наконец, объекты с динамическим временем существования co здаются и уничтожаются во время выполнения проrраммы опера циями динамическоrо распределения памяти new и delete. Такие объекты размещаются в специально выделенной области памяти, называемой "'Х:у'Ч,а" (heap). В заключение рассмотрим доnо,//,ните,//,'Ьн:ые возможности npenpo цессора. Выше ero команды использовались для включения файлов и задания нетипизированных констант 5 (см. nодразд. "Константы и на'Ч,а'//''Ьные зна'Ч,ения в Си" разд. "Задание 'Х:онстант и на'Ч,а'//''Ьных зна'Ч,ениi1" и nодразд. "Cиnp02paMMa" разд. "Стру'Х:тура и заnис'Ь nрО2раммы" 2,//,авы 5). Условные команды препроцессора позволя ют компилировать или пропускать часть проrраммы в зависимости от значения HeKoToporo условия. Так как препроцессор представля ет собой MaKporeHepaTop, то, используя ero, можно переопределять 5Является устаревшим дополнением к объявлению const. 
384 синтаксические единицы языка (идентификаторы, ключевые слова, знаки пунктуации, знаки операций, операторы и друrие цепочки сим волов). К примеру, введем сокращенное обозначение оператора BЫ вода, часто используемоrо внекоторой проrрамме: #define Ттат cout« "\п Трам ... трам ... тарарам... \п" Выполнение оператора Ттат эквивалентно (по результату) опера тору cout из строки замещения. Директива #define позволяет определять м-ах;росы  MaKpOKOMaH ды с арrументами вида 6 #define J(Vl, V2, ..., V n ) тело Код макроса вставляется в проrрамму столько раз (в отличие от iпliпефункций), сколько раз вызывается макрос. Приведем пример использования макросов: #include <iostream.h> // #define Мах(А, В) ((А) > (В) ? (А) : (В)) #define Min (А, В) ((А) < (В) ? (А) : (В)) #define Sqr (Х) ((Х) * (Х)) void main (void) // Macros { cout « "\п Мах (1, 2) ==11 « Мах (1,2) « "\t Min (1,2) ==11 « Min (1, 2) « "\t Sqr (1.23) ==11 « Sqr (1.23L); } // ео program Отсутствие круrлых скобок в теле макроса может привести к непра вильному порядку вычисления. В теле перед формальным параме тром можно поместить символ #  указание компилятору преобра зовать фактический apryMeHT в строку символов. Заметим, что в отличие от обычных функций макрос приrоден для обработки пара метров любоrо типа. Значит, один макрос может заменять несколько функций 7. Альтернативой использованию макроса является фу'Нхцu.я inline. В противоположность обычной функции встраиваемая функция по мещается в файл заrоловков. Такая функция используется для Си: 6 Является устаревшим дополнением к объявлению встраиваемой функции inline. 7Впрочем, механизм переrрузки и шаблоны функций позволяют решать те же задачи, что и макросы [25, 48]. 
385 оптимизации небольших по размерам алrоритмов, например: inline double Мах (double А, double В) { return А > В ? А : В; } Подпроrрамма Фортрана Подпроrрамма Фортрана может быть 61tyтpeH,'nei1 (операторная функция, функция function, процедура subroutine) и 61tеш1tеi1 (функция function, процедура subroutine). Внутренние подпро rpaMMbI размещаются в проrраммной еДинице (здесь они и вызы ваются), а внешние  перед rлавной проrраммной единицей и/или за нею. Операторная функция Операторная функция должна предшествовать первому выполняе мому оператору. Она имеет вид f([Vl, V2, ..., V n }) == а rде j(Vl, V2, ..., V n ) представляет собой заrоловок функции f, а BЫ ражение а  ее тело. Тип значения функции (тип имени 1) и типы формальных параметров Vl, V2, ..., V N задаются так же, как тип переменной, т. е. в операторах объявления типа. Тип может быть встроенным или строковым. Выражение а, кроме формальных параметров, может содержать константы, rлобальные переменные (например, элементы массивов) и/или вызовы друrих функций. Вызов функции f имеет вид л[ul, И2, .. . , uJ), rде фактические параметры Ul, И2, ..., и n  выражения. Их значения, очевидно, co rласованы с формальными параметрами. Как только управление получает оператор, содержащий вызов функции f, происходит обра щение к ее объявлению (к этому моменту должны быть заданы зна чения rлобальных переменных), устанавливается связь между COOT ветствующими фактическими и формальными параметрами, а затем находится значение выражения а. Оно принимается в роли резуль тата работы функции и тем самым становится известным в точке вызова. 
386 Для примера представим Фортраном функцию "деление по модулю" Modulo (см. разд. "АЛ20ритмфункция и аЛ20ритмпроцедура" 2ла вы 4). Вот соответствующая проrрамма: program StatementJunction ! Фортран: implicit попе integer Modulo, М, N, 1, J, L, [( Modulo (М, N) == М  (M/N) * N ! write(*,'(///a\)') , Положительные 1, J, L ======>' read (*, *) 1, J, L J{ == Modulo(13, I) + Modulo(J + 1, L) write(*,'(/ 4(a,i10))')' 1==',1,' J==', J,' L==', L, + ' Ответ: К ==', J{ end ! ео program Функция function Внешняя функция f  это проrраммная единица вида [тип} [recursive} function Л[Vl, V2, ..., vJ) [result( имя результата)} [раздел операторов обаявления} [раздел выполняемых операторов} [contains раздел внутренних подпРО2рамм} end [function[f}} В заrоловке функции метапеременная тип представляет собой опи сатель типа (см. подразд. "Массивы в Фортране" разд. "Массив" 2лавы 7). Он задает тип результата функции. При отсутствии слова тип тип f нужно установить оператором объявления типа. Формальные параметры Vl, v2, . .., v n  имена переменных (к приме ру, BCTpoeHHoro, CTpoKoBoro и производноrо типов) и имена внешних подпроrрамм. Имя Vj (i == 1, 2, ..., п) локализуется в теле функции и не может появляться в операторах automatic, common, data, equivalence, intrinsic, save, static. Тип параметра устанавлива ется в разделе операторов обоявления так же, как тип перемен ной. Длина CTpoKoBoro параметра задается либо константой, либо 
387 звездочкой в скобках. Допускаются произвольные rраницы индек сов формальноrо массива. Тоrда в списке параметров присутствуют имена целочисленных переменных, представляющих реrулируемые размеры. Их значения при вызове функции заданы и не меняются в процессе ее выполнения. Для рекурсивной функции наличие име- ни результата обязательно. Ero тип совпадает с типом функции. В случае прямой рекурсии (см. разд. "Рех:урсия" 2лав'Ы 4) имя f и имя результата должны отличаться. Разделы образуют тело функции. Раздел об'Оявлениi1 может состоять из любых предложений за исключением заrоловков подпроrрамм и блоков данных. Имена внутренних подпроrрамм и имена объектов, перечисленные в этом разделе и представляющие вспомоrательные переменные, массивы, структуры, метки, локализуются в теле функ ции. Они (кроме меток) доступны и внутренним ПОДПроrраммам. Раздел операторов содержит, по крайней Мере, один оператор вида f == а или имя результата == а, rде а  выражение, значение которо- ro является результатом работы функции, и хотя бы один оператор возврата return. Он отмечает лоrический конец функции и пере- дает управление и результат в точку вызова данной функции. При отсутствии раздела contains оператор f == а или имя результата == а часто оказывается перед заключительным оператором end, указы- вающим компилятору физический конец функции, и тоrда оператор return можно не писать. Имени результата разрешено иrрать и роль вспомоrательной переменной. Для вызова функции пишут первичное выражение Л[и1, и2, . . ., и n }) rде фактический параметр ui (i == 1, 2, . . . , n)  выражение (в част- ности, константа, простая переменная, элемент массива или струк- туры, вызов функции, отношение), имя массива или структуры, се- чение или конструктор массива, массивовое выражение, строка, под- строка, указатель или имя внешней подпроrраммы. Формальный параметр может быть входным, выходным и входным-выходным, причем в последних двух случаях (это случаи волновоrо (побоч- Horo) эффекта) фактический параметр должен быть именем про- стой, индексированной или составной переменной. Параметр пере- дается только по ссылке (по адресу), т. е. передается указатель на место, rде содержится значение фактическоrо параметра. Такой спо- 
388 соб позволяет пересылать данные как в подпроrрамму, так и из нее. В случае нежелательности побочноrо эффекта следует защитить фактический параметр от изменения, объявив и образовав ero KO пию в вызывающей проrраммной единице. Формальные и фактиче ские параметры надо соrласовать по смыслу (роду), типу и числу. Компилятор не проверяет совместимость параметров. Это должен делать проrраммист. Устанавливаемый таким образом интерфейс между функцией и вызывающей проrраммной единицей называет ся 1tеяв1tы,м. Компилятор может выполнять проверку соответствия параметров в случае, коrда функция находится в том же исходном файле, что и обращение к ней, и предшествует обращению. Заста вить компилятор всеrда производить проверку можно посредством u1tтерфеi10tО20 бло'К:а, имеющеrо вид interface u1tтерфеi1сы nодnРО2ра,м,м end interface И1tтерфеi1с nодnРО2ра,м,мы состоит из ее заrоловка, объявлений фор мальных параметров и оператора end. Такой интерфейс называет ся яв1tы,м. Для примера закодируем алrоритмфункцию нахождения остатка: с interface to integer function Modulo (М, N) с integer М, N ! Интерфейсный блок с end ! Фортрана 77 program Externalfunction implicit попе interface integer function Modulo (М, N) ! Интерфейсный integer М, N ! блок end function Modulo ! Фортрана 90 end interface integer Modulo, 1, J, L, [( write(*,'U//a\)') , Положительные 1, J, L ===>' read (*, *) 1, J, L J{ = Modulo(l3, I) + Modulo(J + 1, L) write(*,'U 4(a,i10))')' 1=', 1,' J=', J,' L=', L, + ' Ответ: К =', [( end! ео таш 
389 integer function Modu/o(M, N) ! implicit попе integer М, N Modu/o == М  (M/N) * N return end! ео Modulo Если фактический параметр есть имя подпроrраммы li (i == 1, 2, . . . , n), оно обязано появиться в вызывающей проrраммной еди нице в об5явлении внешних имен, имеющем вид external Л, 12, . . . , 1n а имя функции ( фактической или вызываемой)  еще и в объявлении типа. К примеру, найдем длину кривой / (см. разд. "Фу?t1(;'Ционалъная схема 11 и 11 АЛ20ритмфу?t1С'Ция и аЛ20ритмnро'Цедура 11 2лавы 4): с real function Ra/ston*8 (А, В, Eps, N, Р) ! implicit попе external F real*8 А, В, Eps, Р, .., integer N, ... Ra/ston == return end! real function Р*8 (Х) ! implicit попе real*8 Х F == 1.414213562373095dO return end! program Center ! implicit попе external Р, Ra/ston real*8 Р, Ralston, L L == Ra/ston (ldO, 2dO, 1d 6, 10, Р) write(*,'(///" L==",f17.15)') L end! ео Ra/ston ео F ео таш ео program с 
390 Приведем теперь текст рекурсивной функции Fact, вычисляющей n факториал (с,м. разд. "Рекурсия" zлавы 4): recursive integer function Fact (N) result (Р) ! F90: integer N if(l < N .and. N < 13) then F == N * Fact(N  1) else if (N ==== 1 .or. N ==== О) then Р==1 else write (*, *) , *** error: arg ==', N,' Fact.' stop end if ! ео N < О или N >== 13 end if return end ! ео Fact Внутрен:н,яя nодnрОёра'м'ма определяется в rлавной проrрамме, MO дуле или подпроrрамме (короче, в носителе) после оператора contains. По умолчанию она обладает явно заданным интерфей сом, поэтому ее заrоловок и объявления формальных параметров не должны появляться в интерфейсном блоке. В отличие от внешней внутренняя подпроrрамма, вопервых, не содержит в себе никаких подпроrрамм и, BOBTOpЫX, концевое предложение функции f имеет вид end function[fJ а процедуры f  вид end subroutine[fJ Такая подпроrрамма может обращаться к друrой внутренней под проrрамме и использовать переменные cBoero носителя. В последнем случае при возможной коллизии имен имена переменных BHYTpeH ней подпроrраммы "закрывают" (временно) rлобальные имена (см. ниже проrрамму CommonInternal). Процедура Внешняя nро'Цедура f к точке вызова возвращает одно или несколько значений или вообще ни одноrо. Она имеет вид 
391 [recursive} subroutine f [([Vl, V2, . . . , V n })} [раздел операторов обо-я,вленu-я,} [раздел выnолн-я,емых операторов} [contains раздел вн ут рен н их nодn росрамм} end [subroutine[f}} В синтаксисе процедуры и функции MHoro схожеrо. Они отличают ся заrоловками (тип имени процедуры не объявляется, формальным параметром может быть звездочка), концевыми операторами, спосо бом возврата значений (передача результатов осуществляется толь ко через выходные параметры и, возможно, через общую память) и способом вызова  обращение к процедуре выполняется onepaтo ром вызова вида саН f [([иl, и2, ..., и n })} rде фактическим параметром, в частности, может быть *мет'/\:а 8 . Оператор return передает управление к преемнику оператора саН вызывающей проrраммной единицы. Приведем пример процедуры "взятие остатка": program ExternaCsubroutine implicit попе external М odulo integer 1, J, L, К1, К2, J{ write(*,'(j//a\)') , Положительные 1, J, L ======>' read (*, *) 1, J, L саН Modиlo(13, 1, К1) саН Modиlo(J + 1, L, К2) J{ == К1 + К2 write(*,'(j 4(a,i10))')' 1==', 1,' + ' end! subroutine Modulo(M, N, К) ! implicit попе integer .i\1, N, [( Фортран: J ==', J, ' L ==', L, Ответ: К ==', J{ ео таш 8В книrе эта возможность и оператор entry не рассматриваются. 
392 J{==M(M/N)*N return end! ео Modulo А теперь представим фраrмент объявлений, заrоловок и оператор процедуры вывода матрицы А == (aik)mxn: integer Lim, ... parameter (Lim == 80) real*8 А( Lim, Lim) саН PuCmat, (А, Lim, N, N) subroutine Putmat, (А, Lim, М, N) real*8 А( Lim, Lim) Если же использовать размещаемый массив, получим универсаль ную процедуру вывода (экономится память и время; см. nодразд. "Массивы в Фортране" разд. "Массив" zлавыl 7), и тоrда ее заrоло вок и оператор вызова станут такими: саН Putmat, (А, N, N) subroutine Putmat, (А, М, N) real*8 А(М, N) в Фортране определен еще один способ обмена данными между про rраммными единицами  через общую область nамятu. Ее мож но использовать в той проrраммной единице, rде написан оператор соmmоп, например: program CommonInte,nal ! Фортран: implicit попе external F integer А, В, С, D, Е соmmоп А, В 
393 А == 1 В==2 С == 3 D == 4 Е==5 write (*, *) , 1)', А, В, С, D, Е саН F(D, Е) write(*, *)' 3)', А, В, С, D, Е end! subroutine F(D, Е) ! implicit попе integer И, V, D, Е, С соmmоп И, V V == 6 С == 7 D == 8 Е == 9 write (*, *) , 2)', И, V, С, D, Е return end! ео таш ео F в приведенном примере переменная А r лавной проrраммы и пере менная И процедуры F занимают одну и ту же область памяти. То же справедливо и для пары В и v. Имена соответственных элемен тов общей области MorYT различаться (см. пример ). А это результат выполнения проrраммы Coттonjnternal: 1) 2) з) 1 1 1 2 6 6 з 7 3 4 8 8 5 9 9 Друrой способ создания "общей области" памяти, но внутри про rраммной единицы,  посредством оператора equivalence. К при меру, следующее объявление real*8 А(2,2), В( 4), ХО, Х о equivalence (А(l, 1), В(1)), (ХО, Хо) делает эквивалентными А(l,l) и В(1), А(2,1) и В(2), А(1,2) и В(3), А(2,2) и В(4) и, наконец, ХО и Хо. После TaKoro "наложения данных" можно работать с вектором В вместо матрицы А. В послед 
394 ней паре имен предполаrается, что имя Х о  ошибочное. Заданием эквивалентности (ХО, Х о) эта ошибка леrко исправляется. Упражнения Решите сформулированные ниже задачи, выделив rоловной и под чиненные алrоритмы. 1. Найдите однофамильцев, обучающихся в одной rруппе. Выведите их имена и отчества. Выясните тезок, их фамилии и отчества. 2. Составьте проrрамму для изучения названий проливов. Из спис ка стран случайным образом выбираются названия странсоседей. Приведите названия соответствующих проливов, например, . Джибути  Йемен . Россия  США пролив: пролив: Бабэль Мандебский; Беринrов; . Россия  Япония пролив: Лаперуза. Ответ оцените по семибалльной системе. 3. Удалите символы, расположенные между скобками { и }, /* и */, и сами скобки. Найдите самое длинное слово текста С некоторой долей справедливости Фортран 54 можно критиковать, но мы должны отдать ему дань уважения /* как пионеру */: именно с нето началась эра автоматизации проrраммирования. 4. Выведите буквы, на которые начинаются слова в порядке убыва ния частоты их употребления в следующем предложении Бейсик эволюционизирует и ето некоторые версии приближаются к универсальным языкам проrраммирования, но происхождение Бей сика все равно проrлядывает за ето современной тотой. 5. Сколько раз в некотором тексте встречаются заданные слова (Ha пример, Ье, i5, there, с, со)? Выведите слова, длина которых больше 7 и не больше 14 символов Well beguп i5 Ьаlf doпe. Хорошее начало полдела откачало. What caп't Ье cured, тU5t Ье eпdured. Приходится мириться с тем, чеrо нельзя исправить. Where there i5 5тoke there i5 fire. Нет дыма без оrня. Talk оЕ the devil, aпd Ье i5 5ите to арреат. Леrок на помине. 6. Дети, шифруя записки, инвертируют слова. Составьте проrрамму 
395 кодирования и декодирования некоторых сообщений Nothing venture, nothing have. Волков бояться  в лес не ходить. Out of sight, out of mind. С rлаз долой  из сердца вон. Time and tide wait for по тап. Время не ждет. А stitch in time saves nine. Один стежок, сделанный вовремя, стоит девяти. А tree is known Ьу its fruit. Дерево познается по плоду. Аll roads lead to Lesnoe. Все дороrи ведут в Лесное. 7. В некотором тексте подсчитайте количество предложений, слов, всех символов (кроме u), сдвоенных символов, тире, коротких тире и запятых. Выведите длинные (1) 14) и короткие (1  7) слова Never put off till tomorrow what уои сап do today. Не откладывай на завтра тото, что можно сделать сеrодня. No news 18 good neW8. OT сутствие новостей  это все равно, что хорошие новости. StiJ1 water8 run deep. В тихом омуте черти водятся. Out of the fryingpan into the fire. Из оrня да в полымя. 8. Отсортируйте в лексикоrрафическом порядке несъедобные rрибы. Найдите однословные названия бледная поrанка, желчный rриб, мухомор пантерный, мухомор Kpac ный, мухомор порфирный, лисичка ложная, отневка ольховая, опе нок ложный, сатанинский rриб, перечный rриб, валуй ложный, эн томола ядовитая, строчок, свинушка. 9. Разделите слова одним пробелом, а предложения  двумя. Под считайте длины предложений и длину текста Half uu8uloaf uuisuu betteruuu th anuunou bread. Н8uuбезрыбьеuuиuрак uu рыба. uuHeuuu wa8uu bornuu wi thuu8uuusilveruspoonuuinuuuhisuumou th. uu Он uuuродилсяuuвuсоро чке. uuH оп est у uuisuu theu be8t uu poli су. uuuuu Честность uuuuuлучшаяuuполитик а. 10. Какая буква чаще начинает слова в таком тексте А little pot 18 8ООП hоt.Дурака леrко можно вывести из себя. Аll 18 not gold that glitter8. Не все то золото, что блестит. А8 уои make your bed, 80 уои lie оп it. Что посеешь, то и пожнешь. Early to bed, and early to ri8e, make8 а тап healthy, wealthy, and wi8e. J( то рано ложится и рано встает, здоровье, боrатство и ум наживет. 11. Найдите в тексте числа и запишите их в целочисленный вектор. Замените их числительными 1 8wallow doe8 not make а 8pring. 1 ласточка весны не делает. Тоо тапу cooks 8роil the broth. У 7 нянек дитя без rлазу. 2 heads are 
396 better than 1. Ум хорошо, а 2 лучше. 12. Сколько раз в тексте встречаются слова не, но, в, во, с, и, по. Для каждоrо предложения укажите долю соrласных (rласных). В каком предложении она максимальна (минимальна) 'ТЕХсистема подrотовки научнотехнических публикаций была раз работана д. Э. Кнутом в 1978 т. Она не только не оказалась BЫTec ненной современными настольными издательскими системами, но приобрела еще более широкую популярность во всем мире и Te перь завоевывает нашу страну. Столь продолжительное "творческое долrолетие" уникально среди компьютерных издательских систем, и по этому параметру 'ТЕХ стоит в одном ряду с лучшими языками проrраммирования. 13. Разделите слова одним пробелом, а предложения  двумя. Раз бейте текст на строки длиной не более 30ти символов. Перенос на новую строчку делайте на месте пробела. В последнем предложении удалите возможные концевые пробелы: uu С.  П етербурruстроилсяuuuнеuuодинuuuдень.uSt. Peters burg uuu was uuпоtu Ьuiltuiпuuuаuudау.uuuuu Сколькоuстран,uuuстолькоuuи uuuuuu обычаев. uuuSоuuumапу uuсоuп triеs,usоuumапу uuucustoms. uu 14. Уберите из текста сдвоенные символы" и ". Подсчитайте коли чество слов с окончанием ая, ом, ой, их, ых "'ТЕХ  восхитительная, великолепная часть компьютерной изда тельской системы для набора любых текстов (например, " 'ТЕХничес ких" текстов  текстов с большим количеством математических формул) на любом языке (например, анrлийском, русском или япон ском), а кроме тото,  это система для получения "изысканных" текстов, сравнимых по своей красоте с теми, что выходят изпод py ки высококлассноrо мастера набора." 15. Составьте проrрамму для запоминания названий химических элементов: из списка случайным образом выбирается название эле мента; приведите ero "химическое" имя, например, . золото ответ: Аи; . серебро ответ: Ag; . платина ответ: Pt. Ответ оцените по семибалльной системе. 
397 16. Одиночную звездочку замените пробелом, а двойные, тройные, ...  двумя пробелами. Выведите слова с удвоенными символами I11***news*travels*fast. **** *Плохая*молв а *на *крыльях* летит. **It * never**rains*but *it *pours. *** Беда *одна *не*ходит. ******If*you *тип * after**two**hares, **you**wi11*catch *neither. **За *двумя*зайцами*** поrонишься, *ни**одноrо*не*поймаешь. *Look*before*you*leap. *Не** зная*броду, *не*суйся*в*воду. **More*haste, *less*speed. *******Тише ********* ***едешь, ********** дальше***********будешь. 17. Зашифруйте (расшифруйте) текст, используя перемешанный ал фавит, полученный случайной перестановкой всех букв исходноrо алфавита: Скобками вы точно укажите себе, читателю и компилятору то, что вы хотите сделать. .. Злоупотребление словом goto не является при знаком высокой культуры проrраммирования. .. Не стучите по кла вишам. . . 18. В анrлийском тексте мноroточие замените точкой, а в русском  восклицательным знаком. Подсчитайте количество слов в каждом предложении Аll work and по рlау тakes Jack а dull Ьоу. .. Мешай дело с бездельем, проживешь век в веселье. Better late than пеует. Лучше ПОЗДНо, чем никоrда. Birds of а feather flock together. Рыбак рыбака видит изда лека. .. Cast not уоит pearls before swine. ., Не мечите бисера перед свиньями. 19. Отсортируйте в лексикоrрафическом порядке съедобные rрибы. Найдите названия, имеющие синонимы или содержащие букву ь. В каждом названии первую букву слова замените прописной белый (боровик), подосиновик (красноrоловик, челыш), подберезо вик (обабок, черныш), моховик, масленок, дубовик, волнушка, бе лянка, валуй, сыроежка, rруздь, рыжик, лисичка, шампиньон, опе нок, rорькушка, сморчок. 20. Выведите самое короткое, самое длинное и срединное слово /1 Чистая" математика делает то, что можно, так, как нужно, а при кладная  то, что нужно, так, как можно. 21. Сколько раз в тексте встречаются двухбуквенные сочетания? Выведите соответствующие слова. Для каждоro слова текста YKa жите долю соrласных (rласных). В каком слове она максимальна (минимальна) 
398 А bad workman quarrels with his tools. У плохоrо мастера всетда ин струмент виноват. А drowning тап wi11 catch at а straw. Утопающий за соломинку хватается. А friend in need is а friend indeed. Друзья познаются в беде. А good beginning makes а good ending. Лиха беда начало. 22. П реобразуйте текст ВИДа Архип Иванович Куинджи. Николай Николаевич Те. к виду ТеН. Н. Куинджи А. И. 23. Определите количество симметричных слов. Найдите самое длинное симметричное слово Handsome is that handsome does. Понастоящему красив лишь тот, кто красиво поступает. People who live in glass house should never throw stones. Тот, кто живет в стеклянном доме, не должен бросать ся камнями. 24. В некотором тексте, например, Аll is not gold that glitters. Не все то золото, что блестит. Where there is smoke there is fire. Нет дыма без оrня. Sti11 waters run deep. В тихом омуте черти водятся. Strike while the iron is hot. Куй железо, пока rорячо. А watched pot is long in boiling. Котда ждешь, время тянется долrо. Ап оипсе о! prevention is worth а pound о! сиrе. Предупрежде ние лучше лечения выведите rистоrраммы относительных частот появления букв без различия их реrистра (вертикальная ориентация для rистоrрамм). 25. Напишите проrрамму, которая для k лиц по запрашиваемому He полному имени выводит полное имя (например, Ваня  Иван, Ba ся  Василий, Тоша  Теорrий, Дуня  Евдокия, Зема  Зиrмунд, Ира  Ирина, Катя  Екатерина, Липа  Олимпиада, Митя  Дмитрий, Муся  Мария, Сема  Семен, Сима  Серафима, Сла ва  Ярослав, Соня  София, Фима  Ефим, Шура  Александр и т. д.). в неполных словах выделите корень СЛОВа. 26. Найдите символы, которые встречаются В тексте лишь один толь ко раз Catch the bear before уои sell his skin. Не убив медведя, шкуры не продавай. Constant dropping wears the stone. Терпенье и труд все пе 
399 ретрут. поп' t count уоит chickens ЬеЕоте they ате hatched. Цыплят по осени считают. 27. Для целоrо k Е [о; 255] выведите фразу В строке' Лучше лиш ний стоп, чем лишний ляп.' k символов, соrласовав окончание слова символ со значением k. 28. Определите сложность предложений (назовем сложностью npeд ложенuя сумму числа слов и знаков препинания). Какие символы и сколько раз встречаются в следующем ниже тексте: По праву достойна в стихах быть воспета О свойствах корней теорема Виета. Что лучше, скажи, постоянства такото, Умножишь ты корни  и дробь уж тотова: В числителе с, в знаменателе а, А сумма корней тоже дроби равна. Хоть с минусом дробь, ну да, что за беда: В числителе Ь, в знаменателе а. Ликвидируйте возможные строки из одних пробелов. 29. Выведите rистоrраммы относительных частот появления букв без различия их реrистра (rоризонтальная ориентация для rисто rpaMM) А bird in the hand is worth two in the bush. Не сули журавля в небе, а дай синицу в руки. А little leak wi1l sink а great ship. В большом деле не бывает мелочей. Practice тakes perfect. Дело мастера боит ся. 'Tis the last straw that breaks the caтel's back. Последняя капля переполняет чашу. 30. Составьте проrрамму для запоминания анrлийских слов: из спис ка случайным образом выбирается русское слово; приведите ero aH rлийский эквивалент, например, . алфавит ответ: АВ С; . здравствуй ответ: Ы; . до свиданья ответ: Ьуе  Ьуе. Ответ оцените по десятибалльной системе. 
400 Модуль Модуль  прекрасный инструмент для разработки библиотек при кладных проrрамм. Обычно он представляет собой набор Подпро rpaMM, собранных в отдельном файле. Ero можно использовать дpy rими проrраммами, что экономит время и сокращает стоимость раз работки новых проrраммных продуктов. Модуль в Паскале Модуль в Паскале имеет следующий вид: unit им,ямоiJул,я; interface [и'Н,терфеtiс'Н,а,я 'Часть} implementation [исnолн.яема,я 'Часть} [begin . и'Н,ициирующа,я 'Часть} end. Им,я моiJул,я служит для связи с rлавной проrраммой и/или друrи ми модулями. Оно должно совпадать с именем файла, содержащим исходный текст модуля. К примеру, если файлы некоторых общих определений, ввода/вывода и численных методов называются COOT ветственно commdef.pas, inоиt.раs, nиттеth.раs, то COOTBeTCTBY ющие модули должны именоваться commdef, inout и nummeth. И'Н,терфеtiс'Н,а,я 'Часть может состоять из объявлений rлобальных констант, типов, переменных и полных заrоловков подпроrрамм. Они известны в любом месте rлавной проrраммы и в любом модуле. Испол'Н,,яема,я 'Часть может содержать объявления локальных объек тов (меток, констант, типов, переменных  они используются, Ha пример, в инициирующей части), краткие заrоловки подпроrрамм (заrоловки без формальных параметров и указания типа функций) и их тела. Если же здесь даются полные заrоловки, то они должны совпадать с заrоловками, приведенными в интерфейсной части. И'Н,ициирующа,я 'Часть завершает модуль. Она может состоять из операторов, которые исполняются сразу после подключения MOДY 
401 ля. Здесь можно задать начальные значения переменных, открыть файлы и пр., т. е. произвести вспомоrательные, подrотовительные операции. Эта часть выполняется один раз при запуске проrраммы. Любая из трех составных частей модуля может быть пустой. Оператор nодлю'Че'tiuя модулей uses uмя модУЛЯl, UМЯ модУЛЯ2, . . ., uмя модуляп ; должен следовать либо за словом interface, либо за словом imple mentation, либо за заrоловком проrраммы. Никакой модуль не MO жет вызываться рекурсивно. Ниже в качестве примера дана Паскальпроrрамма TesCnumeralme thods, тестирующая библиотеку nuтmeth, состоящую из девяти численных алrоритмов [21]: program TesCnuтeralmethods; {$N+,F+} uses commdef, inout, nuттeth; const W == 26; . var Х, Lam1, Laтn, Q, Eps : extended; /s : boolean; Nend, /(end : word; А, А1, Е : Matrix; В, Ad, Bd, Cd, Dd, ХО, Xsys, УО, У1, Уn : Vector; function F (Х : extended) : extended; begin F :== Х  1.0 end; { ео F(X) } function Phi (Х : extended) : extended; begin Phi :== (Х * Х * Х  3.0) * 0.5 end; { ео Phi(X) } begin { ......... Statements:} Bisec(0.5, 1.5, 1e18, Р, Х, /s); if /s then writeln (Х : W) . else writeln (' Нет корня на [а;Ь] или число корней четно.'); Wegstein (1.5, 1e18, 100, Phi, Х, Nend); if Nend == 101 then writeln (Nl, , *** error: jневязкаl >Eps. Wegstein.', Nl, , В этом случае имеем:'); writeln(X : W, , " (Х  Phi(X)) : 10, , " Nend); { ....... } writeln (Gauss...4 (О, 1.0, 1e 18, F) : W); { ...................... } А[l, 1] :== 2.0; А[1,2] :== 1.0; А[2, 1] :== 1.0; А[2,2] :== 2.0; В[l] := 3.0; В[2]:= 3.0; ХО[l]:= В[l]; ХО[2]:= В[2]; 
402 Sиbstitиtion (А, 2, А1); MиlCmatr (А1, А, 2, 2, 2, Е); pиCmatr (Е, 2, 2, W); { ......................................... } Gaиssmaincol (А, В, 2, Xsys); ResAxeqb (А, Xsys, В, 2, W); { ............................... } Q :== 0.5; Eps :== (1.0  Q)/Q * 1e18; GSeidel (А, В, хо, 2, Eps, 100, Xsys, Kend); if Kend == 101 then writeln( NI, , *** error: Iневязкаl >Eps. GSeidel.', NI, , В этом случае имеем:'); ResAxeqb (А, Xsys, В, 2, W); writeln(Kend); { ........... } Ad[l] :== о; Ad[2] :== 4.0; Ad[3] :== 7.0; Bd[l] :== 2.0; Bd[2] :== 5.0; Bd[3]:== 8.0; Cd[l] :== 3.0; Cd[2] :== 6.0; Cd[3] :== о; Dd[l] :== 5.0; Dd[2] :== 15.0; Dd[3]:== 15.0; Drivcaway (Ad, Bd, Cd, Dd, 3, Xsys); ResиltsAxeqb (Ad, Bd, Cd, Dd, Xsys, 3, W); { ................. } А[l, 1] :== 3.0; А[1,2] :== 1.0; А[2, 1] :== 2.0; А[2,2] :== 4.0; УО[l] :== 1.0; УО[2]:== 1.0; Mizes (А, 2, Уо, 1e 18, 100, Laт1, У1, Kend); if Kend == 101 then writeln (NI, , *** error: Iневязкаl >Eps. Mizes (Lam1).', NI, , В этом случае'); write (NI, Lam1 : W, NI, Kend); PиCvect (У1, 2, W); { ....... } Laminf(A, 2, УО, 1e18, 100, Lam1, Lamn, Уn, Kend); if Kend == 101 then write (NI, , *** error: Iневязкаl >Eps. Mizes (Lamn).', NI, , В этом случае', NI); writeln(NI,NI, Lamn: W, NI, Kend) { ........................... } end. { ео program } unit commdef; { interface const Lim == 30; NI == #13#10; type Риnс == function (Х : extended) : extended; Vector == array[l. .Lim] of extended; Matrix == array[l. .Lim, 1. .Lim] of extended; commdef. pas } { 10.01.01 } 
403 implementation end. { ео comdef } unit inoиt; {$N+} { interface uses commdef; procedure GeCvect (var А : Vector; N: word; Id: char); procedure PиCvect (var А : Vector; N, W : word); procedure GeCmatr (var А : Matrix; М, N : word; Id: char); procedure pиCmatr (var А : Matrix; М, N, W : word); procedure MиlCmatr (var А, В : Matrix; М, N, L : word; var С : Matrix); procedure ResAxeqb (var А : Matrix; var Х, В : Vector; N, W : word); procedure ResиltsAxeqb (var А, В, С, D, Х : Vector; N, W : word); inoиt.pas } { 23.08.01 } implementation { procedure GeCvect; var 1 : word; begin for 1 :== 1 to N do begin write (Nl, Id+'[', 1, '] ======> '); end; { } read (A[I]) end ео GeCvect } procedure pиCvect; var 1 : word; begin writeln; for 1 :== 1 to N do write (' ',A[I]: W) end; { ео PuCvect } procedure GeCmatr; var 1, J : word; begin for 1 :== 1 to М do for J :== 1 to N do begin write (Nl, ld+'[', 1, ',', J, '] ==== > '); read (A[I, J]) end 
404 end; { ео GeCтatr } procedure PuCтatr; var 1, J : word; begin writeln; for 1 :== 1 to М do begin for J :== 1 to N do writeln end end; { write (' ',А[1, J] : W); { ео вывода матрицы } ео РиС тatr } procedure MulCтatr; var 1, J, К : word; S : extended; begin for 1 :== 1 to М do for J :== 1 to L do begin S:== о; for К :== 1 to N do S:== S + А[1, К] * В[К, J]; С[1, J] :== S end end; { { ео 1, J } ео MulCтatr } procedure ResAxeqb; var 1, J : word; Р : extendedj {Контроль Ах  Ь == О и } { вывод решения системы; } { методы raycca, Зейделя} begin for 1 :== 1 to N do begin Р :== о; for J :== 1 to N do Р:== Р + А[1, J) * хр); writeln (' Х[', 1, ')==', Х[!) : W, , " (Р  В[1]) : 10) end { ео проверки } end; { ео ResAxeqb } procedure ResultsAxeqb; var 1, N1 : word; {Контроль Ах  Ь == о. и } { вывод решения системы; } {метод проrонки } 
405 begin N1 :== pred (N); writeln ( ' Х [ ' 1 ' ] ==' Х [ l ] . W ' " , ., , (В[l] * Х[l] + С[l] * Х[2]  D[l]) : 10); end; { end.{ for 1 :== 2 to N1 do writeln (' Х[', 1, ']==', Х[!] : W,' " (А[!) * X[pred (1)] + В[I] * Х[!) + С[I] * X[succ (1)]  D[I]) : 10); writeln (' Х[', N, ']==', X[N] : W,' " (A[N] * X[N1] + B[N] * X[N]  D[N]) : 10) ео ResultsAxeqb } ео inout } unit nuттeth; {$N +} { interface uses coттdef; const Author ==' Евсей Пуассон. Лесное.'; procedure Bisec (А, В, Eps : extended; Р: Риnс; var Х : extended; var Is : boolean); procedure Wegstein (ХО, Eps : extended; Nтax: word; Phi : Риnс; var Xs2 : extended; var Nend : word); function Gauss--4 (А, В, Eps : extended; Р: Риnс) : extended; procedure Substitution (var А : Matrix; N: word; var В : Matrix); procedure Gaussтaincol (А : Matrix; В: Vector; N: word; var Х : Vector); procedure GSeidel (var А : Matrix; var В, ХО : Vector; N : word; Eps: extended; Ктах: word; var Х : Vector; var Kend : word); procedure Driveaway (var А, В : Vector; С, D : Vector; N : word; var Х : Vector); procedure Mizes (var А : Matrix; N: word; var УО : Vector; Eps : extended; Ктах: word; var Laт1 : extended; var У1 : Vector; var /(end : word); procedure Laтinf (var А : Matrix; N: word; var УО : Vector; Eps : extended; l{тах: word; Laт1: extended; var Laтn : extended; var Уn : Vector; var l{end : word); nuттeth.pas } { 01.11.01 } implementation { } 
406 procedure Bisec; { Метод БИСЕКЦИЙ уточнения} { корня уравнения J( х )==0 } { А, В . левая и правая rраницы отрезка [А; В] } { Ерв  абсолютная поrрешность вычисления корня } {Р  функция f } {Х  корень уравнения J( х) == о } {!в  флажок: !s==true  на [А; В] есть корень; } { !s==false  нет корня или число корней четно} var Н, Sa, Del : extendedj function Sign (Х : extended) : extended; begin if Х < о then Sign:== 1.0 else if Х > о then Sign:== 1.0 else Sign:== О end; begin Sa:== Sign (Р(А)); if Sa <> Sign (Р(В)) then begin !В :== true; Х :== А; Н :== (В  А) * О.5; repeat Del:== Sa* Sign (Р(Х)) * Н; Х :== Х + Del; Н :== Н * 0.5 until abs (Del) <== Ерв; exit end { ео уточнения корня } else !В :== false end; { ео Bisec } procedure Wegstein; { Метод ВЕrСТЕЙНА уточнения} { корня уравнения х == Phi(x) } { ХО  начальное приближение корня } {Ерв  относительная поrрешность вычисления корня } { Nтax  запланированное число итерациЙ } {Phi  функция Phi } { Х в2  корень уравнения х == Р hi ( х ) } { Nend  фактическое число итераций; если неравенство } { I Del/ Х в11 <==Ерв не выполнилось, то Nend==Nтax+1 } 
407 var Xso, Х1, Xs1, Х2, Х2Х1 : extended; N : word; begin XsO :== хо; Х1 :== Phi(XO); Xs1 :== Х1; for N :== 1 to Nmax do begin Х2 :== Phi(Xs1); Х2Х1 :== Х2  Х1; Xs2 :== Х2  (Х2Х1 * (Х2  Xs1))/(X2X1  Xs1 + XsO); if abs(Xs2  Xs1) <==Eps*abs(Xs1) { Del==Xs2Xs1 } then begin Nend :== N; exit end; XsO :== Xs1; Xs1 :== Xs2; Х1 :== Х2 end; { ео N, Eps } Nend:== succ (Nmax) end; { ео Wegstein } function Gaиss4; { Метод rлуссл вычисления} { интеrрала (n == 4) } { А, В  нижний и верхний пределы интеrрирования } {Eps  относительная поrрешность PYHre } { F  подынтеrральная функция } const С1 == 0.347854845137453858; С2 == 0.652145154862546143; Т3 == 0.339981043584856264; Т4 == 0.861136311594052575; var Е255, Н, 1т, 12т, В1, А1, К1, К2, К2Т3, К2Т4 : extended; М, К : word; Finished : boolean; begin Е255 :== 255.0* Eps; 1т := о; М := 4; while not Finished do begin 12т :== о; for К :== 1 to М do begin В1 :== А + к * Н; А1:== В1  Н; К1 := 0.5 * (В1 + А1); К2 :== 0.5 * (В1  А1); К2Т3 := К2 * Т3; К2Т4 :== К2 * Т4; 12т := 12т + К2 * (С1 * (Р(К1  К2Т4) + Р(К1 + К2Т4))+ С2 * (Р(К1  К2Т3) + Р(К1 + К2Т3))) { ео К } H:=(BA)*0.25; Finished := false; end; 
408 Finished:== abs (12т  1т) <== E255*abs (12т); inc (М, М); Н :== 0.5 * Н; 1т :== 12т end; { ео Eps } Gaиss4 :== 12т end; { ео Gaиss4 } procedure Sиbstitиtion; { Методом ЗАМЕЩЕНИЯ по схеме raycca } { находится обратная матрица} { А  исходная матрица размера N х N } { В  обратная матрица } Р : extended; var 1, J, К : word; begin for 1 :== 1 to N do for J :== 1 to N do В[I, J) :== A[I, J); for 1 :== 1 to N do begin Р : == 1. О / В [ 1 ,I] ; for К :== 1 to N do В[I, К] :== В[I, К) * Р; В[I,I] :== Р; for J : == 1 to N do if J <> 1 then begin for К :== 1 to N do if К <> 1 then B[J, К] :== B[J, К]  B[I, К] * B[J, 1]; B[J,I] :== P * B[J, 1] end end end; { {eoJ} {ео1} ео Sиbstitиtion } procedure Gaиssтaincol; {  Метод rAYCCA решения системы} { Ах == Ь с выбором rлавноrо элемента в столбце} { А  матрица размера N х N коэффициентов системы } { В  векторстолбец свободных коэффициентов } { х  векторстолбец неизвестных } var К, К1, 1, J : word; Р, R : extended; begin {  Прямой ход: } for К :== 1 to pred (N) do begin 
409 J :== К; Р :== abs (А[К, К]); for 1 :== К1 to N do if Р < abs (A[I, К]) then begin J :== Ij Р:== A[I, К] endj if J <> I< then begin for 1 :== I< to N do begin Р :== A[I<,I]; end; Р :== В[К]; end; R :== 1.0/ А[К, К]; for 1 :== К1 to N do begin Р :== A[I, К] * Rj for J :== К1 to N do A[I, J] :== A[I, J]  Р * А[К, J]; B[I] :== B[I]  Р * В[К] end end; X[N]:== B[N]/A[N,N]; for I< :== pred (N) downto 1 do begin Р :== 0.0; for J :== succ (К) to N do Р:== Р + А[К, J] * X[J]; Х[К] :== (В[К]  Р)/А[К, К] end end; { К1 :== succ (К); A[I<,I] :== A[J, 1]; A[J,I] :== Р В[К] :== B[J]j B[J] :== Р { ео прямоrо хода } {  Обратный ход: } { ео обратноrо хода} ео Gaиssтaincol } procedure GSeidelj { Метод rAYCCA  ЗЕЙДЕЛЯ } { решения системы Ах == Ь } {А  матрица размера N х N :коэффициентов системы } {В  векторстолбец свободных коэффициентов } { ХА  векторстолбец начальных приближений неизвестных } {Eps  абсолютная поrрешность } { f'i." тах  запланированное число итераций } { Х  векторстолбец неизвестных } { f'i." end  фактическое число итераций; если неравенство } 
410 { IDellEps не выполнилось, то Kend==Kтax+1 } var 1, К, J : word; Delтax, Del, Xnew : extended; Р : Vector; begin for 1 :== 1 to N do begin X[I) :== XO[I); P[I) :== 1.0/A[I, 1) end; for J( :== 1 to Ктах do begin Dтax :== о; for 1 :== 1 to N do begin Del :== B[I]; for J :== 1 to N do if J <> 1 then Del:== Del  A[I, J) * X[J); Хnеш :== Del * P[I); Del :==abs (Хnеш  X[I]); X[I] :== Xnew; if abs (Del) > Delтax then Delтax:== Del end; if Delтax<==Eps then begin Kend :== К; exit end end; { еоК, Eps } Kend :==succ(Kтax) end; { ео GSeidel } procedure Driveaway; {  Метод проrонки решения системы} { уравнений Ах == Ь с трехдиаrональной } { матрицей А размера N х N: } {A[I]X[Il]+B[I]X[I]+C[I]X[I+1]==D[I] (/==1,2,..., N), } { rде A[l]==C[N]==O. } { А[l]==О; А[2]==а[2,1]; ...; A[N1]==a[n1,n2]; A[N]==a[n,nl] } { В[l]==а[l,l]; В[2]==а[2,2]; ...; B[Nl]==a[nl,nl]; B[N]==a[n,n] } { C[1]==a[1,2]; С[2]==а[2,з]; ...; C[Nl]==a[nl,n]; C[N]==O } { D[l]==b[l]; D[2]==b[2]; ...; D[Nl]==b[nl]; D[N]==b[n] } var 1: word; Р : extended; begin Р :== 1.0/ В[l]; С[l] :== С[l] * Р; for 1 :== 2 to N do {  Прямой ход: } D[l] :== D[l] * Р; 
411 begin Р :== 1.Oj(B[I]A[I] * C[pred (1)]); С[I] :== С[I] * Р; D[I] :== (D[I]A[I] * D[pred (1)]) * Р end; {  Обратный ход: } X[N] :== D[N]; for 1 :== pred (N) downto 1 do Х[I]:== D[I]  С[I] * X[succ (1)] end; { ео Driveaway } procedure Mizes; { { { var 1,1<, J : word; У : Laт, S : extended; begin for 1 :== 1 to N do Yl[I]:== УО[I]; Laтl :== о; for 1< :== 1 to Ктах do begin Laт:== Laтlj Laтl :== о; for 1 :== 1 to N do begin S:== о; for J :== 1 to N do S:== S +А[I, J] * Yl[J]; if abs(S»abs(Laтl) then Laтl:== S; У[I] :== S end; for 1 :== 1 to N do Yl[I]:== У[1]! Laтl; if abs (Laтl Laт)<==Eps then begin Kend:== 1<; exit end end; { ео К) Eps } Kend:== succ и(тах) end; { СТЕПЕННОЙ метод Мизеса вычи } сления Iнаибольшеrоl собственноrо } значения и собственноrо вектора } Vector; ео Mizes } procedure Laтinf; { { { { СТЕПЕННОЙ метод вычисления} Iнаименьшеrоl собственноrо значе } ния и собственноrо вектора. Laтinf } использует Mizes: B==Laтl*EA } var 1, J : word; В : Matrix; 
412 begin for 1 :== 1 to N do for J :== 1 to N do if 1 <> J then B[I, J] :== A[I, J] else B[I, J] :== Laт1  A[I, J]; Mizes(B, N, УО, Eps, Ктах, Laтn, Уn, Kend); Laтn :== Laт1  Laтn end; { ео Laтinf } begin writeln(NI, , Hi there.', Nl, , Работают модули commdef, inout и numJlleth.', Nl,' Автор:', AиthoT, Nl) end. { ео nиттeth } Сборка Сипроrраммы В Си модулей нет, но подключить проrраммные файлы coттdef, inout и nuттeth можно, разместив в вызывающей части проrрам мы директивы препроцессора #include. Например: #include <iostream.h> #include <math.h> #include <conio.h> #include <iomanip.h> #include <process.h> #include "coттdef .срр" #include "inout.cpp" #include "nuттeth.cpp" void Message (char *5) { сои t « "\ n \ n * * * error: нет свободноrо места" « "\п для размещения массива" « 5« ". \п"; exit (1); } / / / /  С++  / /  Динамическое Bыдe / /  ление памяти. Ma / /  трица как набор oд / /  номерных массивов. / /  БИБЛИОТЕКА Чис / /  ленных алrоритмов. / /   ео Message const char * Тшо == " " , *Оnе == IIII; void main (void) / / Ах == Ь. { unsigned N, N1, Ктах, Kend, 1; / / **А  указатель на 
413 double Eps, Q, Е, **А, *В, *ХО, *Х; / / массив указателей (YKa / / затель для матрицы). clrscr ( ); cout «" N, Q, Ктах ======> \п"; cin »N» Q » /(тах; N1 == N + 1; if((A == new double*[N1]) ==== О) / / Вспомоrательный Mac Message("A"); / / сив указателей. Фор for (I == 1; 1 < N1; 1 + +) / / мирование строк эле if((A[I] == new double [N1]) ==== О) / / ментов типа double Message("A"); / / (одномерные массивы). if((B == new double [N1]) ==== О) Message ("В"); if((XO == new double [N1]) ==== О) Message ("ХО"); if((X == new double [N1]) ==== О) Message ("Х"); clrscr ( ); while(l) { cout « "\п Eps> Ed ======> "; cin » Eps; Е == (1.  Q)/Q*Eps; if(E> Ed) break; else cout « "\п *** error: увеличьте Eps."; } / / ео ввода Eps clrscr ( ); cout « "\п A[l..N][l..N] ======> \п"; cout « "\п B[l..N] ======> \п"; cout « "\п XO[l..N] ======> \п"; clrscr ( ); cout « "\п\п" « Two « "\п\п Ах==Ь. Метод raycca  Зейделя." «"\п\п Исходные данные:" «"\п\п N=="« N; cout.setf(ios:: scientific); cout.width (8); cout.precision (1); cout « " Eps==" « Eps « " Epscorr==" « Е « "\п Q==" « setw (13) « setprecision (6) « Q « " Кmах==" « /( тах « "\п\п Матрица А :\п"; pиCтatr (А, N); cout « "\п Вектор В : \п"; GeCтatr (А, N); GeCvect (В, N); GeCvect (ХО, N); PиCvect (В, N); 
414 cout « "\п Вектор ХО :\п"; PиCvect (ХО, N); GSeidel (А, В, ХО, N, Е, Ктах, Х, &J(end); cout « '\п' « Оnе « "\п\п Ответ: Axb==O \п"; if(Kend ==== Ктах+1) cout «" *** error: за Кmах==" « Ктах « " шаrов процесс" « " не сошелся. GSeidel.\n В этом случае \п"; ResAxeqb (А, Х, В, N); cout « "\п\п Число итераций К==" « Kend « ".\п\п" « Two; for (I == 1; 1 < N1; 1 + +) delete A[I]; / / Очистка памяти delete[] А; / / от динамических delete[] В; delete[] хо; delete[] Х; / / массивов. } // ео program / / commdej .срр const unsigned Lim == 30; const float Е! == 1.2е  7; const double Ed == 2.23е  16; const long double Eld == 1.09е  19; typedef double (*Fиnc)(double Х); / / ео commdej / / inoиt.cpp void GeCvect (double *А, unsigned N) {unsigned 1; for(I == 1; 1 < N + 1; 1 + +) cin» A[I]; } / / ео Getvect void PиCvect (double *А, unsigned N) {unsigned 1; cout « '\п'; cout.setf(ios:: scientific); for (I == 1; 1 < N + 1; 1 + +) cout « setw (15) « setprecision (6) « А[I]; cout « '\п'; } / / ео pиtvect void GeCmatr (double нА, unsigned N) {unsigned 1, J, N1; for (N1 == N + 1, 1 == 1; 1 < N1; 1 + +) 
415 for (] == 1; J < N1; J + +) cin» A[I][J]; } / / ео GeCтatr void pиCтatr (double нА, unsigoed N) {uosigoed 1, J, N1==N+1; cout « '\0'; cout.setf(ios:: scieotific); for (1 == 1; 1 < N1; 1 + +) {for(J==l; J<N1; J++) cout « setw (15) « setprecisioo (6) « A[I][J]; cout « '\0'; } } / / ео pиCтatr void ResAxeqb (double нА, double *Х, double *В, uosigoed N) {uosigoed 1, J, N1==N+1; double Р; cout.setf(ios :: scieotific); for (1 == 1; 1 < N1; 1 + +) { for(P == .0, J == 1; J < N1; J + +) Р + == A[I][J] * X(J]; cout « 11\0 Х[" « 1 «11]==11 « setw (13) « setprecisioo (6) « X[I] « setw (11) « setprecisioo (1) « Р  B[I]; } } / / // // double Lagrange (double *Х, / / Полином Лаrранжа L (Xstar) dou ble * У, uosigoed N, dou ble Х star) {uosigoed I,N1==N+1,J; double L==.O,P,Q,R; for (1 == о; 1 < N1; 1 + +) { Р == Q == 1.; R == Х [1]; for(J==Oj J<N1; J++) if(J А 1) { Р * == (Х star J[X]); L + == (*(1 + У)) * P/Q; ео ResAxeqb ео inoиt nиттeth.cpp //Л==I Q * == (R  (*(Х + J))); } } returo L; } / / ео Lagrange 
416 void GSeidel (double нА, double *В, double *ХО, unsigned N, double Eps, unsigned Ктах, double *Х, unsigned *I<end) {unsigned 1, К, J, N1==N+1, Кl==Ктах+1; double D, *Р; / / Если IDI > Eps, то I< end == I< тах + 1 if((P == new double [N1]) ==== О) { сочt « II\П \п *** error: нет свободноrо места" « II\П дЛЯ размещения массива Р. GSeidel.\n"; exit (О); } for (I == 1; 1 < N1; 1 + +) {Х[I] == ХО[I]; Р[I] == 1./ А[I][I]; } for и{ == 1; I< < К1; I< + +) {for(*I<end == К, 1 == 1; 1 < N1; 1 + +) { for (D == В[I], J == 1; J < N1; J + +) D  == A[I][J] * X[J]; D * == Р[I]; Х[I] + == D; if(fabs( D) > Eps) *I<end == 10; } if(*I<end !== К1) return; } return; } / / // / / ео 1 / / ео К} Eps ео GSeidel ео nummeth Подобным образом можно действовать и в Фортране: include 'commdef .for' incl ude 'inout .for' include 'nummeth.for' Модуль в Фортране В Фортране модули есть. Фортрановский модуль имеет вид module u.мя.модуля [раздел операторов обоявленuя} [contains раздел noanpozpaMM} end [mОdUlе[u.мя.модуля}} Здесь раздел обоявленuu может состоять из описаний данных, функ 
417 ций и интерфейсных блоков. Модульные подпроrраммы должны за вершаться концевыми операторами вида end subroutine [имя nроцедуръt} end function [им.я фу'Н:ции} Подключаются модули оператором use имя модуля!, имя модУЛЯ2, . . ., имя модуляп местоположение KOToporo  после заrоловка проrраммной единицы. Любой модуль может использовать друrие модули. 
418 r лава 9 Составные типы Кроме простых в языках проrраммирования определены составные типы  массивовый (массивы; СМ. разд. "Массив" 2лавы 7), множе ственный (множества), записной (записи, по друrому, структуры), файловый (файлы), объединения, объекты и классы. Множества Множества в Паскале представляют математические множества. Множество  конечный набор однородных лоrически связанных друr с друrом элементов HeKoToporo базовоrо типа. В роли базово ro типа допускается порядковый тип (кроме типов integer, word и longint; СМ. разд. "Константа" 2лавы 5). Принадлежность перемен ных Vl, V2, ..., V N К множественному типу можно указать, задав имя типа в разделе определения типов type им-я типа == set of пор-яд1'Совыu тип; и перечислив имена Vl, V2, . . . , v n В разделе объявления переменных var Vl, V2, . . . , V N : им-я типа; или объявив Vj (i == 1, 2, ..., п) сразу в разделе var без предвари тельноrо определения имени типа. Множество строится посредством конструктора множества, который представляет из себя заключенное в квадратные скобки перечисле 
419 ние через запятую элементов множества (выражений, значения KO торых есть данные порядковоrо типа). Порядок следования элемен тов множества несуществен. Множество, состоящее из n элементов, имеет 2 n различных подмно жеств, включая самое себя и пустое множество 0, т. е. []. Друrими словами, если порядковый тип определяет n значений, то COOTBeT ствующий множественный тип задает 2 n значений. К примеру, BBe дем множественный тип Letter и три переменные И, V и W этоrо типа. Пусть базовым типом будет тип диапазонный 'а', .'с', Тоrда объявление множеств И, V и W примет вид type Letter == set of 'а'. .'с'; var И, V, W : Letter; Переменные И, V, W MorYT принять следующие восемь различных значений: []; ['а']; ['ь']; ['с']; ['а', 'ь']; ['ь', 'с']; ['а',' с'] и ['а', 'ь', 'с'], а также [ 'ь' 'а' ] о [ 'с' 'ь' ] ' [ 'с' 'а' ] ' [ 'а' 'с' 'ь' ] ' [ 'ь' 'а' 'с' ] , [ 'ь' 'с' 'а' ] ' [ 'с' 'а' 'ь' ] и , , , , , , , , , , , , " , , , ['с', 'ь', 'а'] о Если список элементов, образующих значение переменной множественноrо типа, упорядочен в соответствии с базовым типом, то можно не перечислять все элементы, а достаточно указать только первый и последний, разделив их двумя точками, например, пишем ['а'. .'с'] вместо ['а', 'Ь', 'с']. Множества идентичноrо типа MorYT участвовать в операциях при сваивания, к примеру, U:== []; V:==['a'];,..; W :==['с', 'ь', 'а']; U:== V; U:== W; V:== И; и То п. Контрольныil вопрос Каким операторам эквивалентны операторы присваивания И :== ['а'. о'а'] и V :== ['ь'. .'а'] ? Ответ Операторам U:== ['а'] и V:== [] (так как 'Ь'>'а', то множество ['Ь', .'а'] интерпретируется как пустое). К множествам применимы двуместные операции, перечисленные в табл, 9.1. 
420 Таблица 9.1. Операции над множествами Обозначе Обозначе Pe Название ние в Ma ние в Пример зу ль тематике Паскале тат Пересечение n * [' а' ,'Ь'] * [' а',' с'] [' а'] Объединение U + [' а'] + ['ь'] ['а','Ь'] Разность \  [' а' ,'Ь']  [' а',' с'] ['Ь'] Содержит :> >== ['а' ,'Ь'] >==['а'] true Содержится в С <== [' а'] < == [' а' ,'Ь'] true Принадлежит Е ln [' а'] Е [' а' ,'Ь'] true Равно   [' а' ,'Ь'] == ['Ь',' а'] true   Не равно -; <> ['а']<>['Ь'] true Дополнительно к ним можно использовать Две процедуры  про цедуру include (множество, элемент), включающую новый эле мент в множество, и процедуру exclude (множество, элемент), производящую противоположное действие. Множества наrлядны, а операции над ними относительно быстротеч ны. Они удобны для исключения rромоздких проверок. Например, фразу if (Ch == 'а') or (Ch == 'е') or (Ch == 'i') or (Ch == 'о') or (Ch == 'и') or (Ch == 'у') then . . . лучше заменить фразой if Ch in ['а', 'е', 'i', 'о', 'и', 'у'] then ... Реализации Паскаля допускают множества урезанноrо базовоrо ти па, состоящие из весьма оrраниченноrо количества элементов (к примеру, максимальное кардинальное число множества в Turbo Pascal 7.0 равно 256). Вот на что можно рассчитывать (правда, Mac сив множеств позволяет обойти указанное оrраничение). Элементы множеств вводу/выводу не подлежат, но можно задать KOHCTaHTY множество, например: type АВС: set of 'а' : 'z'; const Vowel . АВС == [ 'а' 'е' 'i' 'о' 'и' ' у ' ] ' . , , , , , , в заключение решим задачу подсчета количества различных цифр (different digits) целоrо числа n. Для выделения очередной цифры 
421 (digit) будем находить остатки от деления на 10. Например, если n == 1999, то 1999 : 10 == 199 (9 в остатке); 199 : 10 == 19 (9 в остатке); 19 : 10 == 1 (9 в остатке). Различные цифры накопим в множестве set of digit, используя операцию объединения, а принадлежность TeKY щей цифры к этому множеству проверим с помощью операции in. Приведем текст проrраммы: program DigiCset; uses crt; const Nl == #13#10; type DigitSet == set of О. .9; var SetDig: DigitSet; Dif Dig : О. .10; {$R+ } N, М : longint; Digit : О. .9; begin clrscr; write (NI, NI, Nl, , longint N ======> '); readln (N); М :== abs (N); SetDig:== []; DifDig:== о; clrscr; repeat Digit :== М mod 10; if not (Digit in SetDig) then begin SetDig:== SetDig+[Digit]; inc (DifDig) end; { ео if not } М:==М div 10 until М == о; writeln(NI, , В числе " N, , разных цифр " DifDig, '.') end. { ео program } В Си и Фортране множеств нет. Структура Структурная переменная (или просто, cтpY'ICтypa, запись)  KO нечный набор лоrически связанных элементов (подруrому, палеи), возможно, различных типов, упорядоченных в заданном проrрам мистом смысле и объединенных общим именем. Структуры обыч но используются при производстве деловых и информационных дo 
422 кументов (анкет, ведомостей, каталоrов, справок и пр.). Типичным примером структуры служит личная карточка студента: студент (student) описывается набором атрибутов, таких, как личный номер (id number), фамилия (surname), пол (sex), rод рождения (birth year), адрес (address) и телефон (telephone). в свою очередь некоторые из этих атрибутов сами MorYT оказаться структурами (к примеру, фа милия (имя, отчество), rод рождения (число, месяц) и адрес, имею щий несколько компонентов). Как любая переменная, структурная переменная должна объяв ляться. Ее оббявление состоит из двух частей: 1. Определение CTPYKTypHoro типа (друrими словами, задания ша блона структуры). 2. Собственно объявления структурной переменной. Шаблон предоставляет компилятору информацию, необходимую для резервирования места в памяти и орrанизации доступа к по лям структурной переменной. Шаблон именуется. Он задает область определения: если шаблон находится внутри блока (Паскаль, Си),  это локальный шаблон, видимый в rраницах блока; если же шаблон размещен вне блоков, то он известен во всех блоках ниже точки объявления шаблона. Имена полей в одном шаблоне должны разли чаться, но в разных шаблонах они MorYT совпадать. Объявление структурной переменной состоит из имени шаблона и имени структурной переменной. Используя объявление, компилятор выделяет необходимую для структуры память. Длина структуры не может превышать 65536 байтов. Для доступа к полям структуры применяют операцию то'Ч,-х:а. Она формирует ссылку на нужное поле из имени стру-х:турно11 nepeMeH но11 и имени ПОЛЯ, т. е. имеет вид имя стру-х:турно11 nеременно11. имя поля Такое составное (по друrому, уточненное) имя может использовать ся в любом месте, rде допускается простая переменная. Поле струк- туры обладает всеми свойствами обычной переменной. Оно может иметь любой тип, в том числе и структурный. Тоrда ссылка на поле вложенной структуры должна состоять из имен структурной пере менной, CTPYKTypHoro поля и поля вложенной структуры, разделен- ных операцией то'Ч,-х:а. Структуры одноrо шаблона MorYT участво 
423 вать в операциях присваивания. Шаблон может описывать только одно поле. Это полезно, так как co ответствующие "экзотические" шаблоны повышают надежность про rpaMMbI. К примеру, если ввести шаблоны для скорости, веса и дли ны, имеющие по одному вещественному полю, то в проrрамме, BЫ числяющей соответствующие значения, можно контролировать KOp ректность операций (шаблоны структур, т. е. структурные типы, различаются по имени, значит, уже при компиляции будет зафикси рована ошибка, если в проrрамме происходит, например, сложение данных разных структурных типов, скажем, скорости и веса). Структуры в Паскале Задание записноrо типа ( шаблона) в Паскале имеет вид имя шаблона == record иМЯnОЛЯl, иМЯnОЛЯ2, ..., иМЯnОЛЯk : mUnl; тиn2; тиn р ; end; Ero можно поместить либо в разделе определения типов type, и TO rда объявление записных переменных Vl, V2, . . . , V N примет вид var Vl, V2, . . . , V N : имя шаблона; либо в разделе объявления переменных var. Паскаль допускает записи с вариантными полями (см. [58,59]). Полям записной константы можно задать начальные данные. Для примера определим массив CToиp157 из трех записей, назначим всем полям начальные значения и посредством индексированноrо cocTaBHoro имени обратимся к полю Phone записи CToиp157[1]: type Student == record Idnumber : longint; Surname : string[30]; Phone : string[8] end; const CToиp157 : апау[1. .3] of Student == ( (Idnumber: 995001; Surname: 'Иванов П. С.'; Phone: '01'), 
424 (Idnumber : 995002; Surname: 'Петров С. И.'; (Idnumber : 995003; Surname: 'Сидоров И. П.'; Group157[1].Phone ... Заметьте, что имя поля от CBoero значения отделяется двоеточием. Phone : '02'), Phone : '03')); Функция sizeof( Group157) возвращает число байтов памяти, зани маемой массивом структур Group157. Можно сократить составное имя до имени поля, если использовать оператор nрuсоеди1tе1tия, который имеет вид with имя заnис1tОU nеременнои do оператор Паскаль допускает вложение операторов with друr.в друrа. Приме нение оператора with, как правило, облеrчает чтение проrраммы и повышает ее эффективность. КонтрольныJi вопрос Чем отличается запись от массива? Ответ П роrраммист сам устанавливает иерархию и порядок следования элементов (полей), включаемых в запись. Поля записи MorYT иметь разные типы и доступ к ним осуществляется не по индексу, а по имени поля. Структуры в Си в Си шаблон определяется так: struct [имя шаБЛО1taj {mUnl UМЯnОЛЯl, uм.яnОЛЯ2, ..., иМЯnОЛЯk; тиn2 ..., а о., тиn р ..., }; Имя шаБЛО1tа может отсутствовать, если в функции используется единственный шаблон. Следом за правой фиrурной скобкой может следовать список структурных переменных Vi (i == 1, 2, . . . , n). Если этот список пуст, то объявление структур нужно разместить в пред ложении вида 
425 struct имя шаблона Vl, V2, . . . , V n ; Здесь же можно задать начальные значения переменных. Размер зарезервированной памяти (в байтах), предназначенной для xpa нения структуры, можно определить, используя операцию sizeof (struct имя шаблона). Разрешается объединять определение шабло на, объявление структурных переменных и задание начальных зна чений. Если поле  строковое данное, то имя стру-к;туры. имя поля есть указательконстанта на первый элемент массива символов. Можно найти адрес первоrо байта поля, написав &им.я cтpy-к;тy ры. имя поля. На практике структуры часто объединяются в массивы, к примеру: struct Student { unsigned long Idnumber; char Sиrnаmе[ЗО], Phone[8]; }; struct Student Grоир157[З] == {{995001, {995002, {99500З, "Иванов П. С.", "Петров С. И.", "Сидоров И. П.", "01"} , "02"} , "оз,,}}; Group157[0].Phone ... Задание шаблона структуры вводит новый тип. Значит, ничто нам не мешает использовать указатель на этот тип, например: struct Student Grоир157[З] == {{995001, ..., "ОЗ"}}, *Gr157ptr; Тоща оператор Gr157 ptr == Group157; устанавливает указа тель на первый элемент массива структур, и будут эквивалентны следующие три имени: Group157[0].Phone, (*Gr157ptr).Phone и Gr157ptr>Phone. Обратите внимание на обязательные круrлые скобки во втором имени (здесь учитывается paHr операций; см. разд. "Лоzи"iес-к;ое выражение" zлавы б). Чтобы обратиться к полю Phone второй структуры, можно исполь зовать любое из имен: Group157[l].Phone, (*(Gr157ptr+1)).Phone и (Gr157ptr+1)>Phone. Полный переход к следующему элемен ту массива структур обеспечивает оператор ++ Gr157 ptr;. Тоrда ссылка Group157[1].Phone будет равносильна ссылке (*Grl57ptr). Phone и ссылке Gr157 ptr > Phone. Си разрешает как вызов функции с передачей копии всей структуры 
426 или отдельных ее полей, так и с передачей указателя на всю CTPYK туру или только отдельные ее поля. Функция может возвращать как структуру, так и указатель на нее. Структуры в Фортране В Фортране задание CTpYKTypHoro типа (шаблона записи) и объявле ние записей V1, V2, ..., V N производится либо оnераторами type и end type в форме type uмя шаблона тиn1 UМЯ поля 1 , uмя nОЛЯ2, ..., UМЯ nОЛЯk тиn2 тиn р end type [имя шаблона} type (uмя шаблона) V1, V2, . . . , V N либо оnераторами structure, end structure и record в форме structure / uмя шаблона/ тиn! UМЯ nОЛЯt, UМЯ nОЛЯ2, . . ., UМЯ nОЛЯk тиn2 тиn р end structure record / uмя шаблона / V1, V2, . . . , V N Полями записи MorYT быть и массивы, и друrие записи. Разрешаются рекурсивные структурные типы. К примеру, представим рекурсив ный шаблон Node: type Node real(8) :: Х(О : 9) type (Node), pointer :: NexCnode end type Node type (Node):: First, Current ! полемассив ! полеуказатель в составном имени вместо тО"l'Х:и можно использовать знак процен та, например, First % NexCNode, Current % Х. Записи можно присвоить начальные значения aj (i == 1, 2, . . . , т) с 
427 помощью '/'Сонстру'/'Стора записи, который имеет вид и,Мяшаблона (аl, а2, ..., а т ) А это примеры объявления и использования массива из трех записей: structure / Student / integer Idnumber character Surname*30, Phone*8 end structure record / Student/ Group157(1: 3) Group157(1).Phone == '01' Group157(1 ).Phone Если запись является формальным параметром ПОДпроrраммы, то и шаблон, и объявление записи повторно задаются в декларативной части подпроrраммы. !!! type Student ",. Id Ь ... lnteger nит er !!! character(30) Surname !!! character(8) Phone !!! end type Student !!! type (Student) Group157(3) Контрольноезание Получите платежную ведомость (с,М. разд. "Массив" 2лавы 7), ис пользуя структурную переменную. Ответ program Payroll; { uses crt; const Lim == 20; Nlim == 40; Nl == #13#10; type Ind == l..Lim; N ате == string [Nlim]; Stringpayroll == record Surname : Name; Wage, Prize, Total: word end; Arrstr == array [Ind] of Stringpay]oll; var Form: Arrstr; N, 1 : Ind; Sum: word; { procedure OuCpay]oll (var Form : Arrstr; N: Ind; const Оnе ==' u Two=='u ПАСКАЛЬпроrрамма: } } var S: word); '. , '. , 
428 var N1, 1: Ind; begin w.rite(Nl, 'u': 12, 'Платежная ведомость', Nl, Two, Nl, , uuu ЧленыuuЗарплатаuuП ремияuuВсеrоuuuuПодпись' , Nl, 'uuбриrады', 'u': 17, '(ефимков)', Nl, Two, Nl); N1 :== succ(N); S :== о; for 1 :== 1 to N do begin with Form[I] do begin Wage:== (N1  1) * 3; Total :== Wage + Prize; writeln ('u', Surname: 8, Nl, Оnе) Prize :== Wage * 2; S :== S + Total; Wage: 6, Prize: 9, Total: 8, end end; writeln ('u': 12, 'Сумма', Sum: 15, Nl, Two); { ео with } { ео 1 } exit end; { begin clrscr; write (Nl,Nl,Nl, , N ======> '); readln (N); writeln (Nl, ' Список бриrады ======> '); for 1 :== 1 to N do begin write (Nl, 1, 'ю фамилию ======> '); end; clrscr; writeln (Nl,Nl,' Ответ:'); OuCpayroll (Form, N, Sum); { with Form[N] do writeln (Nl, , rжа', Surname: 8, Wage: 6, Prize: 9, Total: 8, Nl, , Общая сумма равна', Sum: 7, , ефимкам.', ео OuCpayroll } readln (Form[I].Surname) { ео ввода }  Контроль: } 
429 NI,NI, , Все... " NI,NI) end. { ео program } #include <iostream.h> // СИпроrрамма: #include <conio.h> #include <iomanip.h> const unsigned Lim == 20, Nlim == 9; struct Stringpayroll {char Surname [Nlim]j unsigned Wage, Prize, Total; }; // void OuCpayroll (Stringpayroll *Form, unsigned N, unsigned *S) {const char *One=="u", * Two == "u "; unsigned 1, FW, РР, РТ; cout«"\n\n" « setw(32) « "Платежнаяuведомость" «'\п' « Тшо «" \ nuuu Членыuu3арплатаuuП ремияuuВсеrоuuuuПодпись" «"\пuuбриrады" « setw(26) « "(ефимков)" «'\п' « Тшо; for(*S == 0,1 == о; 1 < N; 1 ++) {FW==(NI)*3; FP==FW*2j FT==FW+FP; *S+==FT; cout « "\nu"; cout.setf(ios::left); cout« setw(8) « Form[I].Surname; cout.setf(ios::right ); cout « setw(6) « FW « setw(9) « РР « setw(8) « РТ « '\п' « Оnе; Form[I]. Wage == FW; Form[I).Prize == РР; Form[I). Total == РТ; } firoI cout « '\п' « setw(17) « "Сумма" « setw(15) « *S « '\п' « Two « '\п'; return; } // ео OuCpayroll void main (void) // Payroll { struct Stringpayroll Form[Lim); unsigned N, 1, Nl, Sum; clrscr ( ); cout « "\п\п\п N ==== > "; cin» N; 
430 cout « "\п Список бриrады ======> \п"; for(I == о; 1 < N; 1 ++) { cout « '\п' « sеtw(З) « 1 + 1 « "ю фамилию ======> "; cin »Fo,m[I].Bu,name; } // ео ввода clrscr ( ); cout «"\п\п Ответ:"; OиCpay/oll(Po/т, N, &Вит); / /   Контроль: N1 == N  1; cout « "\п rжа" « setw(8) « Fo,m[N1].Bu,name « setw(6) « Fo,m[N1]. Wage « setw(9) « Fo,m[N1].P,ize « setw(8) « Fo,m[N1]. Tota! « "\ n Общая сумма равна " « setw(7) « Вит «" ефимкам." «"\п\п Все... \п\п"; } // ео program include 'fgraph.fi' ! ФОРТРАНпроrрамма: subroutine OиCpay/oll (Ро/т, Lim, N, В) implicit попе integer Lim, N, В, N1, 1 structure / St,ingpay]oll/ character Burname*8 integer Wage, P,ize, Tota! end structure record / Bt,ingpay/oll/ Ро/т(1 : Lim) character*( *) Оnе, Two parameter (Оnе == 'u', + Two == 'u ') write (*, '(jt14, а /а /а /а,17х, а/а)') + 'Платежная ведомость', + Two, + 'uuu Членыuu3арплатаuuП ремияuuВсеrоuuuuПодпись', + 'uuбриrады', '(ефимков )', + Two N1 == N + 1 S == о 
431 do 1 == 1, N, 1 Fo,m(I).Wage == (N1  1) * 3 Fo,m(I).P,ize == Fo,m(I). Wage * 2 Fo,m(I).Total == Fo,m(I). Wage + Fo,m(I).P,ize S == S + Fo,m(I).Total write (*,'(lх, а, i6, i9, i8 ja)') Fo,m(I).Su,name, Fo,m(I). Wage, Fo,m(I).P,ize, Fo,m(1).Total, Оnе ! ео 1 + end do write(*,'(12x,a,i15 ja)') return end! 'Сумма', S, Two ео OuCpay/oll program Pay/oи ! main: implicit попе external OuCpay/oll integer Lim, N, 1, Summa/y parameter (Lim == 20) structure j St,ingpay/oll j character Su,name*8 integer Wage, P,ize, Total end structure record j St,ingpay/ollj Ро/т(1 : Lim) саН clearscreen (О) write (*, '(/ j ja \)') , N ======> ' read (*, *) N write (*, '(/а)') , Список бриrады ======> ' do 1 == 1, N, 1 write (*, '(/i3, а \)') 1, 'ю фамилию ======> ' read (*, '(а)') Fo,m(I).Su,name end do ! ео ввода саН clearscreen (О) write(*, '(/jja)') , Ответ:' саН OuCpay/oll (Ро/т, Lim, N, S) с   Контроль: write(*, '(/a,a,i5,i9,i8 /a,i7,a //а /)') + ' rжа ',Fo,m(N).Su,name, Fo,m(N). Wage, + Fo,m(N).P,ize, Fo,m(N).Total, + ' Общая сумма равна', Summa/y, , ефимкам.', 
432 + end! Все... ' ео program Обоедunеnuе подобно структуре в том, что состоит из полей различ ных типов, но имеющих один и тот же начальный адрес. Комбинируя массивы, структуры и объединения, можно создавать разнообразные структуры данных, моделирующие сложные объекты (см. [58,59,28, 24,48,67, 50, 4, 42,62,6], а также [13,31,51, 2,3,8, 18]). Упражнения Решите приведенные ниже задачи обработки записей (структур). Ис пользуйте стандартные функции. 1. Из списка Номер Световой Номер Световой маршрута сиrнал маршрута сиrнал 9 белый  белый 38 желтый  желтый 17 белый  желтый 40 зеленый  зеленый 18 белый  синий 46 желтый  синий 20 зеленый  белый 53 синий  зеленый 21 желтый  белый 55 красный  синий 22 синий  синий 58 белый  красный 32 желтый  зеленый 61 желтый  желтый выберите не больше 10ти трамвайных маршрутов. По заданной KOM бинации световых сиrналов выдайте номер маршрута и наоборот: задан номер маршрута, получите на выходе комбинацию световых сиrналов. 2. Дано type Дек;арт == record х, у : extended end; Поляр == record r, 'Р : extended end; Приведите проrрамму, которая использует процедуру DP (d,p), пре образующую координаты точки из декартовых d в полярные р, и процедуру PD (р, d), выполняющую обратное преобразование. 3. Дано const Lstr == 64; Nmax == 2048; Lim == 128; 
433 type Cmpor;;a == string [Lstr]; )[{ителъ == record Фамилия} Тород : Cmpor;;a; Адрес: record Ули'Ца : Cmpor;;a; Дом} Корпус, Квартира 1..Nmax end end; Cnucor;; == array[l..Lim] of )[(ителъ; Напишите проrрамму, использующую процедуру ИронияСудъбы (С), которая находит фамилии двух жителей из списка С, живущих в разных rородах по одинаковому адресу. 4. Некоторые русские личные имена (рекла, назвища) можно pac пределить по записям/структурам: . числовые имена (Первак, Вторак, Третьяк, Четвертак, Пятак, Шестак, Семак, Осьмак, Девятко, Десятой); . имена по цвету волос, кожи (Черныш, Черняй, Чернява, Чер навка, Бел, Беляй, Беляк, Белой, Белуха); . имена, связанные с ростом, телосложением, с внешним видом (Сухой, Толстой, Долrой, Мал, Малыш, Малюта, Малой, Ma луша, Заяц,rуба, Беспалой, rолова, rоловач, Лобан, Большой, Безнос) ; . имена, связанные с характером, поведением (rроза, Правда, Добрава, Ворона, Бессон, Булrак, Забава, Крик, Истома, Мол чан, Неулыба, Смеяна, Несмеяна, Смирной); . имена, связанные с флорой/фауной (Волк, Кот, Жеребец, Ko рова, Бык, Щука, Трава, Пырей, Щавель). Напишите проrрамму слияния записей и сортировки имен в лексико rрафическом порядке. Найдите самое длинное имя и имя, в котором больше Bcero rласных букв. 5. Ювелирные камни по степени ценности классифицируются так: . драrоценные камни первоrо сорта (алмаз, сапфир, рубин, изумруд, шпинель, александрит, эвклаз); . драrоценные камни BToporo сорта (топаз, аквамарин, берилл, 
434 красный турмалин, кровяной аметист, альмандин, rиацинт, опал, циркон); . полудраroценные камни (rpaHaT, бирюза, зеленые и пестрые турмалины, чистой воды rорный хрусталь, сердолик, araT, дымчатый топаз (раухтопаз), светлый аметист, солнечный и лунные камни) j . самоцветные камни (нефрит, лазурит, амазонит, лабрадор, Ma лахит, авантюрин, яшма, янтарь, raraT (черный янтарь), KO ралл, перламутр); . отдельно  жемчуr. Напишите проrраммусправку по банку" Камни". Элементы каждой rруппы отсортируйте в лексикоrрафическом порядке. 6. Напишите проrрамму, контролирующую резервирование мест на авиарейс номер 'Ц'Ц'Ц. В салоне самолета размещено 10 рядов по 5 кресел в каждом ряду. При бронировании места запоминаются три символа  инициалы пассажира. Выведите схему мест после запол нения салона (заполнение случайное и не обязательно полное). Кто сидит в седьмом ряду в центре? А кто позади? 7. В международном турнире принимают участие 12 шахматистов. Сформируйте список, содержащий ФИО, названия стран, коэффи циенты Эло участников и их результаты (победа  1 очко, ничья  0.5, проиrрыш  О очков). Выведите фамилии спортсменов и коли чество набранных ими очков в порядке занятых мест. 8. Дано type Coтplex == record re, im : extended end; Coeff == record а, Ь, с : Coтplex end; { а =1= о } Приведите проrрамму, использующую процедуру Value (р, х, у), KO торая вычисляет у  значение квадратноrо трехчлена у == ах 2 +Ьх+с с коэффициентами из р в комплексной точке х. 9. Обработайте результаты подписки на rазеты и журналы (10 наиме нований): название, шифр, стоимость подписки на rод, число подпис чиков. Выдайте справку об общем количестве подписчиков и общей сумме полученных денеr. Какое издание пользуется наибольшей/ наименьшей популярностью? Какой журнал самый дороrой? 10. Напишите проrрамму, которая в подrотовленный заранее ша блон письма (например, приrлашение на симпозиум) вписывает BBe 
435 денные пользователем дату, адрес, подпись и пр., а потом выводит rOToBoe письмо. 11. Даны сведения о рыбах (по rороскопу): const Nmin == 30; Nmax == 250; type Имя == (Антон, Афанасий, Вадим, Вера, Венера, Виола, Вла дислав, Ирина, Ия, Мария, Манефа, Муза, Наум, Нина, Рафаил, Римма, Рудольф, Тимофей, Фаина, Эльвира, Эммануил); Данные == record Пол: ()Кен, Муж); Рост : Nmin..Nтax end; Труппа == аrrау[Имя] of Данные; Напишите проrрамму, которая использует: . функцию СредРост (Т), определяющую средний рост жен щин/мужчин из rруппы Т; . функцию Высох;ui1 (Т), определяющую имя caMoro BbIcoKoro мужчины из rруппы Т; . лоrическую функцию ОдинРост (Т), проверяющую, есть ли в rруппе Т хотя бы два человека одноrо роста. 12. Напишите проrрамму, в которой создается и используется ша блон с текстом поздравления: Уважаемхх, ИQФ! Сердечно поздравляем вас с наступающим уууу Новым [одом  ro дом ж! Желаем вам счастья, крепкоrо здоровья, творческих успехов и pa достноrо настроения! Ваши ректор декан 31. 12. ЧЧ Лесное ФИQ ФИQ Введите вместо хх  ая или ый; вместо ИQФ и ФИQ  фамилии, имена, отчества; вместо уууу  номер HOBoro rода; ж  название животноrо (Кабана, Крысы, Вола, Тиrра, Кролика, Дракона, Змеи, 
436 Лошади, Овцы, Обезьяны, Петуха, Собаки) и цц  две последние цифры номера cTaporo rода. Подrотовьте поздравления 12ти чело векам. 13. Дано const Lstr == 16; Nmax == 2048; Lim == 16; type СтрО1Са == string [Lstr]; Дата == record Число: 1..31; Месяц: 1..12; Тод : 1901..Nmax end; АН1Сета == record Фамилия: СтрО1Са; Пол: (М, )[(); День рожденu.я : Дата end; Труппа == array[l..Lim] of АН1Сета; Напишите проrрамму, которая использует: . процедуру Младwиu (т, Ф), присваивающую строке Ф фами лию caMoro юноrо мужчины из rруппы Т; . процедуру Вывести (т, Ф, Дj, выводящую фамилии людей из rруппы Т, начинающиеся с аббревиатуры Сидор, а также их дa ты рождения (например, фамилии Сидоров, Сидоренко, Сидор чук, Сидорович, Сидорчик, МакСидорбей, Сидорис, Сидорай те, Йысидоре, Лордсидоридзе, Сидор оrлы заде, ТерСидорян, Сидореску, Айсидоровский). 14. Во время баскетбольной встречи в список данных, содержащий ФИО и номера иrроков, вносятся набранные (случайным образом) очки (1, 2 или 3 очка). В команде 12 спортсменов. После окончания ИI'рЫ выведите номер лучшеro иrрока втречи, а также количество набранных им очков. Приведите ФИО всех иrроков в порядке убы вания набранных ими очков. 15. Ведомость содержит результаты сессии некоторой rруппы (в rруппе 12 студентов) по пяти экзаменам. Оценки (отл, хор, удовл, неуд) проставляются случайным образом. Дайте сведения об отлич никах, студентах, получивших неуд, и названия ДИСЦИПЛИН, по KO 
437 торым больше Bcero студенты получили отл и неуд. 16. Ведомость содержит сведения о семи видах товара, хранящеrося на складе: шифр товара, ero наименование, количество единиц, цена одной единицы. Отсортируйте эти сведения в порядке убывания цe ны одной единицы. Произведите корректировку сведений о товаре: k видов товара реализовано полностью, в т ВИДах изменилось KO личество единиц. Выведите текущие (последние) сведения о товаре. 17. Некоторые русские личные имена можно распределить по запи сям/структурам: . имена, которыми отмечалось (не)желаемость появления ребен ка в семье и друrие обстоятельства (Боrдан, Бажен, rолуба, Любим, Любава, Ждан, Неждан, Чаян, Нечай, Милава, Поз дей, Поспел, Хотен); . имена по времени рождения (Вешняк, Зима, Мороз); . имена, восходящие к древним поверьям (rоряин, Немил, He крас, Нелюба, Неустрой, Злоба, Старой, Туrарин); . имена, связанные с соседями или происхождением (Казарин, Чудин, Онтоман, Карел, Татарин, Мордвин, Француз, Тула); . имена, связанные с общественным положением, ремеслами (Князь, Барышник, Кузнец, Дуло, Ложка, Шуба). Напишите проrрамму слияния записей и сортировки имен по алфа виту. Подсчитайте общее количество слов. Найдите самое короткое имя и имя, в котором больше Bcero соrласных букв. 18. Даны списки, содержащие имена . из двух букв (Ив, Ия, Ор, Ян); . из трех (ArH, Вар, Фот, Вил, Вий, Фан, Вис, Фал, Вит, Том, Кай, rай, Тит, Дан, Сим, Дей, Руф, Див, Пуд, Ерм, Ной, Ида, Нит, Иов, Нил, Мар, Кир, Мал, Лев, Лин, Ада, Аза, Юст, Ева, Зоя, Лия); . из четырех букв (Фирс, Джон, Пров, Петр, Марк, Мавр, Лавр, Ларr, Лина, Лада, Клим, Васс, Джек, Берк, Блас, fлеб, Домн, Карп, Иван, Адам, Инна). "Слейте" их в один список. Отсортируйте имена в алфавитном по рядке и выведите список целиком. Найдите четырехбуквенные име 
438 на с максимальным/минимальным количеством rласных/соrласных букв. 19. Внекоторой rруппе не более 12ти студентов. Прошло полсеме стра. В журнале по дисциплине 'Тр Об" отмечены пропуски занятий, присутствие или выставляются оценки за ответы (отл, хор, удовл, неуд). Выведите ФИО студентов, не имеющих ни одной оценки, по лучивших неуд, отл+хор, отл+удовл, отл+хор+удовл, хор+удовл, имеющих пропуски занятий (в порядке возрастания числа пропус ков). 20. Имя Александр(а) породило имена Ася, Ара, Адя, Аля, Алик, Ксаня, Ксана, Алекс, Алекса, Алексаша, Саша, Сашура, Шура, Алексаня, Саня, Санюша, Нюша, Санюра, Нюра, а Мария  Маня, Маша, Мура, Мара, Маруся, Муся, Марик. Образуйте две записи. В каждой из них определите самое длинное/короткое имя. "Слейте" записи. Найдите общее самое длинное/короткое имя. Отсортируйте имена в порядке от Я дО А. 21. В конце рабочей неделе в память компьютера вводятся ФИО сборщиков, их рабочие номера и число изделий, собранных каждым рабочим ежедневно. Подсчитайте: . среДНее число собранных за день изделий; . наибольшее/наименьшее число изделий, собранных одним pa бочим; . фамилии тех рабочих и дни, коrда они достиrли наиболь шей/наименьшей производительности труда. 22. Составьте проrрамму, выдающую справку о номере квартиры, в которой проживает Mr. Х. В доме имеется 8 квартир и живут 16 человек. Пользователь вводит фамилию Mr. Х. Если в доме про живает несколько жильцов с такой фамилией, то выдайте сообще ние о необходимости ввода инициалов. Если инициалы у нескольких жильцов совпадают, то нужно ввести дополнительно rод рождения. Если с такими данными найден один жилец (несколько), то выведи те номер(а) квартир(ы), rде он(и) проживае(ю)т и все введенные о нем( них) сведения. Если жильца с такой фамилией нет, то выдайте сообщение об этом. 23. К семи спортивным журналистам обратились с просьбой назвать 
439 трех лучших российских футболистов прошлоrо сезона (по правилу: за 1 место  3 очка, за II  2 и за III  1 очко). Кто вошел в тройку лучших? Из каких они команд? 24. Создайте каталоr деталей, хранящихся на складе, объемом не бо лее 16 наименований. Каждая запись каталоrа содержит шифр дeTa ли, их количество и местоположение. По вводимому шифру компью тер сообщает о количестве деталей на складе и их местоположении. И наоборот, по заданному местоположению выдается информация о шифре детали и количестве. Внесите изменения в сведения о KO личестве деталей, оставшихся на складе после выдачи части из них покупателю. 25. Напишите проrрамму, производящую следующие расчеты. ДaH ные в виде месячной зарплаты рабочих со специальностями различ ных катеrорий сведены в такую таблицу Рабочий: Катеrория, Месячный Наименование фамилия разряд заработок, руб. цеха, отдела Незайцев А. Б. 5 х Ц01 Плохиш Е. Т. 6 у 002 Проруха В. С. 4 z Ц13 . Вычислите общую сумму ВЬЦIлат за месяц по всем катеrориям от общей суммы, среднюю месячную зарплату по катеrориям; . Напечатайте список работников цеха Ц'Ц'Ц/отдела О'Ц'Ц с YKa занием размера зарплаты и итоrовой ежемесячной суммы BЫ плат. 26. Создайте каталоr библиотеки из семи книr (по истории России). Он должен содержать шифр книrи, УДК, ФИО автора, название книrи, rод издания, место издания, издательство, число страниц и признак наличия книrи. Информация о читателе, взявшем книrу, должна быть такой: ФИО, факультет, rруппа, телефон, дата Bыдa чи/возврата. Найдите книrу с заданным шифром и отметьте выдачу книrи. Выдано две книrи. Приведите текущие (последние) сведения о библиотеке. 27. В православной церковной иерархии существуют три степени: епископство, священство и диаконство. Священнослужители, при нявшие монашеский обет, относятся к черному духовенству, осталь 
440 ные  к белому. Принять высокий сан епископа MorYT только преk ставители черноrо духовенства. Внутри каждой степени все священ нослужители равны между собой по блаrодати. Например, патриарх равен любому епископу и является лишь первым среди равных. Па триархом называется епископ столичноrо rорода (епископ MOCKOB ский, Алексий Второй  патриарх). Имеем структуру: Белое духовенство Черное духовенство Епископство Патриарх Митрополит Архиепископ Епископ Священство Протопресвитер Протоиерей Иерей Архимандрит Иrумен Иеромонах Диаконство Протодиакон Диакон Архидиакон Иеродиакон Заполните именами священнослужителей все иерархические CTPYK туры. Определите сан священнослужителя ХХХ. К какой степени и какому духовенству он принадлежит? 28. В чемпионате России по футболу принимают участие 18 команд. Создайте структуру данных из названий команд и результатов иrр: выиrрыш  2 очка, ничья  1 очко и проиrрыш  О очков. Обрабо тайте результаты (прошлоrоднеrо) чемпионата и выведите полные сведения о ero призерах. Из KaKoro rорода чемпион России? 29. Составьте проrрамму, выдающую справку о номерах рейсов авиа лайнеров до указанноrо rорода (число rородов  4, число рейсов  8). Кроме номера рейса по дополнительному запросу выдайте ин формацию о времени вылета самолета, ero типе и наличии свобод ных мест (после каждоrо запроса о данном рейсе количество свобод ных мест уменьшайте на единицу). Пользователь вводит название <орода. В ответ на это выведите номера рейсов самолетов. Для по 
441 лучения дополнительных сведений о рейсе вводится ero номер. Если пользователь сразу вводит номер рейса, то он получит дополнитель ные сведения о рейсе. Выведите сведения о запросах на каждый из имеющихся рейсов. Если rорода или рейса, введенноrо пользовате лем, нет, то выдайте соответствующее сообщение. зо. Создайте телефонный справочник вашей rруппы. Разработайте две процедуры, одна из которых по фамилии студента выдает номер ero телефона и адрес, а друrая по номеру телефона  фамилию и адрес. Файл Чтобы получить твердую копию результатов работы проrраммы, нужно вывести их на принтер. Для ввода значений составной пере менной (а они, как правило, мноrочисленны) или сохранения инфор мации по окончании работы Проrраммы (с целью последующей ее обработки) следует также использовать внешние устройства, наПри мер, жесткий диск и дискеты. Под фаi1лом понимают либо лоrиче ское устройство  источник или приемник текстовой информации, либо именованную область внешней памяти (винчестера, дискеты). ЛО2и'Чес-кие ycmpoi1cmBa  это специальные системные имена, KOTO рые даны стандартным аппаратным средствам компьютера: клавиа туре, экрану, принтеру, коммуникационным каналам ввода/вывода (например, prn  лоrическое имя принтера). Любой файл характеризуется тремя атрибутами: 1. Он имеет имя. 2. Он состоит из однотипных компонентов (их тип любой, кроме фай ловоrо и объектноrо). З. Ero длина неизвестна, не задается при объявлении, а оrраничена лишь емкостью внешнеrо устройства. Имя фаi1ла  это строковое данное (переменная или константа), состоящее не более чем из восьми символов: прописных и строчных латинских букв, цифр и символов ! # $ % & I ( )  @ '  Имя начинается с любоrо разрешенноrо символа l . За именем может 13апрещены имена аих, coml, com2, com3, сон, lptl, lpt2, lpt3, Hul и prH. MS DOS понимает их как имена лоrических устройств. 
442 следовать расширение. Оно отделяется от имени точкой и содержит до трех разрешенных символов. Использование расширения удобно, если оно описывает содержимое файла (к примеру, dat  от data, txt  от text и пр.). Прописные и строчные буквы и в имени, и в расширении не различаются. Перед именем файла можно указать nутъ х; фаuлу: имя диска, имя KopHeBoro каталоrа (папки) и имена подкаталоrов, например: 'D: \STUDUSER\ 1 0571\IVANOVP\ in.dat' Если путь не указан, то подразумевается, что файл находится в текущем каталоrе. Каждой проrрамме доступны два предопределенных файла со CTaH дартными файловыми переменными 2 (с-м. разд. 11 Стандартныи ввод/вывод" 2лавы 5). Любые друrие файлы и лоrические устрой ства станут известны компилятору только после выполнения про цедуры отх;ръtтия файла (лоrическоrо устройства). Она заключа ется в установлении связи файловой пере мен ной с именем существу ющеrо или создаваемоrо файла и в указании направления передачи данных: чтение из файла или запись в Hero. В результате специаль ная переменнаяуказатель, связанная с файлом, позиционируется на начало файла, т. е. на компонент с порядковым номером О (в Фор тране  с номером 1). При выполнении очередной операции переда чи данных файловый указатель 3 перемещается (в случае nоследова теЛЪНО20 доступа) к компоненту с номером 1 и т. д. Величина шаrа приращения определяется размером компонента. В случае nрЯ-МО20 доступа файловый указатель смещается к компоненту с заданным номером компонента. Перед завершением работы проrраммы следует прервать связь Me жду файлом и проrраммой, т. е., друrими словами, файл нужно за 20тметим, что файловая переменная освобождает нас от необходимости зна ния технической орrанизации обмена данными между аппаратными cpeДCTBa ми компьютера, так как проrрамма работает не с конкретными физическими устройствами, а с их образами в виде файловых переменных. При этом каждой такой переменной ставится в соответствие физический файл  именованная область памяти на какомлибо носителе информации. Аналоrами файловой пе ременной (Паскаль) являются указатель на файл (Си) и номер устройства BBO да/вывода или имя (внешнеrо) устройства (Фортран). ЗПодруrому файловый указатель называют .маркер файла, стрелка файла и даже окно. 
443 ?Срытъ. Тоrда все данные, имевшиеся в буфере, будут переданы в файл. Дело в том, что пересылаемые данные всеrда сначала посту пают во внутренний буфер файла и только после заполнения буфера они передаются на диск, принтер, экран или назначаются в качестве значений переменных. Если выполнение проrраммы заканчивается до закрытия файла, то часть данных может остаться в буфере и в pe зультате будет утеряна. Кроме Toro, не будет записан специальный признак  символ конца файла, значит, в друrой раз проrрамма не сможет получить доступ к файлу. Без закрытия файла буфер можно очистить с помощью процедуры выталкивания данных. Файлы бывают двух типов  текстовые и двоичные. Передача KOM понентов те?СстовО20 фаi1ла всеrда сопровождается их преобразова нием из символьноrо представления во внутреннее и наоборот  из BHYTpeHHero в символьное. При обработке двои'Ч1tО20 фаi1ла обмен данными выполняется без преобразования: при записи в файл копи руется содержимое ячеек оперативной памяти, а при чтении после довательность байтов двоичноrо файла переносится в ячейки опера тивной памяти, зарезервированные под элементы ввода. Текстовый файл предназначен для чтения человеком (он содержит строковое представление выходных данных всех типов), а двоичный  для хранения на диске данных, которые потребуются в процессе выпол нения проrраммы. Передача компонентов двоичноrо файла происхо дит быстрее и такой файл, как правило, имеет меньшую длину, чем текстовый файл с теми же данными. ФаUлы в Паскале в Паскале текстовые файлы объявляются типом text, а двоичные, типизированные, задаются фразой file of тип и нетипизирован ные  типом file. Переменную файловоrо типа можно объявить Ok ним из следующих способов: type и-мя фаi1ловО20 типа == file of тип; var и-мя фаi1ловоi1 nepeMe1t1toi1 : textj и-мя фаi1ловоi1 nepeMe1t1toi1 : и-мя фаi1ловО20 типа; и-мя фаi1ловоi1 nepeMe1t1toi1 : file of тип; и-мя фаi1ловоi1 nepeMe1t1toi1 : filej rде тип  любой тип, кроме файловоrо. Связь файловой переменной с конкретным физическим файлом или 
444 устройством устанавливает процедура assign. Обращение к ней BЫ полняется оператором 'Нлзна'Чения, который имеет вид assign ( имя фаi1ловоi1 nеременнои, внешнее имя) rде внешнее имя  строковое данное, представляющее собой имя файла на диске (дискете) или лоrическое устройство (например, 'prn'). Здесь, в операторе процедуры, явно указывается, на каком устройстве находится или будет находиться тот или иной набор дaH ных. Для открытия файла применяют две процедуры: первая из них, с именем reset, открывает существующий файл для чтения, а вторая, с именем rewrite, открывает новый файл для записи. COOTBeTCTBY ющие операторы отх:рытия фаi1лов имеют вид reset (имя фаi1ловоi1 nеременнои) rewrite (имя фаi1ловоi1 nеременнои) При открытии процедурой rewrite существующеrо файла все дaH ные из Hero будут стерты. Чтобы по ошибке не потерять информа цию, рекомендуется предварительно создавать резервные копии тех файлов, которые будут открываться процедурой rewrite. Процедура close закрывает файл. Оператор зах:рытия фаi1ла имеет вид close (имя фаi1ловоi1 nеременнои) После выполнения оператора связь файловой переменной с именем файла, установленная ранее процедурой assign, сохраняется. Следо вательно, файл можно повторно открыть без дополнительноrо обра щения к процедуре aSSlgn. Процедура flush сбрасывает на диск содержимое файловоrо буфера и, таким образом, rарантирует сохранность на диске всех последних изменений файла. Оператор о'Чистх:и буфера имеет вид flush (имя фаi1ловоi1 nеременнои) Процедура flush иrнорируется, если файл был открыт процедурой reset для чтения. Лоrическая функция eof (имя фаi1ловоi1 nеременнои) проверяет x:o неч фаi1ла. Она возвращает true, если файловый указатель стоит в конце файла. При чтении это означает, что файл исчерпан, а при записи  очередной компонент будет добавлен в конец файла. 
445 Функция ioresult возвращает условный признак последней опера ции ввода/вывода. При успешном завершении операции функция дa ет ноль. Эта функция доступна только при отключенном контроле ошибок ввода/вывода (директива компилятора {$I+} включает KOH троль, а {ы} отключает ero). Кроме Toro, для всех трех типов файлов определено еще не менее 15 процедур (например, процедуры изменения текущеrо каталоrа, выделения имени текущеrо каталоrа и пр. (см. [58])). Компоненты тех:стовО20 фаuла имеют тип text. Такой файл co стоит из строк переменной длины. Доступ к каждой строке возмо жен лишь последовательно, начиная с первой. Считать nю строку можно только после Toro, как уже считаны предыдущие (n  1 )a строки. При создании TeKcToBoro файла в конце всех строк ставит ся признак eoln  конец строки, а в конце файла  признак eof. Признак eoln представляет собой следующую последовательность /1аски/1кодов: возврата каретки  символ CR (АSСIIкод 13) и пе ревода строки  символ LF (АSСIIкод 10). В процессе обработки TeKcToBoro файла комбинация символов CR LF преобразуется в одиночный символ LF при чтении, а символ LF  в комбинацию CR LF при записи 4 . Кроме Toro комбинация клавиш (Ctrl) + (z) интерпретируется как символ конца файла. Чтение данных из файла производится с помощью операторов ввода, имеющих вид read (и.мя фаuловоu nере.меннои, сnисох: ввода) readln ( и.мя фаuловоu nере.меннои ) сnисох: ввода) readln (и,мя фаuловоu nере.меннои) а запись в файл  посредством операторов вывода вида write (и.мя фаuловоu nере.меннои ) сnисох: вывода) writeln (и.мя фаuловоu nере.меннои ) сnисох: вывода) writeln (и.мя фаuловоu nере.меннои) Процедура append открывает текстовый файл для добавления дан- ных в конец существующеrо файла. Оператор расширения фаuла имеет вид append ( и.мя фаuловоu nере.меннои) 4 В ДВОИЧНОМ файле преобразование символов CR  LF подавляется. 
446 Если же текстовый файл был открыт посредством процедуры reset или rewrite, то выполнение оператора append приведет к закрытию этоrо файла и открытию ero вновь для добавления информации. При этом файловый указатель устанавливается в конец файла. Лоrическая функция eoln[( имя фаi1ловоi1 nepeMe'/t'/toi1)} проверяет 1Соне'Ц стРО1Си во вводном текстовом файле. Она возвращает true, если файловый указатель достиr признака конца строки. Коrда и-мя фаi1ловоi1 nepeMe'/t'/toi1 опущено, функция проверяет CTaHдapT ный файл input. Отметим, что существует отличие в работе функ ций eoln и eof с дисковыми файлами и лоrическими устройства ми: функции тестируют соответствующие признаки для файла перед очередным чтением, а для лоrическоrо устройства  после чтения. Приведем пример, в котором оценим объем некоторой книrи в учет ноиздательских листах. Для этоrо общее количество символов TeK cToBoro файла разделим на 40000: program Sizeofbook; {$N +} uses crt; const Nlim == 80; W == 9; D == 6; Nl == #13#10; type Lenstr == string [Nlim]; var Fi, Ро: text; Finame, Роnате: Lenstr; Sum: extended; function Count (var Р: text): extended; { const Slim == 128; var S: string [Slim); N: longint; begin N :==0; while not eof(F) do begin readln (Р, S); inc (N, length(S)) end; Count:== N/40000.0; exit end; { begin clrscr; write (NI,NI, , Имя файлаисточника ======> '); readln (Finame); assign(Fi, Finame); {$I} reset(Fi); {$I+} if ioresult < > О then } ео Count } {  Statements: } 
447 begin writeln (Nl, , Невозможно открыть файл " Finame, Nl, , См. имя файла и каталоr.' ); halt end; write(Nl,' Имя файламишени ======> '); readln(Foname); assign (Ро, Роnате); rewrite (Ро); Вит :== Count (Fi); writeln (Ро, Nl, , Имя файлаисточника  " Finame, Nl, , Имя файламишени ', Роnате, Nl,Nl, , Ответ:', Nl, , Уч.изд. л. " Вит: W: п, Nl,Nl, , Все...', Nl); close (Ро) close (Fi); end. { ео program } Вводной и выводной файлы имеют следующий вид: Любая маленькая проблема имеет простое и ясное неправильное решение. Ответ: Уч.изд. л. 0.001725 f( типизированным фаuлам относятся файлы, объявленные как file of тип. Чтение TaKoro файла выполняет оператор ввода ВИда read ( имя фаuловоu nеременнои, списо".. ввода) а запись данных в файл  оператор вывода вида write ( имя фаuловоu nеременнои, списо".. вывода) Длина каждоrо компонента типизированноrо файла постоянна, что дает возможность реализовать nрЯМОU доступ к любому из них по ero номеру. Устанавливает файловый указатель к требуемому KOM поненту процедура seek. Оператор смеЩения у"..азателя имеет вид seek (имя фаuловоu nеременнои, номер "..омnонента фаuла) Первый компонент файла имеет номер О. Функция filesize ( имя фаuловоu nеременнои) возвращает число KOM понентов файла. Например, чтобы переместить файловый указатель в конец файла, нужно выполнить оператор seek ( имя фаuловоu nеременнои, filesize ( имя фаuловоu nеременнои)) 
448 Функция filepos (имя фаi1ЛО60i1 nepeMeHHoi1) определяет номер TeKY щеrо компонента файла. В качестве примера обработки типизированноrо файла приведем проrрамму перевода слов с одноrо языка на друrой: program Translator; uses crt; const NI == #13#10; procedure Dictionary; { const Lim == 80; Оnе == ' type LenStr == string [Lim]; DicStr == record Word, Меаn: LenStr end; var NameDic, In Word: LenStr; N, 1 : word; F : Ше of DicStr; StrDic: DicStr; Flag: boolean; } '. , begin clrscr; write (NI,NI, , engrus  анrлорусский словарь,', NI, , fraJus  Франкорусский словарь,', NI, , ger...rus  rерманорусский словарь.', NI,NI, , Имя словаря (7 символов: см. выше) ======> '); readln (N ameDic); write (' Число пар слов в словаре ======> '); readln (N); assign (Р, NameDic); for 1:== 1 to N do begin write (' " 1, 'e '+сору (NameDic, 1, 3)+'e слово readln (StrDic. Word); write (' Ero '+сору (NameDic, 4, 3)+'й эквивалент ======> '); readln (StrDic.Mean); write (Р, StrDic) end; { ео ввода словаря} write (' '+сору (NameDic, 1, 3)+'e слово для перевода ======> '); readln (In Word); writeln (NI, Оnе, NI, , { Ввод словаря и перекачка ero в файл Р: } rewrite (Р); ======> '); Ответ:'); 
449 { Поиск слова для перевода: } end end; writeln (Nl, end; { reset (Р); Flag:== false; while not Flag do if eof(F) then begin Flag:== truej writeln (Nl,' Sorry. Нет TaKoro слова в словаре '+NaтeDic+'.') end { Нет слова } else begin read (Р, StrDic); if /n Word == StrDic. Word then begin Flag :== true; write (Nl, , " /n Word: length иn Word), Nl, , " StrDic.Mean: length (StrDic.Mean)) { ео перевода } { Слово найдено } Оnе); close (Р) ео Dictionary } begin clrscr; writeln (' Перевод с одноrо языка на друrой.'); Dictionary; writeln (Nl, , Все... ') end. { ео program } Нетunuзuровтt1t'Ые фаi1л'Ы объявляются словом file без указания ти па ero компонентов. Это, вопервых, делает такие файлы совмести мыми с типизированными файлами и, BOBTOpЫX, обеспечивает BЫCO коскоростной обмен данными между оперативной памятью и диском. Чтение из файла и запись в файл производятся блоками, поэтому в операторах reset и rewrite вторым aprYMeHToM должен быть размер блока файла в байтах (например, 512). Все средства, доступные типизированным файлам, можно использо вать и в работе с файлами без типа. Исключение составляют про 
450 цедуры read и write. Вместо них применяют процедуры blockread и blockwrite. Соответствующие операторы ввода/вывода имеют сле ДУЮЩИЙ вид: blockread (имя фаi1ловоi1 nepeMeHHoi1, имя буфера, n[, k)) blockwrite (имя фаi1ловоi1 nepeMeHHoi1, имя буфера, n [, k)) Они обеспечивают передачу в буфер n компонентов файла за oд но обращение к диску. Необязательный выходной параметр k есть число фактически обработанных компонентов. Фаi:iлы в Си Информация, необходимая для работы с файлами в Си, хранится в файле заrоловков <stdio.h>. В нем посредством оператора typedef определен тип данных FILE. Фактически это описание структуры, тип которой имеет имя FILE. Она предназначена для хранения CBe дений о файле. Указатели на файлы объявляют следующим обра зом: FILE * имя ух;азателя на фаi1Лl , * имя ух;азателя на фаi1Л2, . . . , * имя ух;азателя на фаi1л n ; Функция, отХ;РЫ6ающая фаi1л, возвращает значение указателя на структуру типа FILE. Это значение надо присвоить указателю на файл: имя ух;азателя на фаi1л == fopen ( внешнее имя, режим обработ х;и фа i1ла ) [ J Здесь внешнее имя  строковое данное, представляющее собой имя файла на диске (дискете) или лоrическое устройство (например, "prn"). Режим обработх;и фаi1ла  также строка, которая может принимать одно из следующих значений: "r"  чтение существующеrо файла; Ilw"  запись в файл (существующий файл будет стерт); "а"  добавление в конец файла (если файла eT, он создается). Можно открыть файл и для чтения, и для записи. Тоrда режимом обработх;и фаi1ла должна быть одна из строк "r+", "w+" или "а+". По умолчанию файл является текстовым. Явно текстовый файл объ являют добавлением к режиму обработки символа t, а двоичный  символа Ь (например, "r+b" или "rb+"). Текстовый файл COCTO 
451 ит из последовательности символов, разбитой на строки с помощью управляющеrо символа \п. Двоичный файл  это последователь ность символов в двоичном формате. Для каждоrо oTKpbIBaeMoro файла формируется своя структура ти па FILE. После успешноrо открытия указатель файла можно ис пользовать в различных функциях ввода/вывода. Таких функций насчитывается более 40 [28, 24, 48, 67, 55, 50]. Если файл не yдaeT ся открыть, то функция fopen вместо адреса файловой структуры возвращает нулевой указатель NULL, и работа проrраммы закан чивается. Функция fclose (имя у""азателя на фаtiл)[) закрывает файл. Результатом ее выполнения будет О  отключение связи между указателем на файл и внешним набором данных за вершено успешно или, в противном случае,  значение EOF 5 . Все открытые файлы, кроме stdin, stdout, stdprn, stderr и stdaux, можно закрыть посредством одноrо вызова функции fcloseall ( ) [) Она возвращает либо число закрытых файлов, либо значение EOF. Типы обеих функций  int. Функция fflush (имя у""азателя на фаtiл)[) возвращает О, если успешно выполнена о-чист""а буфера; в противном случае значение функции есть EOF. Функцию flushall ()[) применяют для сброса буферов всех открытых файлов. Функция feof ( имя у""азател.я на фаtiл) [) возвращает ненулевое значение, если файловый указатель достиr ""он'Ца фаtiла; в противном случае значение функции равно О. 5#define EOF (1) используется для проверки конца файла, как правило, при посимвольном чтении из файла; при построчном вводе для определения конца файла обычно применяют значение NULL, так как при достижении конца файла будет получен нулевой указатель. 
452 Функции fgetc, fputc, fgetchar и fputchar предназначены для ne реда'Ч-и символов. Функция fgetc (имя у-казаmеля на фаi1л)[J читает символ из файла и преобразует ero к типу int. Теперь этот символ можно присвоиrь iпtпеременной. В случае ошибки ввода или при конце файла функция возвращает значение EOF. Функция fputc (символъная nеременная, имя у-казаmеля на фаi1л)[ J пишет значение символъноi1 nepeMeHHoi1 в файл. Если запись про шла успешно, она возвращает iпtзначение символъноi1 nepeMeHHoi1; в противном случае значение функции есть EOF. Функции fgetchar () [ J fputchar ( символ ъная nеременная) [) работают соответственно со стандартными файлами stdin и stdout. Функции fgets и fputs предназначены для nереда'Ч-и стро-к. Функция fgets (сmро-ковая nеременная, [, имя у-казаmеля на фаi1л)[ J вводит строку из файла. Ее символы считываются в cтpo-кo вую nеременную, пока не будет выполнено одно из условий: 1. Начнется новая строка. 2. Достиrнут конец файла. 3. Условия 1 или 2 не выполнились, но прочитан l  1 символ 6 . После достижения конца файла ero признак и нультерминатор пе ре носятся в конец сmро-ковоi1 nepeMeHHoi1. При успешном выполне нии функция определяет адрес сmро-ковоi1 nepeMeHHoi1; при конце файла или в случае ошибки возвращается значение NULL. Функция fputs (сmро-ковая nеременная, имя у-казаmеля на фаi1л)[ J пишет строку в файл. Если запись прошла успешно, она возвращает iпtзначение последнеrо записанноrо символа сmро-ковоi1 nepeMeH HOi1; в противном случае ее значение есть EOF. Эта функция, про 6Если проrрамма обрабатывает произвольный текстовый файл, то peKOMeH дуется значение 1, равное 81. 
453 изводя построчный вывод данных в не добавляет признак новой строки. вручную. Например: #include <stdio.h> #include <string.h> #include <process.h> #define LaJa printf("\n Sentence ======> ,,) void main (void) // FPUTS { FILE *Р; char *Рhrаsе=="Без денеr и свободы нет. А. С. Пушкин" "и долrОвечно царственное слово. А. А. Ахматова"; if((F == fopen(" Hip.hop", "w")) ==== NULL) { puts ("\п\п *** error: невозможно открыть файл."); exit (1); } Lala; while (strlen (gets (Phrase)) > О) { fputs (Phrase, Р); fputs ("\п", Р); } // файл (например, на принтер), Значит, этот код надо вводить LaJa; } ео example fputs("\n", . . . Функция fscanf ( имя ух:азателя на фаi1л, "сnисох: форматов"! сnисох: ввода}) [) выполняет форматное 'Чтение данных из файла. Если ввод произ веден успешно, значением функции будет число введенных данных; при конце файла функция возвращает значение EOF. Эта функция так же, как и функция scanf, не умеет читать строки, содержащие пробелы (см. fgets и fread). Функция fprintf( имя ух:азателя на фаi1л, "сnисох: форматов"! сnисох: вывода}) [) выполняет форматную запись данных в файл. Если вывод CДe лан успешно, значением функции будет число переданных символов (байтов); в случае ошибки функция возвращает значение EOF. В качестве примера использования определенных выше средств представим Сипроrрамму Sizeofbook: #include <stdio.h> #include <string.h> 
454 #include <prOCe88.h> #include <conio.h> COn8t un8igned Nlim := 81; double Count (FILE *Р) jj { COn8t un8igned Slim := 128; char 5 [Slim]; un8igned long N := о; while (fget8 (5, Slim, Р) !:= NULL) N +:= 8trlen (5)  1ul; return double (N)j40000.; } jj ео Count void main (void) jj Sizeofbook { FILE *Fi, *Fo; char Finame [Nlim], Foname [Nlim]; double Sum; clr8cr ( ); printf("\n\n Имя файлаисточника :=:=:=> "); fflU8h(8tdin); get8 (Finame); if((Fi:= fopen(Finame, "r")):=:= NULL) { printf("\n Невозможно открыть файл %8" "\п См. имя файла и каталоr.", Finame); exit(l ); } printf("\n Имя файламишени :=:=:=> "); fflU8h(8tdin); get8 (Foname); Fo:= fopen (Foname, "w"); Sum:= Count(Fi); fprintf(Fo, "\п Имя файлаисточника  %8" "\п Имя файламишени  %8" "\п\п Ответ:" "\п Уч.изд. л. %9.61f" "\п \п Все. .. \п", Finame, Foname, Sum); fclo8e (Fi); fclo8e (Fo); } // ео program Функции fread и fwrite обрабатывают nоследователъности баi1 тов. Они удобны при передаче составных данных в двоичном фор мате. Функция fread (у'К:азателъ, раЗМер, 'К:оли'Чество, имя у'К:азателя на фаi1л) [) читает из файла указанное 'К:оли'Чество данных. Размер каждоrо данноrо задан в байтах. Читаемая информация помещается в 
455 область памяти, адресуемую уазателем. Функция возвращает чи сло фактически считанных данных. К примеру, введем структуру DicStr из файла Р: fread (&DicStr, sizeof(DicStr), 1, Р); Так как в списке aprYMeHToB установлено, что следует читать по одной структуре, то текущее значение функции равно 1. После дo стижения конца файла функция возвращает О. Функция fwrite пишет данные в файл. Список ее aprYMeHTOB анало rичен списку aprYMeHToB функции fread. Функция возвращает чи сло фактически записанных данных. Например, пере шлем на диск структуру DicStr: fwrite (&DicStr, sizeof(DicStr), 1, Р); Функция rewind (им'я' уазател.я на фаilл); передвиrает файловый указатель в начало файла. Теперь приведем Сипроrрамму Translator. В ней используются функции fflush, feof и rewind: #include <stdio.h> #include <string.h> #include <conio.h> #include <process.h> void Dictionary ( ); void strNLcpy(char В1[], char В2[], unsigned N, unsigned L); void main ( ) // Translator { clrscr () j puts (" Перевод с одноrо языка на друrой."); Dictionary (); puts ("\п Все. .. ,,); } / / ео таш void Dictionary () / / { const unsigned LenStr == 81; const char * Оnе == " struct DicStr {char Word [LenStr], Меаn [LenStr];} StrDicj char NaтeDic [LenStr], [n Word [LenStr], R [LenStr], Q [LenStr]; unsigned N, 1, Flag, True == 1, False == о; FILE *Р; ". , 
456 clr8cr( ); printf("\n\n ita.Jus  итальянскорусский словарь," "\п sparus  испанскорусский словарь," "\п porrus  портуrальскорусский словарь." "\п \п Имя словаря (7 символов: см. выше) ======> ,,); get8 (NaтeDic); strNLcpy (R, NaтeDic, 1,3); strNLcpy (Q, NaтeDic, 4, 3); printf(" Число пар слов в словаре ======> ,,); 8canf("%u", &N); fflU8h (8tdin); // Ввод словаря и перекачка ero в файл Р: F == fopen (NaтeDic, "w+"); for(I==l; I<N+1; 1++) { printf (" %иe %8e слово get8 (StrDic. Word); printf(" Ero %8Й эквивалент ======> ", Q); get8 (StrDic.Mean); fprintf(F, "%8\П%8\П", StrDic. Word, StrDic.Mean); } // ео ввода словаря printf(" %8e слово для перевода ======> ", R); get8 (In Word); printf("\n%8\n  > " 1 R) '  " , Ответ: \п", Оnе); / / Поиск слова для перевода: rewind (Р); Flag == False; while (! Flag) if (feof(F)) { Flag == True; printf("\n Perdonare. Нет TaKoro слова в словаре %8.\п", NaтeDic ); / / Нет слова } el8e { f8canf(F, "%8 %8", StrDic. Word, StrDic.Mean); if(8trcmp (In Word, StrDic. Word) ==== О) { Flag == True; printf("\n %s\n } %8", In Word, StrDic.Mean); / / ео перевода / / Слово найдено } printf("\n%8\n", Оnе); } // fclo8e (Р); ео Dictionary 
457 void strNLcpy (char 51[), char 52 [), unsigned N, unsigned L) {unsigned М, I<==N+L, 1==0, J; //1 С Nй позиции CTpO М == strlen (52)+1; //1 ки 52 выделяется под if(2<==I< && I< <==М) //1 строка 51 длины L. {for(J==N1; J<M; J++) 51[1++)==52[J); 51[L] =='\0'; return; } else { puts ("\п *** error: проверьте номер позиции, длину" "\п подстроки и длину строки. strNLcpy. "); exi t (1); } } // // // ео вырезки подстроки / / Нет подстроки ео strNLcpy ео program Следующие две функции служат для nр.яМО20 доступа к байтам (обычно внутри двоичных файлов). Функция fseek (им.я у'К:азател.я на фаi1л, смещение, от'К:уда)[ J перемещает файловый указатель на заданное смещением число бай тов, начиная с позиции, установленной aprYMeHToM от'К:уда. Смеще ние  это длинное целое, а от'К:уда  это есть: О SEEKSET  смещение от начала файла; О SEEKCUR  смещение от текущей позиции файловоrо указа теля; О SEEKEND  смещение от конца файла. При успешном выполнении функция возвращает О. Попытка YCTaHO вить файловый указатель перед началом файла является ошибкой, и тоrда fseek возвращает ненулевое значение. Контрольноезание Замените rewind на fseek. Ответ fseek (им.я у'К:азател.я на фаi1л, OL, SEEKSET); Функция ftell (им.я у'К:азател.я на фаi1л) [) 
458 определяет текущую позицию файловоrо указателя. Она возвраща ет величину смещения (в байтах) относительно начала файла. При неудачном выполнении значением функции будет lL. Функция ferror (имя указател.я 'На Фаi1л)[J позволяет определить, была ли ошибка при передаче файла. Воз вращаемое нулевое значение свидетельствует о том, что ошибок не было, а не нулевое  сиrнализирует об ошибке. Функция clearerr ( имя указател.я 'На фаi1л); очищает признак ошибки. Если подключить заrоловочный файл <fstream.h>, можно приме нять nотоковую передачу да'Н'Ных. Чтобы создать потоки для чтения файла и записи в файл, нужно использовать следующие средства: ifstream имя фаi1ловоi1 nepeMeHHoi1; ofstream имя фаi1ловоi1 nepeMeHHoi1; имя фаi1ловоi1 nepeMeHHoi1.open (в'Неш'Нее имя); имя фаi1ловоi1 nepeMeHHoi1 » Vl » V2 » ... » V n ; имя фаi1ловоi1 nepeMeHHoi1 « аl « а2 « . .. «а n ; Здесь Vl, V2, ..., V N  переменные, а al, а2, ..., а n  выражения. Для примера приведем Сипроrрамму Sizeofbook. В ней использу ются файловые потоки ввода Fi и вывода Ро, функция ввода CTpO ки getline(cmpoKa, дли'Настроки) и функция peek(), позволяющая "взrлянуть" на очередной символ вводноrо потока: #include <fstream.h> #include <string.h> #include <process.h> #include <conio.h> #include <iomanip.h> const unsigned Nlim == 81; double Count (ifstream& Р) // { const unsigned Slim == 128; char 5 [Slim]; unsigned long N == о; while (F.peek()!== EOF) {F.getline (5, 5Iim); N+== strlen (5);} 
459 return double (N)j40000.; } jj void main (void) jj Bizeofbook { ifstream Fi; ofstream Ро; char Finame [Nlim], Роnате [Nlim]; double Вит; clrscr ( ); cout « "\n \n Имя файлаисточника ======> 11 « flush; cin »Finame; Fi.open (Finame); if(!Fi) { cout « "\n Невозможно открыть файл 11 « Finame « "\n См. имя файла и каталоr."; exit(l); } cout « "\n Имя файламишени ======> " « flush; cin »Роnате; Fo.open (Роnате); Вит == Count(Fi); Ро « "\n Имя файлаисточника  " « Finame « "\n Имя файламишени "« Роnате « "\n\n Ответ:" « "\n Уч.изд. л. " « setw (9) « setprecision (6) « Вит «"\n\n Все ... \n"« endl; Fi.close ( ); Fo.close ( ); } jj ео program ео Count Фаi:tлы в Фортране В Фортране система вводаjвывода основывается на понятии запи си [4, 42, 62, 6]. Заnисъю называется лоrически завершенная rруп па данных (например, строка символов, заканчивающаяся символом новой строки). Записи бывают форматные, неформатные и запись конца файла. Неформатная заnисъ создается без преобразования данных. Файл состоит из записей и завершается записью х;онец фаi1 ла (при вводе с клавиатуры х;онец фаi1ла проставляется OДHOBpeMeH ным нажатием клавиш (Ctrl) + (z)). В Фортране различают файлы внешние и внутренние. Внешнui1 фаi1л  поименованная область памяти на внешнем носителе. Такой файл можно открыть (друrими словами, подсоединить к устройству 
460 ввода/вывода) для последовательноro или прямоrо доступа. Внеш ний файл бывает форматным (текстовым), двоичным или неформат ным. Файлы последних двух типов содержат неформатные записи. BHympeHHui1 фаi1л  строка или массив. Он размещается в опера тивной памяти. Здесь этот файл не рассматривается. К устройствам ввода/вывода можно подсоединить любые файлы и физические устройства (принтер, параллельный порт и т. п.). Ta кие устройства имеют номера. Всеrда каждой Фортранпроrрамме известны устройства с номерами *, о, 5 и 6, причем по умолчанию к устройствам *, О или 5 подсоединена клавиатура, а к устройствам *, О или 6  экран. Номер ycmpoi1cmBa 7  переменная или константа типа integer, принадлежащая отрезку [о; 32767]. Перед открытием файла номер ycmpoi1cmBa должен быть задан, например, любым из предложенных ниже способов: integer номер ycmpoi1cmBa/ OHcтaHтa/, . . . parameter ( номер ycmpoi1cmBa == OHcтaHтa, . . .) номер ycmpoi1cmBa == OHcтaHтa . Именно по номеру ycmpoi1cmBa после открытия файла осуществля ется доступ к файлу. Внешний файл подсоединяется к устройству ввода/вывода посред ством оператора от""рытия фаi1ла вида ореп (unit == номер ycmpoi1cmBa, file == внешнее имя, status == cтa туе, iostat == вид ошиби, access == вид доступа, action == pe ж;им обработи фаi1ла, blank == пробел, blocksize == размер, саrriаgесопtrоl==nервыi1 символ, dеlim==О2рани-ч;ителъ, err== Meтa, form == тип фаi1ла, pad == nревыситъ длину формат HOi1 записи, position == позиция, recl == длина) Здесь в спецификации unit номер ycmpoi1cmBa задает номер устрой ства, к которому подсоединяется файл с именем внешнее имя. В спецификации status статус есть 'old'  файл должен суще ствовать, 'new'  файл не должен существовать, 'scratch'  файл временный или 'unknown'  неизвестный (сначала делается попыт ка открыть файл со статусом 'old', а затем  со статусом 'new'; 'unknown' установлен по умолчанию). Эта спецификация имеет 7Напомним, что в Паскале это файловая переменная. 
461 смысл только для файла на диске. В спецификации iostat 6uдошuбх:u есть целочисленная переменная, значение которой равно О при отсутствии ошибок открытия фай ла,  отрицательному числу, если обнаружен конец файла, или  номеру возникшей ошибки. В спецификации access 6иддостуnа есть 'direct'  прямой, 'sequ ential'  последовательный (установлен по умолчанию) или 'ap pend'  последовательный файл, открываемый для добавления в конец файла. В спецификации action реж;uм обработх:u фаi1ла есть 'read'  для чтения, 'write'  для записи или 'readwrite'  для чтения и записи (установлен по умолчанию). в спецификации blank пробел есть 'zero'  при вводе числовых данных все пробелы в поле ввода, кроме начальных, будут ВОСПри ниматься как нули или 'пиВ'  все пробелы будут проиrнорированы (установлен по умолчанию). в спецификации blocksize размер задает размер буфера, исполь зуемоrо при передаче данных (по умолчанию установлен размер, равный 512 байтам). В спецификации carriagecontrol nep6bti1 СUМ60Л задает способ ин терпретации первоrо символа каждой записи форматноrо файла: 'fortran'  первый символ является символом управления кареткой принтера и не выводится ни на принтер, ни на экран (установлен по умолчанию) или 'list'  первый символ не является управляющим символом и всеrда выводится. В спецификации delim оzра1tU'iuтелъ определяет способ выдачи символьных и строковых данных: 'apostrophe'  окаймлять их апо строфом, 'quote'  кавычкой или 'попе'  ни тем, ни друrим сим волом (установлен по умолчанию). в спецификации err метх:а есть метка оператора, которому переда ется управление, если при выполнении открытия файла возникает ошибка. В спецификации form тиn фаi1ла есть 'formatted'  файл формат ный, 'binary'  файл двоичный или 'unformatted'  файл нефор матный. По умолчанию для последовательноrо доступа установлен 
462 'formatted', а для прямоrо  'unformatted'. В спецификации pad npeвыитъ'b длину форматноil записи есть 'yes'  запись дополняется пробелами, если список ввода или спи сок форматов требуют больше данных, чем наличествует в записи (установлен по умолчанию), или 'по'  в противном случае. В спецификации position позиция есть 'rewind'  файловый YKa затель установить в начало файла, 'append'  в конец файла или 'asis'  не изменять позицию файловоrо указателя. И, наконец, в спецификации recl длина есть целочисленное данное, задающее длину каждой записи (в байтах) файла прямоrо доступа. Все спецификации оператора ореп можно опустить за исключени ем номера ycmpoilcmea. Если фраза unit == не указана, то номер ycmpoilcmea должен начинать (возможный) список спецификаций 8 . Оператор close (unit == номер ycmpoilcmea, err == метх:а, iostat == вид ошибх:и, status == статус) закрывает файл. В спецификации status статус есть 'delete'  после закрытия файл удалить или 'keep'  файл сохранить (YCTa новлен по умолчанию). Оператор rewind (unit == номер ycmpoilcmea, err == метх:а, iostat == вид ошибх:и) перемещает файловый указатель в начало файла на диске. Операторы backspace (unit == номер ycmpoilcmea, err == метх:а, iosta t == вид ош ибх:и ) backspace номер ycmpoilcmea перемещают файловый указатель в начало предыдущей записи. Оператор endfile (unit == номер ycmpoilcmea, err == метх:а, iostat == вид ошибх:и ) пишет запись конца файла в файл на диске. 8Так же надо поступать в друrих операторах передачи данных. 
463 Функция eof ( номер ycmpoi1cmBa) возвращает .true., если файловый указатель установлен на запись конца файла или после этой записи; в противном случае eof воз вращает .false. (файловый указатель указывает на х;оне'/.{ фаi1ла в случае пустоrо файла, после чтения последней записи файла или после добавления новой записи в файл). Оператор read (unit == номер ycmpoi1cmBa, fmt == формат, end == Memx;al, err == метх;а2, iostat == вид ошибх;и, rec == номер) сnисох; ввода читает данные из файла. В спецификации fmt формат есть * (см. nодразд. "Ввод/вывод в Фортране" разд. "Стандартныi1 ввoд/вы вод" 2лавы 5), метка оператора формата или форматная строка ВИда '( сnисох; форматов)'. в спецификации end Memx;al есть метка оператора, которому пере дается управление при считывании записи конца файла. В спецификации err метх;а2 есть метка оператора, которому пере дается управление, если при чтении данных возникает ошибка. В спецификации rec номер есть номер записи, которая будет считана из файла прямоrо доступа. Оператор wri te пишет данные в файл. В остальном он подобен опе ратору чтения. К примеру, дадим Фортранпроrрамму Sizeofbook: include 'fgraph.fi' program Sizeofbook implicit попе external Coиnt integer Fi, Ро, Err parameter (Fi == 1, Ро == 2) character*80 Finame, Роnате real*8 Coиnt, Sиmmary !  Statements: саН clearscreen (О) write(6,'(/ /а\)') , Имя файлаисточника ======> ' read (5, '(а)') Finame ореп (Fi, file == Finame, status == 'old', iostat == Err) 
464 if(Err .пе. О) then write (6, '(/lx,a,a)') , Невозможно открыть файл " Finaтe stop , См. имя файла и каталоr.' end if write(6, '(/а \)') , Имя файламишени ======> ' read (5, '(а)') Fonaтe ореп (Ро, file == Роnате, status == 'new') 5иттату == Count (Fi) write (Ро, '(2(/а,а) / /а /a,f9.6 / /а)') + ' Имя файлаисточника  " Finaтe, + ' Имя файламишени ', Роnате, + ' Ответ:', + ' Уч.изд. л. " 5иттату, + ' Все ... ' close (Fi) close (Ро ) end! ео таш real function Count*8 (Р) ! implicit попе integer Р, N /0/ character 5*128 do while (.not. eof(F)) read (Р, '(а)') 5 N == N + lentrim (5) end do Count == dble(N)/40000dO return end! ! ео подсчета с ео Count ! ео program А это Фортранпроrрамма Translator: include 'fgraph.fi' program Translator implicit попе external Dictionary саН clearscreen (О) write (*, *) , Перевод с одноrо языка на друrой.' саН Dictionary 
465 write(*, '(/а)')' end! subroutine Dictionary ! implicit попе character*( *) Оnе, NaтeDic*80, In Word*80 integer N, 1, F parameter (Р == 7, + Оnе == ' ' ) structure / DicStr / character*80 Word, Меаn end structure record / DicStr / StrDic logical Flag саН clearscreen (О) write(*, '(//а /а /а //а\)') + ' fin....rus  Финскорусский словарь,', + ' swe....rus  шведскорусский словарь,', + ' nor....rus  норвежскорусский словарь.', + ' Имя словаря (из 7ми символов: см. выше) ======> ' read (*, '(а)') NaтeDic write (*, '(а\)') , Число пар слов в словаре ======> ' read ( *, *) N с  Ввод словаря и перекачка ero в файл Р: open (unit == Р, Ше == NaтeDic) do 1 == 1, N, 1 write (*, '(lх, i5, а\)') 1, 'e' / / NaтeDic (1: 3)/ /'e слово ======> ' read (*, '(а)') StrDic. Word write(*, '(а\)')' Ero '//NатеDiс(4:6)//'й эквивалент ======>' read (*, '(а)') StrDic.Mean write (Р, '(а)') StrDic. Word, StrDic.Mean end do ! ео ввода словаря write (*, '(lх, а\)') NaтeDic(l : 3) + / /'e слово для перевода ======> ' read(*, '(а)') InWord саН clearscreen (О) write(*, '(а /а/)') Оnе,' Ответ:' Все... ' ео таш ! Поиск слова для перевода: 
466 rewind (F) Flag == .false. do while (.not. Flag) if (eof (F)) then Flag == . true. write (*, '(а)')' Anna anteeksi. Нет TaKoro слова в словаре' + 11 NaтeDic else ! Нет слова read (F, '(а)') StrDic. Word, StrDic.Mean if(In Word .eq. StrDic. Word) then Flag == .true. write (*, '(2х, а, а)') [n Word, StrDic.Mean end if ! ео перевода end if end do ! Слово найдено write(*,'(a)') Оnе close (F) end ! ео Dictionary с ео program Контрольноезание Файл in.txt состоит из трех вещественных чисел: х == 1, у == 2, z == 1O7. Образуйте копию этоrо файла. В конец файлакопии дo бавьте те же числа. Результаты работы выведите на принтер и экран. Ответ program P..filetext; {$N+} { Pascal: } const Nl == #13#10; W == 8; var Х, У, Z, Р, Q, R : extended; F15, F16, F26 : text; begin assign (F15, 'in.txt'); reset (F15); read (F15, Х, У, Z); assign (F16, , out.txt'); rewrite (F16); writeln (F16, Х, У, Z); append (F16); writeln (F16, Х, У, Z); reset (F16); read (F16, Х, У, Z, Р, Q, R); assign (F26, 'prn'); rewrite (F26); writeln (F26, Nl, , Х==', Х: W,' У==', У: W,' Z==', Z: W, 
467 Nl ' P' Р' W ' Q ' Q . W ' R ' R . W) . , , . , , . , , . , writeln (Nl, , Х==', Х: W,' У==', У: W,' Z==', z: W, Nl ' P ' Р' W ' Q ' Q . W ' R ' R . W) . , , . , , . , , . , close (F15); close (F16); close (F26) end. { ео Efiletext } #include <stdio.h> // С++: void main (void) // Cfiletext { double Х, У, Z, Р, Q, R; FILE *F15, *F16, *F26; Р15 == fopen (" in.txt", "rt+"); fscanf(F15, "%lg %lg %lg", &Х, &У, &Z); F16==fopen("out.txt", "at+"); fprintf(F16, "%lg %lg %lg\n", Х, У, Z); fprintf(F16, "%lg %lg %lg\n", Х, У, Z); rewind (F16); fscanf(F16, "%lg %lg %lg %lg %lg %lg", &Х, &У, &Z, &Р, &Q, &R); F26 . fopen("prn", "wt"); fprintf(F26, "\п Х == %6.0Ie У == %6.0Ie Z == %6.0Ie" "\п P==%.Ole Q==%.Ole R==%.Ole\n", Х, У, Z, Р, Q, R); printf("\n Х == %6.0Ie У == %6.0Ie Z == %6.0Ie" "\п Р == %.Ole Q == %.Ole R== %.Ole\n", Х, У, Z, Р, Q, R); fcloseall ( ); } // ео Cfiletext #include <fstream.h> // С++: void main (void) // Cfilefstreaт { double Х, У, Z; ifstream F15; ofstream Р16; Р15.0реп ("in.txt"); Р16.0реп ("out.txt"); Р15 » Х » У » Z; Р16 « Х « "uu" « У « "uu" « Z; cout « '\п' « Х « "uu" « У « "uu" « Z; } // ео Cfilefstreaт program F..filetext ! Fortran: implicit попе real*8, Х, У, Z, Р, Q, R 
468 integer Р15/15/, Р16/16/, Р26/26/ ореп (unit == Р15, Ше == 'in.txt') read (Р15, *) Х, У, Z ореп (unit == Р16, Ше ==' out.txt') write (Р16, *) х, У, Z write (Р16, *) х, У, Z rewind (F16) read (Р16, *) Х, У, Z, Р, Q, R ореп (unit == Р26, file == 'prn') write(F26, 910)' Х==', Х, , У==', У, , Z==', Z, + ' Р==', Р, , Q==', Q,' R==', R 910 format (/3(a,lpd6.0)) wri te ( *, 91 О)' Х == " Х, , У == " У, , Z == " Z, + ' Р==', Р, , Q==', Q,' R==', R close (Р15) close (Р16) close (Р26) end! Упражнения ео F...filetext Решите приведенные ниже задачи обработки файлов. 1. Напишите проrрамму, которая записывает в файл информацию о студентах, проживающих в общежитии: ФИО, номер rруппы, адрес (проспект/улица, дом, корпус, номер комнаты). Выведите список студентов, проживающих в комнате 'Ц'Ц'Ц (остальная часть адреса может различаться). rде пребывает ФИО? 2. Файл содержит сведения о прочности мехов. Самым прочным счи тается мех выдры. Ero прочность принята за 100 %. Данные о друrих мехах: заяц, кролик  5 %, бобер  96 %, нутрия  27 %, куница, co боль  60 %, сурок  10 %, крот  7 %, енот  75 %, белка, рысь  25 %, норка, скунс  70 %, ондатра  37 % и лисица  50 %. OTCOp тируйте файл: . в лексикоrрафическом порядке, . по убыванию прочности мехов. 
469 Какой самый прочный/непрочный мех? З. Свободно конвертируемыми валютами являются доллар (амери канский, синrапурский, новозеландский, австралийский, карибский (Антиrуа и Барбуда, Доминика), джибутийский, канадский), фунт стерлинrов, шиллинr (австрийский), йена, франк (французский, бельrийсколюксембурrский), динар (бахрейнский, кувейтский), ри ал (Саудовской Аравии, оманский, катарский), марка (rерманская), rульден (rолландский), крона (датская), рупия (индонезийская), ринrит (малазийский) и дирхам (ОАЭ). Остальные валюты  orpa ниченно конвертируемые (например, песета испанская, фунт ир ландский, лира (итальянская, турецкая), эскудо портуrальский, крона (шведская, норвежская), марка финская, вон корейский, ...) и неконвертируемые (например, крузейро бразильский, фунт еrипет ский, шекель, рупия (индийская, пакистанская), юань, рубль, rрив на, дирхам марокканский, динар (юrославский, ливийский), ... ). Создайте файл из свободно конвертируемых валют. Отсортируйте ero в лексикоrрафическом порядке: . по названиям стран; . по названиям валют. Какие страны имеют денежной единицей ринrит, вон, туrрик, rрив ну? 4. Файл содержит сведения о числе мясорубок и соковыжималок, co бранных 12ю сборщиками HeKoToporo цеха за рабочую неделю. Ka ждая запись состоит из ФИО, табельноrо номера, числа собранных изделий по дням недели. Выведите результаты трудовой деятель ности бриrады сборщиков. Кто и в какой день достиr наибольшей производительности труда? 5. Файл содержит сведения об ассортименте отдела иrрушек HeKO Toporo супермаркета: название иrрушки, цена, количество, peKOMeH дуемые возрастные rраницы (например, 25  от двух ДО пяти лет). Количество видов иrрушек не превосходит числа n. Выведите: . названия иrрушек, предназначенных детям от k до m лет; . информацию о самой дороrой иrрушке; . названия иrрушек для ребенка от Уl дО У2 лет стоимостью не больше s руб. 6. Файл содержит сведения о месячной зарплате рабочих цехов ХХХ 
470 и УУУ: наименование цеха, ФИО, табельный номер, размер зарпла ты. Вычислите общую сумму выплат за месяц по цеху ХХХ, а TaK же среднемесячный заработок работника этоrо цеха. Выведите Beдo мость начисления зарплаты рабочим цеха УУУ. 7. Файл содержит список некоторых женских имен: старых кален дарных (Аrния, Ада, Александра, Алла, Анастасия, Анна, Анфи са, Екатерина, Ирина, Татьяна), древнерусских нехристианских (Ба жена, rолуба, Добрав а, Ждана, Лада, Любава, Светлана, Тамила, Томила), общеславянских (Болеслава, Бронислава, Вацлава, Слава, Яромира, Ярослава) и новых (Адель, Азалия, Алина, Алиса, Аэли та, Ядвиrа, Яна, Янина). Выведите: . древнерусские имена, начинающиеся с букв [, Д, Ж; . имена, первые буквы которых Я. 8. Файл Денъ а1tzела (а6суст) содержит имена, номера дней и смысл имен: Антон, 16, (rреч.: приобретающий взамен); Борис, 6, (слав.: от Борислав); Валентин, 12, (лат.: сильный); Василий, 15, (rреч.: цap ственный); Илья, 2, (евр.: крепость Божия); Лаврентий, 23, (лат.: увенчанный лаврами); Макар, 7, (rреч.: счастливый); Леонид, 21, (rреч.: подобный льву); Максим, 26, (лат.: великий); Митрофан, 20, (rреч.: сын матери); Прохор, 10, (rреч.: начальник хора); Роман, 1, (лат.: римский); Серафим, 1, (евр.: пламенный); Степан, 15, (rреч.: венец); Тихон, 26, (rреч.: счастье); Анна, 7, (евр.: блаrодать); Мария, 4, (евр.: rоспожа); Нонна, 18, (еrип.: посвященная боrу) и Серафима, 11, (евр.: пламенная). Выведите: . женские имена и их смысл; . имена с днем анrела  1 aBrYCTa; . славянские имена; . rреческие имена. 9. Файл содержит сведения об автолюбителях: ФИО, индекс и номер паспорта, адрес, номер водительскоrо удостоверения, rруппа крови, телефон (дом., раб.), факс, email, http, марка автомобиля, rод BЫ пуска, мощность двиrателя, номерной знак, цвет. Выведите сведения о владельцах "Мерседес Е 320" цвета морской волны. Какой цвет наиболее популярен? 10. Файл содержит сведения об отправлении поездов дальнеrо следо вания с Финляндскоrо вокзала: номер поезда, станция назначения, 
471 время отправления, время в пути, наличие свободных мест. Выведи те информацию о наличии билетов на поезд с номером 'Ц'Ц'Ц. Коrда он отправляется и прибывает в конечный путь назначения? 11. Файл содержит информацию о видеомаrнитофонах, хранящих ся на TOproBOM складе: фирмапроизводитель, страна, марка, стои мость, количество. Выведите информацию о маrнитофонах стои мостью от х руб. до у руб. Маrнитофоны поступают в продажу. Дайте справку о текущем (последнем) состоянии файла. Продукция какой фирмы наиболее популярна? 12. Файл содержит сведения о книrах по вычислительной MaTeMa тике (методам вычислений): ФИО автора, название, УДК, место из дания, издательство, rод издания, число страниц, цена. Какая кни ra самая толстая/тонкая, дороrая/дешевая? Какие книrи выпущены издательством ВНУ (БХВ)? 13. Файл Мосты содержит расписание разводки мостов: Володар ский (2.10  3.45, 4.15  5.45), Финляндский (2.30  5.00), Алек сандра HeBcKoro (2.30  4.55), Императора Петра Великоro (2.00  5.00), Литейный (1.50  4.40), Троицкий (1.50  4.50), ДBOpЦO вый (1.40  3.00, 3.10  4.50), Николаевский (лейтенанта Шмид та) (1.45  4.55), Биржевой (2.10  4.50), Тучков (2.10  3.05, 3.35  4.40), Сампсониевский (2.10  2.45, 3.20  4.25), rренадер ский (2.45  3.45, 4.20  4.50) и Кантемировский (2.45  3.45, 4.20  4.50). Отсортируйте мосты: . по алфавиту; . по увеличению начальноrо времени разводки. 14. Один файл содержит некоторые славянские имена, включенные в церковные календари (Боян, Владислав, Вячеслав, Милютин, Мсти слав, Ростислав, Святослав, Ярослав), а друroй  не разрешавшие ся церковью к употреблению (Боrдан, Болеслав, Боримир, Борислав, Бронислав, Вацлав, Велимир, Витольд, rорислав, Зиrмунд, Кази мир, Любомир, Мечислав, Милан, Милен, Милослав, Радим, Pa домир, Ратмир, Светозар, Светлан, Сиrизмунд, Станислав, Чеслав, Ян). "Слейте" оба файла в один. Отсортируйте имена по алфавиту. Найдите имя средней длины. 15. Файл содержит названия башен Кремля, начиная со Спасской и далее против часовой стрелки: Сенатская, Никольская, Уrловая, 
472 Арсенальная (Собакина), Средняя Арсенальная, Троицкая, KYTa фья, Комендантская, Оружейная, Боровицкая, Водовзводная (Сви блова), Блаrовещенская, Тайницкая, lя Безымянная, 2я Безымян ная, Петровская, Беклемишевская (Москворецкая), Константино Еленинская, Набатная и Царская. Выведите исходный файл и OT сортированный (по алфавиту). Названия каких башен начинается с букв А, С и Ц? 16. Файл содержит сведения о результатах соревнований по пяти борью rруппы из 12ти студентов. Информация о спортсмене вносит ся в виде: ФИО, вид спортаi, баЛЛj (i,j == 1,2,3,4,5). Отсортируйте файл: . по алфавиту; . в соответствии со спортивными успехами студентов. 17. Файл содержит список ФИО 12ти детских писателей и позтов. Семи скаутам предложили назвать трех любимых авторов. Выведи те список авторов в порядке "убывания популярности". Какие изда тельства выпустили в свет их книrи? 18. Файл содержит результаты соревнований 12ти велосипедистов: ФИО, спортивное звание, спортивное общество, вид, длина дистан ции, время. Кто из спортсменов подтвердил звание МС Рф 9 ? Кто впервые выполнил норму МС РФ? 19. Файл содержит сведения о 12ти пациентах поликлиники: ФИО, пол, возраст, адрес (проспект/улица/бульвар/аллея/линия/ переулок, дом, корпус, квартира). Выведите упорядоченные по ал фавиту списки: . мужчин/женщин; . пациентов старше У лет, проживающих на проспекте/улице/ бульваре/ аллее/ линии/ в переулке ХХХ. 20. Файл содержит сведения о рейсах авиакомпании Пулково: HO мер рейса, тип самолета, пункт назначения, время вылета, время посадки, число свободных мест в салоне. Выведите времена вылета самолетов в r. nCK и сведения о наличии свободных мест на рейс в nCK со временем отправления t. 21. Файл содержит сведения об отправлении поездов дальнеrо следо 9МС рф  мастер спорта Российской Федерации. 
473 вания с MOCKoBcKoro (Николаевскоrо) вокзала: номер поезда, CTaH ция назначения, время отправления, время в пути, наличие билетов. Выведите времена отправления поездов в r. nCK в интервале от t 1 ДО t 2 И информацию о наличии билетов на поезд с номером 'Ц'Ц'Ц. 22. Создан файл Товар. Запись состоит из шифра товара, имени TO вара, количества единиц, цены одной единицы (оптовой и рознич ной). Все записи отсортированы в порядке возрастания шифра TOBa ра. Добавьте новые товары, поступившие на склад. Модифицируйте записи о товаре с шифром 'Ц'Ц'Ц  изменение количества, цены еди ницы товара. 23. Файл содержит сведения о ToproBbIx точках вашеrо района (воло сти): название маrазина (Универмаr, Универсам, Супермаркет, Про дукты, Ткани, Меха, Обувь, .. .), адрес, справочный телефон, обще ственный транспорт. Выведите сведения о всех маrазинах Книrа. rде можно купить товар ХХХ и как добраться до соответствующеrо Ma rазина? 24. Файл Телефон:ныi1 сnраво'Ч,1tU'/'i, содержит сведения о 12ти абонен тах: ФИО, адрес, rод установки телефона, номер телефона, наличие льrот. Модифицируйте файл  вводится ФИО; сведения добавля ются / изменяются / удаляются. 25. Файл содержит сведения о нападающих команды СКА (CaHKT Петербурr), участвующей в текущем чемпионате России: ФИО (по алфавиту), возраст, число бросков по воротам, число заброшенных шайб, число rолевых передач, число штрафных минут. Отсортируй те файл по результативности спортсменов. Кто из иrроков больше/ меньше Bcero "заработал" штрафноrо времени? 26. В сборочном цехе трудятся 12 рабочих. Некоторый файл coдep жит сведения о количестве изделий катеrорий А, В и С, собранных рабочими цеха за текущий (последний) месяц. Порция информации состоит из ФИО сборщика, табельноrо номера, названия цеха, числа изделий по катеrориям (собранных рабочим за месяц). Пусть 5 А, 5 в и Sc  расценки за выполненную работу по сборке единицы изде лия катеrорий А, В и С соответственно. Выведите данные: . об общем числе изделий, собранных рабочим ХХХ; . ведомость зарплаты рабочих цеха; . средниЙ размер зарплаты. 
474 27. Файл содержит информацию об ассортименте обуви в бутике Ис na'/icr;;ui1 canOJfCer;;: артикул, наименование, размер, количество, CTO имость одной пары. Артикул начинается с буквы )[( для дамской обуви, М  для мужской и Д  для детской. Выведите сведения: . о наличии и стоимости обуви артикула Х, наименования У и размера z; . ассортиментный список мужской обуви с указанием наимено вания, размера и имеющеrося в наличии числа пар. 28. rруппе из 12ти студентов предлаrается выбрать курс лекций, состоящий из семи дисциплин. Соответствующий файл содержит HO мер rруппы, ФИО студентов, их средние баллы успеваемости и пред лаrаемые дисциплины. Выбираемая дисциплина помечается симво лом У, иначе  N. На прослушивание некоторых дисциплин допус кается не более n человек. Если количество желающих превысит n, то отбираются студенты, имеющие более высокий средний балл успеваемости. Выведите список студентов, желающих прослушать дисциплину ХХХ. 29. Файл содержит сведения о сотрудниках двух отделов HeKoToporo НИИ. В отделах работают по шесть человек. Запись состоит из Ha звания отдела, ФИО, rода рождения, научной степени, должности, стажа работы и оклада. Выведите: . общий список "остепененных" сотрудников (ФИО упорядочены по алфавиту); . минимальный и максимальный оклады в отделе ХХХ; . для отдела УУУ  список сотрудников предпенсионноrо воз раста (на текущий день) с указанием стажа работы. 30. Файл содержит сведения о коллекции книrолюба, состоящей из 12ти книr по живописи, скульптуре и архитектуре: ФИО автора, Ha звание, rод издания, цена, местоположение (номер стеллажа, номер секции). Выведите: . местонахождение книrи ХХХ автора УУУ; . список книr автора zzz; . число книr издания 'Ц'Ц'Ц'Ц roда. 
475 rлава 10 rрафики На экран компьютера можно выводить не только последовательно сти символов (тексты), но и rрафические образы l . Последнее воз можно блаrодаря наличию rрафической системы, состоящей из спе циальных аппаратных и проrраммных средств. К аппаратным cpeд ствам системы относится устройство визуальноrо отображения ин формации (дисплей), а к nр02раммным  rрафические драйверы и библиотека rрафических подпроrрамм. Дисплеи бывают цветные и монохромные, имеют различную раз решающую способность и работают в одном из двух режимов: TeK стовом или rрафическом. Дисплей состоит из двух частей: монито ра, содержащеrо экран (ЭЛТ или жидкокристаллическую панель) с устройствами развертки изображения, и блока управления (дис плейноrо адаптера). В rрафическом режиме экран монитора paCCMa тривается как совокупность близко расположенных точек или, по друrому, пикселов 2 , образующих прямоуroльный растр. Разрешаю щая способность экрана определяется общим количеством пикселов, а также количеством цветов (оттенков), которыми может светиться каждый из них. Разрешение экрана указывается парой чисел (Ha lCM. Ильин Ю. П., Печенкин А. П. Основы проrраммирования на Турбо Пас кале в системе MS DOS.  СПб.: Издво СПбrтУ, 1993. 68 с. 2Pixe! (от анrл. picture e!ement)  элемент или точка растра. В растровой rрафике  минимальная единица изображения, цвет и яркость которой можно задать независимо от остальноrо изображения. 
476 пример, 1024 х 768), первое из которых есть количество пикселов в строке, а второе  количество строк экрана. Каждому пик селу CTa вится в соответствие ero значение. OHOTO и задает цвет (светимость) точки на экране. Светимостью точек можно управлять посредством прикладной проrраммы. Значения пикселов хранятся внекоторой области памяти процессора, называемой вuдеоnамятью. Она COCTO ит из одной или нескольких rрафических страниц. Можно сказать, что страница хранит "карту" экрана. Дuсnлеu1tыu адаптер  устройство управления работой монито ра в текстовом или rрафическом режимах. Выпускаемые в настоя щее время IВМсовместимые компьютеры оснащаются адаптерами, разработанными фирмой IBM, или совместимыми с ними (фирма Hercules). Наиболее часто применяются адаптеры типа VGA (Video Graphics Апау  rрафический видеомассив: 640 х 480, 16 цветов, 1 страница) и супер VGA (8VGA) с разрешением 800 х 600 и более, использующие не менее 256 цветовых оттенков. Разнообразие типов адаптеров и rрафических режимов усложняет задачу управления адаптерами. Для защиты проrраммиста от сложноrо и не всеrда дpy жественноrо оборудования разработаны специальные проrраммы драйверы. Драивер  управляющая проrрамма обеспечения взаимодействия ОС с внешним физическим устройством. Каждому типу устройства сопоставляется свой драйвер. В совокупности они образуют базо вую систему ввода/вывода (BI08), которая хранится в постоянной памяти системноrо блока компьютера (ПЗУ). rрафический драйвер управляет работой дисплейноrо адаптера в rрафическом режиме. Он настраивает rрафические подпроrраммы на взаимодействие с KOH кретным адаптером. В системах проrраммирования Turbo Pascal и Borland С++ каждый rрафический драйвер находится в отдельном Ьgiфайле на диске З . Заrрузка необходимоrо драйвера производит ся автоматически при выполнении прикладной проrраммы посред ством процедуры инициализации rрафическоrо режима initgraph. Ее местонахождение  в библиотеке rрафических подпроrрамм. Бuблuотек;а 2рафu'Ческ;uх nодnрО2рамм  это набор проrрамм и структур данных, предоставляющих проrраммисту самые разно зrрафические драйверы разработаны фирмой Borland International Inc. (bgi  аббревиатура от Borland graphics interface). 
477 образные возможности управления rрафическим экраном. Она co держит средства инициализации rрафической системы и rрафиче cKoro режима, управления цветом, работы с растром пикселов как с двумерной структурой точек, rенерации rрафических примитивов (точек, отрезков прямых, прямоуrольников и некоторых кривых), вывода rрафических текстовых сообщений, доступа к видеопамяти и обработки ошибочных ситуаций. Построение rрафика средствами Паскаля Познакомимся с основными rрафическими средствами библиоте ки graph на примере рисования rрафика функции у = J(x), rдe х = xa(xk)hx. Построение rрафика функции одной пере мен ной на отрезке [Ха; xk] является относительно простой задачей. Решает ее расположенная ниже универсальная Паскальпроrрамма Plot для J(x) = 5(х  2)/х2, rде xa=1.75, xk=6.75, h x =O.25 и hy=O.l (см. раза. "rрафu'К: фУ1i'К:'ЦUU 11 zлавы 3). Она управляет находящейся на втором ypOB не иерархии процедурой, заrоловок которой имеет вид procedure Graphic (ХО, Xk, Нх, Ну : real; Р: Риnс); Именно Graphic строит rрафик функции у = J(x). Ее формальные параметры таковы: О ХО  нижняя rраница Ха отрезка; О Х k  верхняя rраница х k отрезка; О Н х  шаr разметки hx по оси абсцисс; О Н у  шаr разметки hy по оси ординат; О F  имя функции f. Процедура Graphic обращается к находящейся на третьем уровне иерархии функции F со следующим заrоловком: function F (Х : real) : real; Здесь F  фактическое имя некоторой произвольной функции y=J(x). Процедура Graphic содержит в себе внутренние процедуры (без па раметров). Вот их список: О Init  процедура инициализации rрафическоrо режима; О Markax  процедура разметки оси абсцисс; 
478 LJ Findextremum  процедура поиска экстремума функции; LJ Markay  процедура разметки оси ординат; LJ Picture  процедура рисования rрафика. Процедурой Graphic они вызываются в порядке перечисления в спис ке. А это текст проrрамМЫ Plot: program Plot; uses crt, graph; const W == 9; Nl == #13#10; type Риnс == function (Х: real) : real; var ХО, Xk, Нх, Ну: real; { function F (Х : real) : real; begin Р:== 5.0 * (Х  2.0)j(X * Х) end; { {$F+ } } ео F () } { ====== Graphic ====== построение rрафика: } procedure Graphic (ХО, Xk, Нх, Ну: real; Р: Риnс); const Colorborder == darkgray; { цвет окантовки} Background == blue; { цвет окна } Colorgraph == white; { цвет rрафика } Coloraxis == white; { цвет осей } Colorgrid == lightgreen; { цвет сетки } Colorscale == lightgreen; { цвет шкалы } Wscale == 80; { ширина поля для чисел шкалы} Numextremum == 100; { константа в поиске экстремума } PoinCgraph == 300; { количество точек rрафика } Sizefont == 1; { размер шрифта } Px == 9; { число цифр перед дес. точкой } Dx == 2; { число цифр после дес. точки } Py == 9; { ширина поля вывода } {Dy ==2;} var LefCp, Topp, RighCp, ВоСр, Axisx, Axisy, 1, Ндеrо: integer; Х, У, Sup, Inf, Hxo, Hyo: real; Numtostr: string; Nxy, Ng: longint; {  Init  инициализация rрафическоrо режима: } procedure Init; var Gd, Ст, Err: integer; 
479 begin Gd:== detect; initgraph (Gd, Ст, 'с: \tp\bgi'); Err:== graphresult; if Err < > grok then begin writeln (' Graphics error: " grapherrormsg (Err), '.'); writeln (' Program aborted . .. '); halt (1) end; { rраницы окна для rрафика: } Topp:== 25; ВоСр :== getmaxy  Wscale; LefCp:== Wscale; RighCp:== getmaxx  25; setbkcolor (Colorborder); rectangle (О, О, getmaxx 5, getmaxy); { Построение окна: } setcolor (Background); rectangle (LefCp, Topp, RighCp, ВоСр); setfillstyle (solidfill, Background); floodfill (LefCp + 3, Topp + 3, Background); Hzero:== textheight ('О') end; { ео Init } {  м arkax  разметка оси х: } procedure Markax; var Хр, Dx, Xs: real; Xr: integer; begin Hxo:== (RighCp  LefCp)/(Xk XO); if Xk <== О then Axisy:== RighCp else if ХО <== О then Axisy:== LefCp + round (abs (ХО) * Hxo) else Axisy:== LefCp; Nxy:== round ((XkXO) / Нх); Ng :== round ((RighCp  LefCp)/(Hzero + 2)); if Nxy > Ng then 
480 begin Нх:== (XkXO)/ Ng; str (Нх: Px: Dx, Nиmtostr); val (Nиmtostr, Нх, 1) end; Хр :== trunc (ХО / Нх )*Нх; if ХО > о then Хр:== Хр + Нх; Dx :== XpXO; Х :== Хр; Xs:== Dx; settextstyle (defaultfont, vertdir, Sizefoпt); setlinestyle (solidln, О, normwidth); settextjustify (righttext, toptext); setcolor (Colorscale); str (хо: Px : Dx, Nиmtostr); outtextxy (LefCp  (Hzero div 2), ВоСр + 2 * Hzero, Nиmjostr); settextjustify (centertext, toptext); 1:== о; repeat Xr:== LefCp + round (Xs * Hxo); setcolor (Colorgrid); line (Xr, Topp, Xr, ВоСр); str (Х: Px : Dx, Nиmtostr); setcolor ( Colorscale); outtextxy (Xr, ВоСр + 2 * Hzero, Nиmtostr); inc (1); Х:== Хр + 1 * Нх; Xs:==Dx + 1 * Нх until Х  0.0001 *Нх > Xk; settextjustify (lefttext, toptext); str (Xk: Px : Dx, Nиmtostr); outtextxy (RighCp + 2 * Hzero, Botp + 2 * Hzero, Nиmtostr) end; { ео М arkax } {  Markay  разметка оси у: } procedure М аrkлу; var Ур, Ys, Dy, У: real; Yr: integer; begin Hyo:== (ВоСр  Topp)/(Sиp  InJ); if Sup <== О then Axis...x:== Topp else if Inf <== О 
481 then Axis..x :== Topp+ round (Вир * Hyo) else Axis..x:== ВоСр; Nxy :==round((Sup Inf)jHy); Ng :== round ((ВоСр  Topp)j(Hzero + 2)); if Nxy > Ng then begin . Ну :== (Вир  Inf)jN g; str(Hy: Py{: Dy}, Numtostr); val(Numtostr, Ну, 1) end; Ур :==trunc(InfjHy) * Ну; if Inf > О then Ур :== Ур + Ну; Dy :== Ур  Inf; У:== Ур; Ys:== Dy; settextstyle (defaultfont, horizdir, SizeJont); setlinestyle (solidln, о, normwidth); settextjustify (righttext, toptext); setcolor (Color cale); str(Inf: Py{: Dy}, Numtostr); outtextxy (LefCp  Н zero, ВоСр + (Н zero div 2), Numtostr); settextj ustify (righttext, centertext); 1 :== о; repeat Ут :== ВоСр  round (У s * Hyo); setcolor (С о! от grid); line (LefCp, Ут, RighCp, Ут); str(Y: Py{: Dy}, Numtostr); setcolor (Color cale); outtextxy(Left.:p  Hzero, Ут, Numtostr); inc(I); Y:==Yp+I*Hy; Ys:==Dy+I*Hy until У  0.000001 * Ну > Вир; settextjustify (righttext, bottomtext); str(Sup: Py{: Dy}, Numtostr); outtextxy(LefCp  Hzero, Topp  (Hzero div 2), Nuтtostr); { Рисуем оси: } setcolor (Color axis); setlinestyle (solidln, о, thickwidth); line (LefCp, Axis..x, RighCp, Axis..x); line (Axisy, Topp, Axisy, ВоСр) 
482 end; { ео Markay } {  Findextreтит  поиск экстремума: } procedure Findextreтuт; var Н r : real; 1 : integerj begin Hr :== (Xk  XO)/Nuтextreтuт; Вир :== Р(ХО); Inf :== Вир; for 1 :== 1 to Nuтextreтuт do begin X:==Xa+I*Hr; if У > Вир then Вир :== У; end end; { У :== Р(Х); if У < Inf then Inf :== У ео Findextreтит } {  Pictиre  рисование rрафика: } procedure Picture; var Х S, У S, 1: integer; begin setviewport (Left.:p, Topp, RighCp, ВоСр, clipon); Hr :== (Xk  ХО)/ PoinCgraph; for 1 :== а to PoinCgraph do begin Х :== ха + 1 * Hr; Х S:== round ((Х  Ха) * н xo); У :== Р(Х); У S:== round ((Вир  У) * Нуд); putpixel (Х...8, У S, Color graph) end end; { begin Init; М arkay; closegraph end; { ======================================================== ео Graphic } Hr: real; ео Pictиre } м arkax; Picture; Findextreтuтj readln; begin clrscr; writeln (Nl, ' ха, Xk, Их, Иу ======> '); readln(Xa, Xk, Нх, Ну); clrscr; {  Main: } 
483 writeln (Nl, Nl, 'u':12, Трафик функции у :: 5(х  2)/х**2.', N 1, N 1, , Исходные данные:', Nl, Nl,' ХО::', хо: W,' Xk==', Xk: W,' Нх::', Нх : W, Nl, , Ну::', Ну : W); readln; Graphic(XO, Xk, Нх, Ну, Р); writeln (Nl, Nl, , Все. " " Nl) end. { . ео prograт Plot } Поясним кратко эту проrрамму. Средства модуля graph становят ся доступными после ero подключения к Рlоtпроrрамме в разделе uses: uses graph; Обычно после запуска любой прикладной проrраммы экран компью тера находится в текстовом режиме. Для переключения ero в rpa фический режим применяется процедура initgraph. Она распозна ет rрафический адаптер компьютера, заrружает и инициализирует соответствующий rрафический драйвер, переводит адаптер в rрафи ческий режим и передает управление вызывающей проrрамме. Заrо ловок этой процедуры имеет вид procedure initgraph (var драi1вер : integer; var режим: integer; путь: string); rде драi1вер  переменная, определяющая тип rрафическоrо драй вера; режим  переменная, определяющая режим работы rрафиче cKoro адаптера; путь  выражение, задающее маршрут к катало ry, содержащему Ьgiфайл rрафическоrо драйвера. Если в процеду ре initgraph в качестве значения параметра драi1вер использовать предопределенную константу detect, то автоматически выбирает ся необходимый драйвер и устанавливается rрафический режим с наибольшим возможным разрешением. Результаты выбора возвра щаются в виде целочисленных значений переменных драi1вер и pe жим. Поиск необходимоrо Ьgiфайла осуществляется в каталоrе, указанном параметром путь (если он там почемуто не будет най ден, то поиск будет выполняться в текущем каталоrе; коrда путь представляется пустой строкой, то поиск сразу ведется в текущем каталоrе) . Надежность процедуры Graphic поддерживает целочисленная функ 
484 ция graphresult. Она возвращает отрицательное число, если обра щение к какойлибо rрафической процедуре произведено с ошибкой. Если ошибок нет, значением функции будет ноль (предопределен ная константа grok равна О). В нашем случае причиной ошибочноrо обращения к процедуре initgraph может быть неправильное указа ние местоположения файла с драйвером rрафическоrо адаптера. Функция function grapherrormsg ('К:од : integer) : string; выдает текстовое сообщение, соответствующее коду ошибки, возвра щаемоrо функцией graphresult. Подпроrраммы модуля graph позволяют адресоваться к любой точ ке экрана. Для правильноrо указания положения точки (х, у) нуж но знать диапазоны возможных значений ее координат и ориента цию системы координат. Определить максимальные значения KOOp динат, допустимые в данном rрафическом режиме, можно посреk ством функций getmaxx и getmaxy. Текущие значения координат х и у удовлетворяют следующим неравенствам: О  х  getmaxx, О  У  getmaxy. Например, для адаптера VGA в режиме 2 с разрешением 640 х 480 имеем неравенства: О  х  639, О  У  479. Система координат ориентирована так, что точка с координатами (О, О) отображается в левом верхнем уrлу, а точка с координатами (getmaxx, getmaxy)  в правом нижнем уrлу. Центр экрана имеет координаты (getmaxx div 2, getmaxy div 2). Процедура setcolor с заrоловком procedure setcolor (цвет: word); устанавливает основной цвет, которым будет выполняться рисова ние линий, символов и пр., а процедура setbkcolor с заrоловком procedure setbkcolor (цвет: word); устанавливает цвет фона. Цвет можно задать ero номером или име нем соответствующей зарезервированной константы (см. раздел KOH стант процедуры Graphic). Процедура rectangle, заroловок которой имеет вид procedure rectangle (Х лв , Улв, х пн , упн : integer); 
485 вычерчивает прямоуrольник с координатами левоro BepXHero (х лв , улв) и правоrо нижнеrо (x nв , ynв) уrлов, используя текущие цвет и стиль линии. С помощью этой процедуры задаются основное окно вывода и окно для вывода rрафика. Процедура setfillstyle с заrоловком procedure setfillstyle (тип, 'Цвет: word); устанавливает стиль заполнения: тип шаблона заполнителя и ero цвет. Шаблон условно можно представить в виде матрицы размера 8х8 элементов. Каждый элемент имеет значение О или 1. При этом, если точке заполняемой области соответствует элемент матрицы ша блона, равный 1, то она закрашивается цветом с номером 'Цвет, а если О, то точка светится цветом фона. В модуле graph определено 12 типов шаблонов заполнителя: emptyfill, solidfill и т. д. Здесь мы не будем описывать все типы шаблонов (см. [58]). Скажем только, что при использовании шаблона emptyfill окно закрашивается ЦBe том фона, а шаблон solidfill означает  сплошная заливка цветом цвет. Процедура floodfill, имеющая заrоловок procedure floodfill (х, у : integer; бордюр: word); rде х, у  координаты точки замкнутой фиrуры, а бордюр  цвет rраничной линии фиrуры, заполняет фиrуру, используя текущие тип шаблона и цвет заливки. Функция function textheight (стро'К:а : string) : word; возвращает высоту шрифта в пикселах. Мы рассмотрели средства модуля graph, использованные в про цедуре Init. Теперь кратко познакомимся с rрафическими cpeДCTBa ми, нашедшими применение при разметке осей координат. Процеду ры Markax и Markay выводят текстовые строки в rрафическом режиме. Делается это посредством процедуры outtextxy, имеющей заrоловок procedure outtextxy (х, у : integer; стро'К:а: string); Она выводит стро'К:у относительно точки с координатами (х, у). Перед выводом текста нужно выбрать шрифт, размер символов, pac положение текста (rоризонтальное, вертикальное), положение TeK 
486 ста относительно точки с координатами (х, у) (слева, справа, цeH тральное и снизу, сверху или центральное) и цвет символов. Текущий шрифт, расположение выводимоro текста и размер шрифта задает процедура procedure settextstyle (шрифт, направление, размер: word); Здесь шрифт  код (номер) шрифта, направление  код напра вления вывода текста и размер  код размера шрифта. В rрафи ческом режиме используются два вида шрифтов: штриховые (или, по друroму, векторные) шрифты (рекомендуются при выводе текста большими символами) и точечный (матричный) шрифт (peKOMeHДY ется при выводе небольших символов). Для выбора шрифта опре делены специальные константы. Bcero их 11 (см. [58]). К примеру, первая из них, defaultfont, задает точечный шрифт 8х8: это шрифт TeKcToBoro режима, он установлен по умолчанию, ero символы co здаются из матриц 8 х 8 пикселов. Для указания направления вывода текста предназначены константы horizdir (направление вывода  слева направо) и vertdir (напра вление вывода  снизу вверх). Размер шрифта устанавливается параметром размер. Каждый шрифт способен десятикратно изменить свои размеры. Минималь ный размер шрифта (точечноro) равен 1. При таком размере еще отчетливо различаются все ero детали. Процедура settextjustify, имеющая заrоловок procedure sеttехtjustifУ(20ризонталъное выравнивание, верти'/Салъное выравнивание: word); определяет положение текста относительно точки вывода OДHOBpe менно и по rоризонтали, и по вертикали. Для задания расположения выводимоrо текста относительно точки (х, у) имеются следующие константы: О centertext == 1  точка (х, у) в центре текста; О lefttext == О  текст слева от точки; О righttext == 2  текст справа от точки; О bottomtext == О  текст ниже точки; О toptext == 2  текст выше точки. Цвет выводимых символов определяется процедурой setcolor. Весь 
487 последующий вывод текста будет выполняться процедурой outtext ху в соответствии с установленными параметрами, вплоть до изме нения этих параметров. Познакомимся со средствами вычерчивания координатных осей. Ри сование прямых линий производит процедура line. Вот ее заrоловок: procedure line(Xl,Yl,X2,Y2: integer); rде хl, Уl, Х2, У2  координаты точек, которые необходимо соединить отрезком прямой. Толщину линии и ее тип можно установить процедурой setlinestyle, а цвет  процедурой setcolor. Заrоловок процедуры setlinestyle таков: procedure setlinestyle (тип, образе'Ц, толщuна : word); Здесь параметр тип определяет тип линии: CJ solidln == О  сплошная линия; CJ dottedln == 1  точечная линия; CJ centerln == 2  штрихпунктирная линия; CJ dashedln == 3  пунктирная линия; CJ userbitln == 4  узор линии определяет пользователь. Параметр образе'Ц учитывается только для линий типа userbitln. Он задает отрезок прямой длиной в 16 пикселов, который повторя ется по всей длине линии. Параметр толщuна может быть равен normwidth (толщина в один пиксел) или thickwidth (толщина в три пиксела). По умолчанию принимается setlinestyle (solidln, О, normwidth) и setcolor (white), что означает: сплошная белая ли ния нормальной толщины. Процедура Picture рисует rрафик у == Лх). Текущую прямоуrольную область экрана для rрафическоrо вывода (короче, окно или поле вывода) устанавливает процедура setviewport, имеющая заrоловок вида procedure setviewport (х лIl , УЛIl, х пн , Упн : integer; отсе'Ченuе : boolean); Здесь Х лIl , УЛIl, Х пн , Упн  координаты левоrо BepxHero и праВ9rо ниж Hero уrлов окна; отсе'Ченuе  выражение лоrическоrо типа, задаю щее "отсечку" не умещающихся в окне частей изображения. В роли этоrо параметра можно использовать предопределенную константу 
488 clipon (со значением true), означающую "включить отсечку", или константу clipoff (со значением false), означающую "не включать отсечку" . И, наконец, процедура putpixel с заrоловком вида procedure putpixel (х, у : integer; 'Цвет: word); выводит минимальный картинный элемент, пиксел, в позицию экра на с координатами (х, у). Он будет окрашен в заданный 'Цвет. Для завершения работы в rрафическом режиме и перехода в TeKCTO вый режим надо выполнить действия, обратные действиям процеду ры initgraph. Этой цели служит процедура closegraph. Построение rрафика средствами Си При построении rрафика на языке С++ используются та же rрафи ческая библиотека, что в Паскальпроrрамме: // program Plot #include <stdio.h> #include <graphics.h> #include <math.h> #include <process.h> #include <conio.h> const Colorborder == DARKGRAY, Backgroиnd == BLUE, Colorgraph == WHITE, Coloraxis == WHITE, Colorgrid == LIGHTGREEN, Colorscale == LIGHTGREEN, Wscale == 80, Nиmextremиm == 100, PoinCgraph == 300, SizeJont == 1, Clipon == 1; double ХО, Xk, Нх, Ну, Х, У, SиP, Inf, Hxo, Hyo; int LefCp, Topp, RighCp, ВоСр, Axisx, Axisy, 1, Hzero; char Nиmtostr [20]; long Nxy, Ng; // double F (double Х) {return 5. * (Х  2.)/(Х * Х); } // ео F () //  Init ()  инициализация rрафическоrо режима: void Init () { int Gd == DETECT, Ст, Err; 
489 initgraph (&Gd, &Ст, "c:\bc\bgi"); Етт == graphresult ( ); if(ETT!== grOk) { printf(" Graphics error: %s.\n Press any key to ha1t ... \n", grapherrormsg (Етт)); getch ( ); exit (1); } // fраницы окна для rрафика: Topp == 25; ВоСр == getmaxy( )  Wscale; Leftp == Wscale; Rightp == getmaxx( )  25; setbkcolor (Colorborder); rectangle (О, О, getmaxx ()  5, getmaxy ()); //. Построение окна: setcolor (BackgTound); rectangle (Leftp, Topp, Rightp, ВоСр); setfillstyle (SOLID...FILL, BackgTound); floodfill (LefCp + 3, Topp + 3, BackgTound); HzeTO == textheight ("О"); } // ео Init //  MaTkax О  разметка оси х: void М aTkaJ; ( ) { double Хр, Dx, Хв; int Хт; Н xo == double (RighCp  LefCp)/(Xk  ХО); if(Xk <== О) Axisy == Rightp; else if(XO <== О) Axisy == LefCp + int( ceil (fabs (ХО) * Н xo)); else Axisy == LefCp; Nxy ==int(ceil((Xk  ХО)/Нх)); N g == int (ceil (double (RighCp  LefCp)/double (Н zeTO + 2))); if (N xy > N g ) { Н х == (Х k  XO)/double (N g); sprintf(NumtostT, "%9.21f", Нх); sscanf (NumtOstT, "%9.21f", &Нх); } 
490 Хр == ceil(XO/Hx) * Нх; пх == Хр  ХО; Х == Хр; Xs == пх; settextstyle (DEFAULTJ'ONT, VERTDIR, SizeJont); setlinestyle (SOLID..LINE, О, NORMWIDTH); settextjustify(RIGHTTEXT, тор TEXT); setcolor (Color scale); sрriпtf(Nитtоstr, "%9.2If", ХО); outtextxy (LefCp  (Н zero/2), ВоСр + 2 * Н 2ero, Nитtоstr); settextjustify (CENTERTEXT, тор TEXT); 1 == о; do { Xr == LefCp + int (ceil (Х s * Н xo)); setcol6r (С 01 or grid); line (Xr, Topp, Xr, ВоСр); sрriпtf(Nитtо...str, "%9.2If", Х); setcolor (С olor scale); outtextxy (Xr, ВоСр + 2 * Н 2ero, Nитtоstr); 1++; Х == Xp+double(I)*Hx; Xs == Dx+double(I)*Hx; } while (Х  .0001 * Нх <== Xk); settextjustify (LEFT TEXT, тор TEXT); sрriпtf(Nитtоstr, "%9.2If", Xk); outtextxy (Right..p + 2 * Н 2ero, ВоСр + 2 * Н zero, Nитtоstr); } // ео Маrkад //  Markay ( )  разметка оси у: void М arkay ( ) { double Ур, Ys, пу, У; int Yr; Hyo == double (ВоСр  Торр)/(Sир  InJ); if(Sир <== О) Ахisд == Т opp; else if(Inf <== О) AxisJ: == Topp+ int (ceil (Sир * Hyo)); else AxisJ: == ВоСр; Nxy ==iпt(сеil((Sир InJ)/Hy)); N g == int (ceil (double (Bot..p  Topp)/double (Н zero + 2))); if(N ду > N g) 
491 { Ну == (Sup  InJ)fdouble (Ng); sprintf(Nuтtostr, "%9.21e", Ну); sscanf (Nuтtostr, "%9.21e", &Ну); } Ур == ceil (Inf f Ну) * Ну; if(Inf> О) Ур == Ур + Ну; Dy == У р  1 n f; У == У р; У s == Dy; settextstyle (DEFAULTJ'ONT, HORIZDIR, Sizefont); setlinestyle (SOLIDINE, О, NORMWIDTH); settextjustify (RIGHT TEXT, тор TEXT); setcolor (С olor scale); sprintf(Nuтtostr, "%9.21e", InJ); . outtextxy (Left  Н zero, ВоСр + (Н zerof2), Nuтtostr); settextjustify (RIG НТ TEXT, CENTER ТЕХТ); 1 == о; do {Yr== BoCpint(ceil(Ys*Hyo)); setcolor (Color grid); line (LefCp, Yr, RighCp, Yr); sprintf(Nuтtostr, "%9.21e", У); setcolor (Color scale); outtextxy (Left  Н zero, Yr, Nuтtostr); 1++; Y==Yp+double(I)*Hy; Ys==Dy+double(I)*Hy; } while (У  .000001 * Ну <== Sup)j settextjustify (RIGHT TEXT, BOTTOMTEXT); sprintf(Nuтtostr, "%9.21e", Sup); outtextxy (LefCp  Н zero, Topp  (Н erof2), Nuтtostr); f f Рисуем оси: setcolor (Color axiS)j setlinestyle (SOLIDINE, О, THICKWIDTH); line (LefCp, Axisx, RighCp, Axis..x); line (Axisy, Topp, Axisy, ВоСр); } ff ео Markay ff  Findextreтит()  поиск экстремума: void Findextreтuт (double( *Р)( double Х)) { double Hr; int Ij Hr == (Xk  XO)fdouble (Nuтextreтuт); 
492 Sup == Р(ХО); Inf == Sup; for (1 == 1; 1 < Numextremum + 1; 1++) { Х == ХО + double (1) * Hr; У == Р(Х); if(Y > Sup) Sup == У; if(Y < InJ) Inf == У; } } // ео Findextreтит / /  Pictиre ( )  рисование rрафика: void Picture (double( *Р)( double Х)) { int Х S, У S, 1; double Н r; setviewport (Left, Topp, RighCp, ВоСр, Clipon); Hr == (Xk  XO)/double (PoinCgraph); . for(1 == о; 1 < Pointgraph +1; 1++) { Х == ХО+ double(1) * Hr; XS == int (ceil ((Х  ХО) * Hxo)); У == Р(Х); Ys ==int(ceil((Sup У) *Hyo)); putpixel (X, У S, Color graph); } } // ео Pictиre // ====== Graphic ( ) ====== построение rрафика: void Graphic (double( *Р) (double Х)) { Init (); м arka...x (); Findextremum (Р); М arkay ( ); Picture (Р); getch ( ); closegraph ( ); } // ================================================================ ео Graphic void main (void) { clrscr ( ); puts ("\п ХО, Xk, Нх, Ну ======> "); scanf("%lg %lg %lg %lg", &ХО, &Xk, &Нх, &Ну); clrscr ( ); рriпtf("\п\п%12сrрафик функции у == 5(x2)/x2." "\ n \ n Исходные данные:" "\п\п XO==%9.2Ig Xk==%9.2Ig Hx==%9.2Ig" "\п Hy==%9.2Ig\n", 'u', ХО, Xk, Нх, Ну); getch ( ); Graphic (Р); puts ("\п \п Все... \п"); } // ео program Plot 
493 Проrрамма построения rрафика на Фортране здесь не приводится (см. [6]). Упражнение Используя разработанные выше Паскаль и Сиrрафические про rpaMMbI, постройте rрафики функций, перечисленных в упражне ниях разд. "Fрафu'Х: фУ1t'Х:'Цuu" 2лавы 3. В заrоловках Сифункций Graphic, Init, Markax, Findextreтuт, Markay и Picture представь те полные списки формальных параметров. Напишите Фортран проrрамму  аналоr Паскаль и Сиrрафических проrрамм. 
494 rлава 11 Списки Между объектами реальноrо мира, поведение которых описывают проrраммы, существуют разнообразные и непостоянные связи. Одни объекты появляются или исчезают, друrие изменяются. Значит, дaH ные, обрабатываемые компьютером, не всеrда являются простой co вокупностью значений. В зависимости от решаемой задачи элементы данных MorYT быть связаны друr с друrом отношениями, задающи ми порядок следования элементов или характер подчинения одних элементов друrим. Под CmpYKmypOi1 aa'/t'/t'blX будем понимать сами элементы данных и связи между ними. Каждая структура xapaK теризуется еще и набором типовых, базовых операций  операций доступа, включения и удаления элемента. Элемент данных может быть простым ИЛИ сложным. Операция над простым элеме'/tтом BЫ полняется целиком. СЛОJfC'/tыi1 элеме'/tт состоит из нескольких про стых. Вопрос О выборе структуры данных чрезвычайно важен, так как от правильноrо выбора ее зависит эффективность и универсальность проrраммы. Простейшая структура данных  одиночное значение. В проrрамме оно представляется неиндексированной простой пере менной. Доступ к ее значению выполняется по имени. Вектор и Ma трица  также известные нам структуры данных. Вектор  oд нородный линейный массив фиксированноrо размера. Доступ к ero элементам осуществляется посредством индекса  номера позиции 
495 элемента в последовательности. Матрица  вектор, элементы KOTO poro суть векторы. В проrрамме вектор и матрица представляются соответственно одномерным и двумерным массивами. Память под эти структуры данных распределяется статически: при трансляции компилятор по имени объекта, типу и друrим характеристикам BЫ деляет необходимое число байтов. Если заранее неизвестно, каков размер структуры данных, для хранения их используется специальная область памяти  "куча" (heap). Память из "кучи" выделяется динамически. Делают это функции mаllос, саllос, new и др., а освобождают память  free, delete и др!. Динамические объекты чаще Bcero реализуются как связанные структуры данных. Ими MorYT быть лине11:ttъtе cтpY1Cтy pъt  списки, частным случаем которых являются стек (маrазин), очередь, дек, и нелинеilНЪtе стрУ1СтурЪt  тексты, rрафы и деревья. При решении практических задач нередко приходится иметь дело с разнообразными списками, например, списками студентов rруппы, преподавателей кафедры, участников симпозиума, сотрудников OT дела, фирмы и пр. Каждый элемент списка состоит, как правило, из нескольких полей. К примеру элемент списка выпускников Ka федры включает фамилию, имя, отчество студента и средний балл диплома. Назовем СП ис1СО,м совокупность элементов данных, в KOTO рой выделен первый элемент, и каждый элемент, кроме последне ro, имеет одноrо преемника (или каждый элемент, исключая пер вый, имеет одноrо предшественника). В простейшем случае элемент списка  структурная переменная, содержащая указатель на следу ющий (предыдущий) элемент, и произвольное число друrих полей, называемых далее инфор,мационнЪt,ми. Для размещения списка в памяти компьютера используются два способа: последовательное, сплошное представление и связанное, ССЪLЛо'Ч,ное представление. В первом случае элементы списка pac полаrаются последовательно, один за друrим; во втором местопо ложение каждоrо элемента заранее неизвестно  область памяти, которая отводится для размещения элемента, выделяется из "кучи" посредством функций распределения памяти, поэтому все элемен ты содержат, по крайней мере, одно поле  поле связи со следую 1 Здесь мы приводим примеры функций библиотеки СИ (а ниже дадим СИ проrрамму). Подобные средства имеют и Паскаль, и Фортран. 
496 щим (предыдущим) элементом. Связанное представление обеспечи вает более высокую rибкость при работе со списком, чем последова тельное размещение. Оно, в частности, упрощает включение HOBoro элемента в список и удаление ero из списка. Существует несколько разновидностей связанных списков. Если Ka ждый элемент списка содержит указатель на следующий (преды дущий) элемент и имеется указатель на начало (конец) списка, то rоворят об од'Носв.яз'Ном, од'Но'Наnравле'Н'Ном сnиске. Например, он MO жет быть таким [24]: typedef struct{ char Author[64], Title[64], Publisher[32] ; unsigned Year; } Book; / / автор книrи / / название книrи / / издательство / / rод издания книrи struct List { struct List* Next; Book Info; }; / / указатель на следующий элемент // информационные поля Информационное поле представляет собой структурную переменную по шаблону Book. Равенство NULL поля Next  признак последне ro элемента списка. При реализации списка необходимо объявлять указатель, хранящий начало списка: struct List* Head; Сначала список пуст, поэтому Head == NULLj. Частным случаем односвязноrо списка является коль'ЦевоiL, 'Цuклu 'Ч,ескuiL сnисок. В нем последний элемент содержит поле связи с пер вым элементом. Д вусв.яз'НыiL, дву'Наnравле'Н'НыiL сп исок позволяет выполнять "движе ние" от элемента к элементу в обоих направлениях. Элемент TaKoro списка содержит два указателя  на предыдущий (Previous) и сле дующий (Next) элемент списка. Теперь реализация списка требует объявления двух указателей  20ловы (Head) и хвоста (Tail) спис ка. Элемент двусвязноrо списка может быть таким [24]: struct Dlist { struct Dlist* Next; / / указатель на следующий 
497 Book Info; struct Dlist* Previous; / / элемент // информационные поля / / указатель на предыдущий // элемент }; struct Dlist* Head; // указатель на первый элемент struct Dlist* Tail; // указатель на последний элемент Признаком первоrо элемента списка является равенство NULL YKa зателя Previous, а признак последнеrо элемента  N ext равно зна чению NULL. В работе со списками можно выполнять следующие операции [31]: CJ получить доступ к kMY элементу списка для анализа и/или из менения содержимоrо ero полей; CJ добавить новый элемент непосредственно перед kM элементом; CJ удалить kй элемент списка; CJ объединить два (или более) списка в один список; CJ разбить список на два (или более) списка; CJ скопировать список; CJ подсчитать число элементов в списке; CJ отсортировать список по значению HeKoToporo поля; CJ найти в списке элемент с заданным значением HeKoToporo поля и т. Д. Сте1С  это список, в котором все включения и исключения эле ментов производятся только с одноrо конца, называемоrо вершиной сте1Са. Коrда новый элемент помещается в стек, то элемент, ранее находившийся на вершине стека, становится временно недоступным. Аналоrом стека может быть стопка книr 2 : взять можно только Bepx нюю книrу в стопке и положить новую  только сверху. Механизм функционирования стека отражен в друroм ero названии  список типа LIFO (Last in, first out, что означает: "Последним пришел, пер вым вышел"). Базовыми операциями для стека являются: PushO  2или трубка с запаянным концом (ствол), в которую закатывают шарики; извлечь их можно только в обратном порядке: тот шарик, который закатился последним, будет извлечен первым. 
498 добавить новый элемент в стек, РорО .....,..... извлечь элемент из верши ны стека и PeekO  взять элемент из вершины, не извлекая ero. Наиболее простая реализация стека  в виде односвязноro списка элементов. В отличие от стека о'Чередь  структура данных, в которой эле менты добавляются всеrда с одноro края, называемоrо 1\:О'Н'ЦО.м, xвo сто.м очереди, а удаляются с друrоro  'На'Чала, 20ловъt очереди. Эта структура данных реализует дисциплину FIFO (First in, first out, т. е. "Первым пришел, первым ушел"). Базовыми операциями в работе с очередью являются PutO  поместить элемент в очередь и GetO  удалить элемент из очереди. Очередь обычно строят в виде односвязноrо списка. Де1\:  список, в котором добавление и удаление элементов ВЫПОk няется с любоrо края. Следовательно, дек есть обобщение очереди (ero название образовано из первых букв анrлийских слов double ended queue: двусторонняя очередь). Базовые операции в работе с деком  включение элемента в начало или конец списка, удаление элемента из начала или конца списка. Те1\:ст  нелинейная структура данных, элементы которой предста вляют собой записи с тремя полями: первое поле содержит TeKCTO вую информацию (например, слово), второе  указывает на первый элемент следующей строки или имеет значение NULL, а третье  содержит указатель на следующий элемент данной строки. rрафы и деревь-я здесь не рассматриваются (см. [2, 13, 15, 32, 18, 22, 25, 31, 38, 41, 47, 51]). в качестве примера реализации списка и динамическоrо распреде ления памяти приведем проrрамму Од'Носв-яз'Нъtu сnиСО1\:. Она обра батывает произвольное число описаний книr. Элемент списка имеет структуру List (см. выше). Информационные поля структурной пе ременной Wo/k по шаблону Book заполняются с клавиатуры. Прием полей в переменную Wo/k производит функция InpuCbook(). Чте ние данных завершается после ввода 1\:о'Н'Ца фаuла (одновременное нажатие клавиш (Ctrl) + (z), а затем  клавиши (Enter)) в ответ на под сказку ввести имя автора книrи. После этоrо InpuCbook( ) воз вращает значение EOinput. При вводе очередной структурной пере менной выясняется, есть ли в существующем списке элемент с Te ми же полями. Эта проверка защищает от дублирования описаний 
499 книr. Если совпадение элементов не обнаружено, под новый элемент списка резервируется память, и этот элемент включается в список. Проrрамма формирует список, размещая элементы в лексикоrра фическом порядке по полю Info.Aиthor. После окончания ввода на экран выводится весь список. Затем выполняется цикл выборочноrо удаления элементов, начиная с первоrо. Коrда же структура данных будет полностью обработана, на экран выводится весь список из He удаленных элементов. Приведем текст проrраммы [24]: // program Од1iосв-ЯЗ1iыi1 сnисох; #include <stdio.h> #include <string.h> #include <conio.h> #include <alloc.h> const unsigned Lenaиthor == 64, Lentitle == 64, Lenpиblisher == 32, EOinpиt == 255, Like == 1; typedef struct{ char Aиthor[Lenaиthor], Title[Lentitle], Pиblisher[ Lenpиblisher]; unsigned Year; } Book; struct List{ struct List* Next; Book Info; }; char* Prompt[] == {"Автор или (Ctrl) + (z): ", "Название: ", "Издательство: ", "rод издания: " }; //  InpиCbook ()  ввод переменной типа Book: unsigned InpиCbook (Book* Ptr) { clrscr (); fputs (Prompt[O], stdout); fНush (stdin); fgets (ptr > Aиthor, Lenaиthor  1, stdin); if(feof(stdin)) return EOinpиt; if(Ptr > Aиthor[strlen(Ptr > Aиthor)l] ==== '\п') Ptr > Aиthor[strlen (Ptr > Aиthor)  1] == '\0'; fputs (Prompt[l], stdout); fНush (stdin); fgets (Ptr > Title, Lentitle  1, stdin); if(Ptr > Title[strlen(Ptr > Title)l] ==== '\п') Ptr > Title[strlen (Ptr > Title)  1] == '\0'; fputs (Prompt[2], stdout); fНush (stdin); fgets (Ptr  > Pиblisher, Lenpиblisher  1, stdin); 
500 if(Ptr > Publisher[strlen (Ptr > Publisher)  1] ==== '\п') Ptr > Publisher[strlen (Ptr > Publisher)  1] == '\0'; fputs (Рrоmрt[З], stdout); fНush (stdin); scanf("%u", &(Ptr > Уеат)); return о; } / / ео Inputbook //  Outputbook ()  вывод описания книrи. Воз / /  вращает указатель на следующий элемент списка: struct List* OutpuCbook (struct List* Ptr) { puts (Ptr > Info.Author); puts (Ptr > Info. Title); puts (Ptr > Info.Publisher); printf("%u\n \п", Ptr > Info. Уеат); return (Ptr > Next); } / / ео List* OutpuCbook //  Screen()  вывод всех элементов списка. Воз //  вращает указатель на последний элемент списка: struct List* Screen (struct List* Head) { struct List* Ret; if(Head ==== NULL) { puts (" Список пуст. \п"); return NULL; } do { OutpuCbook(Head); Ret == Head; Head == Head > Next; } while (Head !== NULL); return (Ret); } // ео List* Screen //  Ртее ()  освобождение памяти, //  выделенной для элемента списка: void Ртее (struct List* Element) { free (Element); } // ео Ртее //  Haselement ()  проверка наличия / /  в списке идентичноrо элемента: unsigned Haselement (struct List* Head, Book* Work) { while (Head !== NULL) { if(!strnicmp (Head > Info.Author, Work > Author, strlen(Work > Author)) && !strnicmp (Head > Info. Title, Work > ТШе, strlen (Work > Title)) && 
501 !strnicmp (Head > Info.Pиblisher, Work > Pиblisher, strlen ( W ork  > Pиblisher)) && Work > Year)) return Like; (Head > Info. Year ==== Head == Head > Next; } return о; } // ео Haseleтent //  Add ()  помещает элемент Newptr в список //  Head в алфавитном порядке фамилий авторов: unsigned Add (struct List** Head, struct List* Newptr) { struct List* First; struct List* Second; if((*Head) ==== NULL) { (*Head) == Newptr; return о; } if((*Head) > Next ==== NULL) { if(strcmp ((*Head) > Info.Aиthor, Newptr > Info.Aиthor) > о) { // Новый элемент становится первым: Second == (*Head); (*Head) == Newptr; Newptr > Next == Second; Second > Next == NULL; } else { / / Новый элемент становится вторым: (*Head) > Next == Newptr; Newptr > Next == NULL; } return 1; } else { if(strcmp ((*Head) > Info.Aиthor, Newptr > Info.Aиthor) > о) { // Новый элемент становится первым: Second == (*Head); (*Head) == Newptr; Newptr > Next == Second; return 2; } First == (*Head); Newptr > Next == NULL; Second == First > Next; / / Поиск места в списке: while (First > Next !== NULL) 
502 { if(strcmp (First > Info.Aиthor, Newptr > Info.Aиthor) <== О && strcmp (Second>Info.Aиthor, Newptr>Info.Aиthor) >== О) // Элемент между First и Second Newptr > Next == Second; { First > Next == Newptr; return 3; } First == Second; Second == First > Next; } // Не было возврата  элемент в конец списка: First > Next == Newptr; Newptr > Next == NULL; return 4; } } // ео Add / /  Delete ( )  удаление элемента из списка Н ead; void Delete (struct List** Head, struct List* Element) { struct List * Previoиs; if(*Head ==== NULL) return; if (( * н ead) == == Element) { (*Head) == Element > Next; return; } Previoиs == (*Head); while ((Previoиs > Next) !== Element) Previoиs == Previoиs > Next; Previoиs > Next == Element > Next; Ртее (Element); return; } // // Список пуст? // Удаляемый элемент первый? Ртее (Element); / / Поиск предыдущеrо для Element элемента: ео Delete unsigned main (void) { char Ch; struct List* Head; struct List* Newptr; Head == NULL; //  Main  / / Указатель на начало списка struct List* Cиrrent; Book Work; // Сначала список пуст / / Ввод элементов списка с клавиатуры: while (InpиCbook (& Work) !== EOinpиt) { if (Haselement (Head, & W ork) !== Like) { if (( Newptr == (struct List* )mаllос (sizeof(struct List))) ==== NULL) 
504 Упражнения Решите приведенные ниже задачи, используя списковые структуры (см. [41, 13,24, 32])3. 1. Из вещ чисел 8.12, 4.12, 3.62, 3.17, 2.87, 1.82, 1.49, 1.42, 1.37, 1.17, 0.37, 0.22 образуйте список. Проинвертируйте ero. Найдите серединныЙ элемент списка. 2. Из строки В православном календаре День влюблённых (Петра и Февронии)  8 июля сформируйте список. Замените в нем число 8 прилаrательным восьмое. 3. Из строки Каждый человек рождается садовником сформируйте список. Исключите из Hero первый элемент. 4. Из строк Мир построен на силе чисел (Пифаrор) и Всё есть чис ло (Эйлер) образуйте списки. В каком списке меньше элементов? 5. Из месяцев rода Древнерусскоrо календаря Сечень, Лютый, Берёзозол, Цветень, Травень, Червень, Липец, Серпень, Вересень, Листопад, Трудень, Студень составьте кольцеобразную структуру. Дайте современные названия месяцев. 6. Из скороrоворки Корабли лавировали, лавировали, да не вылави ров али сформируйте список. Замените в нем элемент с отрицанием не союзом и. 7. Из скороrоворки Встретил в чаще ёж ежа:  Как поrода, ёж?  Свежа. И пошли домой, дрожа, сrорбясь, съёжась, два ежа COCTaBЬ те список. Подсчитайте в нем число цепочек ёж и ежа. 8. Из скороrоворки Сшит колпак не поколпаковски. Надо колпак переколпаковать, да перевыколпаковать составьте список. Подсчи тайте, сколько раз в нем встречается цепочка символов колпак. 9. Из скороrоворки Кукушка кукушонку купила капюшон. Как же в капюшоне кукушоночек смешон составьте список. Удалите из Hero элементы, содержащие цепочку символов капюшон. 10. Из скороrоворки Карл у Клары украл кораллы, а Клара у Kap ла украла кларнет получите список. Используя ero, сформируйте ЗА также: Данные в языках проrраммирования.  М.: Мир, 1982.  328с.; Замулин А. В. Типы данных в языках проrраммирования и базах данных. Новосибирск: Наука, 1987.  150 с. 
505 частотный словарь. 11. Из скороrоворки На дворе трава, на траве дрова. Не руби дрова на траве двора образуйте список. Разбейте ero на два списка. 12. Из скороrоворки Чем чаще чистишь, тем чашки чище составьте список. Поменяйте в нем местами части предложения. 13. Из скороrоворки У Прошки с плошкой вышла оплошка  плош ку Прошка перевернул составьте список. Найдите в нем самый длинный элемент. 14. Из скороrоворки Расскажика, буква Ё, как твоё житьё бытьё? Буква Ё даёт отчёт: Ничеrо житьё, течёт составьте список. К элементу, заканчивающемуся соrласной буквой, припишите спра ва букву ъ. 15. Из скороrоворки Топали да топали, дотопали до тополя. ДО TO поля дотопали, да ноrито оттопали составьте список. Подсчитайте в нем количество предлоrов. 16. Из скороrоворки rалдят rрачата на rалчат. rлядят rалчата на rрачат составьте список. Поменяйте в нем элементы rрачата и rал чата, rалчат и rрачат. 17. Из строки полифония полиrлот полиrамия полисемия поливита мины полиrон полиrрафия поликлиника полиэтилен полиспаст по лис сформируйте список. Последний ero элемент переставьте в ce редину списка. Проверьте упорядоченность HOBoro списка. 18. Из строки экстракт экскурс экслибрис эксцесс экспозиция экс перт экспорт экспресс экстаз экстерьер сформируйте список. В Ka ждом ero элементе удалите приставку экс. Первый элемент пере ставьте в конец списка. Проверьте упорядоченность HOBoro списка. 19. Из строки телефоноrрамма телеrраф телекамера телемеханика телетайп телефон телевидение телефакс телескоп телеобъектив Te леметрия сформируйте список. "Сожмите" ero, удалив из каждоrо элемента приставку теле. Первый и последний элементы списка по меняйте местами. Проверьте упорядоченность HOBoro списка. 20. Элемент списка содержит фамилию и инициалы автора, назва ние книrи, количество экземпляров книrи, имеющихся в наличии (например, lй элемент списка: Михайлов А. С. Воспитание щенка. 10; 2й элемент: Туртенев И. С. Муму, 20 и т. д.). Список записан в 
506 алфавитном порядке авторов. Отсортируйте список по невозраста нию количества экземпляров. 21. Элемент списка содержит фамилию и инициалы вкладчика, HO мер счета, сумму вклада в рублях (к примеру, lй элемент списка: Чук А. Б. 314159 300; 2й элемент: reK Е. Т. 271828 150 и т. д.). OT сортируйте список по неубыванию сумм вкладов. 22. Из строки А6руццкие Апеннины Аппалачи Арденны Бонн Брюс сель Валлетта Ватерлоо Веллинrтон Венсенн Виннипеr raara rалле rеттинrен rурджаани Дарданеллы Дюссельдорф Ессентуки Иссык Куль Калькутта Канн Кардифф Лозанна Лондондерри Таллин сформируйте список. Подсчитайте в нем частоту появления CДBO енных символов. 23. Из строк католик кекс крекер KpeCTHaKpeCT и каракатица Kap 6ункул кикимора ксёндз сформируйте два упорядоченных списка. "Слейте" их в один упорядоченный список. 24. Из строки А тап, а р1ап, а сапа1  Рапата или Madam! 1 ' т Adam сформируйте список. Получите из Hero новый список, выполнив ци клическую перестановку символов в словах. Сравните оба списка (иrнорируйте знаки пунктуации). 25. Внесите в список информацию о студентах (ФИО, оценки), экза меновавшихся по пяти предметам. Исключите из Hero элементы, OT носящиеся к студентам, у которых оценки неуд и удовл. Какой про цент от общеrо числа студентов они составляют? 26. rруппа из 12ти студентов экзаменовалась по пяти ДИСЦИплинам. Приведите проrрамму, которая данные о студентах (ФИО, результа ты) заносит в список. Исключите из Hero элементы, относящиеся к студентам, у которых одна оценка удовл, а остальные  хор и отл. 27. Для rруппы из 12ти студентов известн:ы результаты последней сессии (по пяти предметам). Приведите проrрамму, которая данные о студентах (ФИО, оценки) заносит в список. Исключите из Hero эле менты, относящиеся к студентам, у которых: . средний балл больше 4; . все оценки 5. 28. В rруппе 12 студентов. Приведите проrрамму, которая данные о студентах (ФИО, оценки последней сессии) вносит в список. Исклю 
507 чите из Hero элементы, относящиеся к студентам, у которых: . средний балл меньше 4.5; . оценка, полученная на третьем экзамене, 5. 29. В rруппе 12 студентов. Напишите проrрамму, которая данные о каждом студенте (ФИО, оценки последней сессии) заносит в список. Исключите из Hero элементы, относящиеся к студентам, у которых: . средний балл меньше среднеrо балла rруппы; . нет удовл и неуд оценок. 30. Студенты, вставшие в Kpyr, пронумерованы числами 1, 2, ..., n, считая против часовой стрелки. Затем, начиная с первоrо, против часовой стрелки отсчитывается kый студент (поскольку студенты стоят по Kpyry, то при счете за nЫM следует первый). Этот kый покидает Kpyr, после чеrо, начиная со следующеrо, снова отсчитыва ется kый студент, и так до тех пор, пока не останется один студент. Определите ero ФИО и номер. 31. Выведите в обратном порядке элементы вещ последовательности до элемента, номер KOToporo равен значению серединноrо элемента друrой, целочисленной последовательности. 32. Вводные данные представляют собой последовательность цел чисел, состоящую из нескольких подпоследовательностей, каждая из которых заканчивается нулем (нуль не принадлежит подпосле довательности). Сформируйте новую последовательность, в которой сохранен порядок следования подпоследовательностей, но внутри каждой подпоследовательности числа следуют в обратном порядке (пример ввода: 1 1039 О 762 О 4 58 12 11 13 о; пример вывода: 93 10 1 026 7 О 13 11 128 5 4 о). 33. Множества А и В представлены списками. Постройте множество С такое, что: . с == А U В; . с == А n В; . с == А \ В. 34. Разреженные матрицы А и В представлены списками. Получите матрицу С, равную: . С == А:I: В; . С == АВ; . С == А Т . 
12 Декларативная часть 13 Исполняемая часть 14 Подпроrрамма Часть 111 Приемы кодирования и отладки проrрамм 
511 rлава 12 Декларативная часть Цель этой части  дать общие сведения о стиле кодирования и He которых приемах исключения ошибок из проrрамм. Проrрамма написана. Теперь ее нужно заставить работать, тестиро вать, а затем, коrда она даст верные результаты, оценить. Мы xopo шо знаем, что означает понятие "математическая культура". Точно также можно rоворить о "проrраммистской культуре", лежащей в основе стиля проrраммирования. Выбор алrоритма Зададимся вопросом: какой алrоритм лучше  наrлядный или эф фективный (быстрый, короткий), точный, надежный или универ сальный? Постановка вопроса в такой форме не совсем корректна. Построить или выбрать алrоритм, обладающий всеми перечислен ными достоинствами одновременно, практически невозможно, ибо, например, требование эффективности наносит ущерб леrкочитаемо сти, требование надежности усиливает сложность алrоритма, Tpe бование универсальности может привести к увеличению объема ис пользуемой памяти, платой за повышение точности расчетов будет увеличение расходов времени исполнения и занятой памяти компью тера. Методика проrраммирования строится на здравом смысле. Нужно поступать так, как решают в математике задачи оптимизации: най 
512 ти экстремум по одной, двум переменным, наложив оrраничения на остальные. Все станет на свое место, если взять во внимание цe левое назначение алrоритма (алrоритм коррекции траектории спут ника требует прежде Bcero высокой скорости исполнения и точно сти; алrоритм из пакета прикладных математических проrрамм  скорости и, часто, повышенной точности; учебная проrрамма  Ha rлядности, ясности и т. д.). rлавная черта культуры проrраммиро вания как раз и состоит в умении подчинить все компоненты про екта определенному функциональному назначению. Бесспорно, что MHoroKpaTHo используемые проrраммы (алrоритмы MaccoBoro при менения) должны быть прежде Bcero эффективными, причем часто время исполнения  более важный фактор, чем объем выделенной под проrрамму памяти. С друrой стороны, проrраммыоднодневки, предназначенные для вспомоrательных, оценочных расчетов, можно писать просто, без особых затрат личноrо времени и сил, не пользу ясь какимилибо "хитроумными" приемами с целью экономии про странства и времени!. Так как проrрамма есть выражение решения некоторой проблемы в терминах языка проrраммирования, то необходимым (но не ДOCTa точным) условием получения хорошей проrраммы является нали чие качественноrо проекта. Здесь действует простое правило: раз рабатывайте, ищите и используйте хорошие алrоритмы и COOTBeT ствующие структуры данных. Это первая заповедь в культуре про rраммирования (наблюдая попытки выполнить "на отлично" коди рование плохоrо алrоритма, можно и пошутить: "Красиво жить не запретишь"; эти попытки похожи на деяния портноrо, пытающеrо-- ся с помощью rалунов и пуrовиц исправить плохо сшитый костюм; дайте ответ на вопрос: "Отчеrо у вас находится время на переделку проrраммы, но часто не хватает ero на создание хотя бы удовлетво рительноrо проекта?"). Большое число алrоритмов собрано в книrах [1, 2, 3, 8, 9, 13, 14, 15, 18, 19, 21, 26, 31, 32, 35, 37, 41, 45, 51, 53, 57, 60, 63, 64] и журна лах по проrраммированию. Правда, там они представлены так, что требуется адаптация их к конкретному языку проrраммирования. 1 Нельзя ракетами стрелять по воробьям; никому не придет в rолову отпра виться в деловую поездку из С.Петербурrа в Москву на велосипеде, но и в Трубников Бор Ил96 не летает. 
513 Выбор имен и констант Проrрамма может получиться лучше или хуже в зависимости от Toro, насколько ее автору известны приемы кодирования 2 . Это xa рактеризует вторую черту культуры проrраммирования. Определим стиль кодирования как стиль мышления, проявляющийся в умении отображать алrоритм решения задачи и структуры данных на KOH I кретный язык проrраммирования. Важным элементом стиля является продуманный подбор имен. "Что значит имя? Роза пахнет розой, хоть розой назови ее, хоть нет." (У. Шекспир, "Ромео и Джульетта", акт II, сцена 2.) Верно, но в проrраммировании важно, чтобы имя объекта отражало ero смысл и роль в общем плане решения задачи (каждое имя должно быть мнемоническим). При выборе имен пользуйтесь правилом М. Джек сона [12]: 1. В аббревиатуру включайте начальные буквы слова, так как "начало слова важнее ero конца". 2. "Соrласные важнее rласных". Избеrайте близких по написанию имен (к примеру, ха и х о). Cxo жие имена должны различаться первыми символами (Ikey, Jkey лучше, чем J(eyi, J(eyj). Цифры пишите в конце имени. Для цe лочисленных данных выбирайте имена, начинающиеся с букв 1, J, J(, L, М или N; дЛЯ комплексных  с буквы С (или с аббревиа туры Cmplx  такая приставка будет напоминать, что переменная комплексная). Имена внутренних подпроrрамм также MorYT иметь приставку  имя окаймляющей подпроrраммы. В качестве имен ис пользуйте анrлийские слова или их сокращения. Помните о возмож ном нежелательном эффекте неявных объявлений в Фортране. Опе ратор implicit попе  надежное средство защиты от Hero. Списки имен в одном объявлении можно упорядочить по алфавиту и объ единить в столбцы, что облеrчит возможный поиск имен в больших списках. Длинные имена уместны для редко используемых перемен ных, в то время как переменные, обращение к которым происходит часто (например, индексы), должны иметь короткие имена. Даже метки MorYT облеrчать или затруднять чтение проrрамм. Их лучше 20 ни не обязательны для исполнения ("Коряво жить не запретишь"), но их применяют опытные проrраммисты. 
514 размещать в порядке возрастания с шаrом 10 в значениях номеров, причем в rлавной проrрамме метками MorYT быть числа 10, 20, ..., в подпроrраммах  1010, 1020, . . ., 2010, 2020, .. . , 3010, 3020, ... и т. д. В Паскале и Си метками должны быть мнемонические имена. Математическим, физическим, химическим и пр. константам, пре дельным значениям счетчиков, размерам коллекций данных и т. п. давайте содержательные имена и присваивайте им значения в дe кларативной части проrраммной единицы (в исполняемой части не должно быть "маrических чисел"). Фраrменты объявлений пишите с отступами, причем каждое предложение  с новой строчки. Сказан ное позволяет создавать удобочитаемые и леrко модифицируемые проrраммы. Стиль  это не I1pOCTO набор правил, это  прежде Bcero выражение опыта общения,. это  подход, позиция. Наиболее распространенными ошибками при записи объявлений являются ошибки пунктуации (замена в разделе определения KOH стант знака == знаком :==, а в разделе определения типов  знака == знаком :), ошибки в выборе типов данных (рабочим типом данных в Паскале должен быть тип extended, а в Си и Фортране  double; индексы объявляйте типом word (Паскаль) и unsigned (Си)) и т. д. 
515 rлава 13 Исполняемая часть Культура проrраммирования предполаrает не только знание языка проrраммирования, но и умелое владение им. Рассмотрим приемы кодирования цепочек, ветвлений и повторений. Выражение ВыраЭfCение  неотъемлемая часть алrоритма. К кодированию Ta кой простой части С.]1едует относиться с должным вниманием и aK куратностью. Размещайте в выражении пробелы везде, rде это при водит к ясной проrрамме. Пишите "лишние" скобки (ничто не CTO ит так дешево, как скобки). Ставьте их в сомнительных случаях (например, во избежание неоднозначности в порядке выполнения операций). Это делает проrрамму леrкочитаемой и предотвращает возможные ошибки (слова "описка" в лексиконе проrраммистов нет; простая и тяжелая ошибки портят результаты работы в равной мере, но простую ошибку труднее локализовать; пример простой ошиб ки  вместо А * В набрано А + В и ошибочные тестовые данные А == В == 2). Избеr айте вычи тани я близких величин (к примеру, формулу 106 ( V х 2 + х + 1  v х 2 + х  1) для больших значений х кодируйте в виде 2e6j(sqrt((X + 1.0) * Х + 1.0) +sqrt((X + 1.0) * Х  1.0))). 
516 Нахождение суммы последовательности начинайте со сложения меньших по модулю чисел. Избеrайте деления больших по модулю чисел на малые по модулю числа, особенно коrда последние имеют невысокую точность. Не забывайте, что при делении целочисленных данных в Си и Фортране дробная часть результата отсекается. Знай те, что арифметические операции полиморфны (т. е., например, знак + в выражении М + N, rде М и N  цел переменные, rенерирует несколько иные машинные коды, чем знак + в выражении А + В, rде А и В типа вещ; операции + и  над вещ данными сопрово ждаются выравниванием порядков операндов, что может привести к потере значащих цифр; см. nодразд. "Вещественное 'Число" разд. "[(онстанта" и разд. "Оператор nрисваивани.я" 2лавыl 5). Помните, что законы ассоциативности и дистрибутивности в компьютерной арифметике не работают (например, в общем случае (А + В) + с i- А + (В + С), А * В + А * С i- А * (В + С)). в одном выражении не употребляйте (по возможности) данные раз ных типов, так как разнотипность  источник трудно обнаружива емых ошибок и, кроме Toro, "смешанная арифметика" требует, как правило, больших затрат времени и памяти. Не надейтесь, что ваш компилятор "читает" выражение 2 * А, rде А  вещ переменная, как 2.0*А. А если уж смешиваете в одном выражении разнотипные данные, то делайте это разумно (к примеру, формулу а 1О кодируйте в виде А * *10 (Фортран), так как при вычислении значения А * *10. MorYT потребоваться лоraрифм и экспонента; формулу ХО + (i  l)h пишите в виде ХО + double(I  1) * Н (Си) и т. д.). Экономьте время, сокращая количество операций, для чеrо, BO первых, делайте тождественные преобразования и, BOBTOpЫX, ис пользуйте более быстрые операции. В современных вычислитель ных системах относительные затраты на выполнение арифметиче ских операций примерно таковы: присваивание цел чисел  1, сло жение (вычитание) цел чисел  1.5, присваивание вещ чисел  2, сложение (вычитание) вещ чисел  З, умножение цел чисел  5, преобразование цел числа в вещ  6, умножение вещ чисел  8, деление  ЗО, возведение в цел степень  40, возведение в вещ степень  120, вызов арифметических функций (sqrt, sin и т. д.)  150. Стало быть, вместо 2.0 * А пишите А + А (но не делайте бес смысленных замен вида 2.0 * A[I, J] на A[I, J] + A[I, J] изза ДОПОk 
517 нительных затрат времени, необходимоrо для доступа к элементам массива), вместо А/10.0  А * 0.1, вместо А ** 2  А * А и т. п. Оче видно, что такие замены не ухудшают читаемость выражений. Но с друrой стороны, не всеrда следует оптимизировать (например, за пись А + А менее точна, чем запись 2.0 * А, ибо ошибка усечения в операциях + или  над вещ данными имеет тенденцию к накопле нию). Эффективность  сам по себе параметр неплохой, но нужно соблюдать меру и не приносить в жертву эффективности леrкочита емость проrраммы и, тем более, точность вычислений. Итак, твори те, выдумывайте, пробуйте. Девиз фирмы IBM: "Think!" (Думай!)  популярная шутка среди проrраммистов. Если используется оптимизирующий компилятор, то тщательно оз накомьтесь с ero возможностями, чтобы знать, какие виды оптими зации он выполняет, и представить себе, какие фраrменты машин Horo кода скорее Bcero будут улучшаться. Обязательно оттестируй те свою проrрамму с помощью двух компиляторов (стандартноrо и оптимизирующеro), так как изза изменения последовательности вычисления значений выражений и порядка выполнения операторов результаты двух проrонов MorYT не совпасть. Наиболее распространенными ошибками при кодировании выраже ний являются пропуск скобок в знаменателях составных выраже ний, непарные скобки, пропуск знака умножения (например, объ явлено double А, В, АВ; и вместо А*В набрано АВ (Си)), ошиб ки целочисленноrо деления (в Си и Фортране, к примеру, 1/3 == О, а 1./3. == 0.(3)) и использование переменных с неопределенными зна чениями. Синтаксические ошибки леrко устраняются, так как они обнаруживаются компилятором. Присваивание значения Присваивание значения  одно из распространенных действий. Оно предполаrает вычисление, преобразование и пересылку значения. Продолжим решение проблемы "леrкочитаемость  скорость  память". Исключайте константные выражения, вычисляя их вруч ную. Первоначальный вид таких выражений можно сохранить в комментарии (например, С == MPI*.125; /* c==pi/8 */). Избеrайте лишних преобразований, для чеro rруппируйте операнды одинаково 
518 ro типа (к примеру, вместо У:== А*М *B*N пишите У:== (М *N)*A*B, но, с друrой стороны, запись (М * N) может привести к целочислен ному переполнению; СМ. в разд. "Оnераторы 'Цur;;.ла" 2.лавъt 7 пример вычисления п!) или вводите дублирующие переменные (например, вместо У:==А/8.0+М; Z:==B*M пишите Т:==М; У:==А*0.125+Т; Z :== В * Т). Избеrайте повторных вычислений (к примеру, вместо У:== (A  В) пишите У:== В  А, вместо У:== А  В; Z:== В  А пиши те Y:==AB; Z:==Y, вместо У:==А+(в+с)/п; Z:==A*(B+C)/D пишите Т:== (В + С)/п; У:== А + Т; Z:== А*Т, вместо У:== А/Х; Z :== В/ Х пишите Т :== 1.0/ Х; У :== А * Т; Z :== В * Т, вместо У:== А/ В/С пишите У:== А/(В*С), вместо У:== А*в/с*п/ Е пишите У:== А * В* п/(с * Е), вместо У == 3. * sin(X)  4. * sin(X) **3 пишите Т== sin(X) У== Т* (3.  4. * Т* Т), а еще лучше У ==sin(3. * Х), вместо Y:==ln(A) + In(B), rде А и В положительны, пишите Y:==ln(A * В), вместо У :== sqrt(A)/sqrt(B) пишите У :== sqrt(A/ В)). Помните: не всеrда нужны промежуточные переменные (такие переменные MO rYT потребоваться лишь однажды, например, вместо И :== Х  А; V:==YB; R2:==U*U+V*V пишите R2:==sqr(XA)+sqr(YB)). Не стремитесь создавать все своими руками, используйте встроенные функции (к примеру, константу 7r /2 (Фортран) можно задать как 2dO * atan(ldO)). Не забывайте, что источник и мишень в Паскаль проrрамме должны быть совместимы по присваиванию; исключение из этоrо правила  источник типа цел, мишень типа вещ. Наиболее распространенными ошибками при кодировании присваи ваний являются ошибки пунктуации (вместо знака присваивания :== используется знак == и наоборот), орфоrрафические ошибки (вместо sqrt написано sqr, вместо arctan или atan  arctg; помните, что ln  имя натуральноrо лоrарифма в Паскале, а log  в Си и Фор тране), ошибки в типах источника и мишени, ошибки использования переменных с неопределенными значениями (к примеру, перемен ной У не присвоено значение, но операторы writeln(Y) и write(*,*) У выводят О, а оператор cout «У;  случайное число ("мусор")). Признаком наличия таких переменных может быть получение раз ных ответов при двукратном проrоне проrраммы с одними и теми же исходными данными, а также ошибки деления на нуль, перепол нения или исчезновения порядка. Отладка  это эксперимент. К ней надо rотовиться. Знайте, что в 
519 вашей проrрамме, как правило, содержится несколько ошибок, по этому вы скорее Bcero наблюдаете эффект их взаимодействия. He которые из ошибок явно и не проявляются. Они MorYT порождать цепочку ошибок, называемых наведен:н:ы.ми (например, при выходе индекса за ero rраницы либо портятся элементы массива, либо иска жаются значения переменных, зарезервированная память дЛЯ KOTO рых соседствует с памятью, отведенной массиву; следствием же бу дет получение трудно объяснимых диаrностических сообщений; си стема может и не выдать какихлибо предупреждений). В длинных сообщениях обращайте внимание прежде Bcero на первые фразы, ибо последующая информация нередко связана с наведенныIии ошибка ми. Будьте rOToBbI к получению от системы сообщений, которые не следует понимать буквально. Ввод и вывод Операции чтения/записи длительны по времени, поэтому их следу ет сокращать. Оrраничивайте ввод с клавиатуры. Вводите только те данные, которые действительно являются переменными (началь ное приближение, Епоrрешность, запланированное число итераций, размер коллекции данных и пр.), а выводите ровно столько инфор мации, сколько вы можете обработать. Два последовательных опе ратора ввода/вывода можно нередко объединить в один, что сэконо мит ресурсы системы. Используйте простые и ясные списки ввода/ вывода (к примеру, в списке вывода вместо У  Р(Х) : 8 пишите (У P(X)) : 8; а здесь cout« '\п'« (2 < 1)« 'u'« (2 «1)« 'u'« (1 == 1) «'u'« (1 ==== 1)« 'u'« (1 + == 1); круrлые скобки просто необходимы [48]). Данные, подлежащие BBO ду, компонуйте в физические или лоrические rруппы. Выполняй те эхопроверку введенных данных, так как, вопервых, возможны ошибки набора ("мусор на входе  мусор в результатах") и, BO вторых, может в будущем потребоваться распечатка (твердая копия данных). В диалоrовом режиме выводите на экран "приrлашение к вводу"  последовательность подсказок, какие данные и в каком порядке следует набирать на клавиатуре. Выясните, существуют ли какиенибудь оrраничения (системные 
520 или административные) на объем выводимой информации. Озна комьтесь с характеристиками используемых внешних устройств (важный параметр  длина строки вывода). Современные принтеры обеспечивают свободный выбор цвета и шрифтов, удобное формати рование и множество rрафических режимов. Выводная информация должна быть ясной, наrлядной и содержательной. Не жалейте уси лий на формирование ее заrоловка и описание ее назначения. Про ставьте дату и нумеруйте страницы. Каждую порцию информации снабдите своим заrоловком, а значения  своими именами. Исполь зуйте такие формы отображения, как таблицы, диаrраммы и rpa фики (нередко рисунок полезнее сотни слов). Выясните, является ли первый символ печатаемой строки символом "управления KapeT кой принтера". Применяйте явные форматы. Ширина поля BЫBO да не должна превышать количества верных разрядов выдаваемоrо результата. Экономьте бумаrу, используя всю ширину листа. По сле завершения отладки не забудьте удалить из текста Проrраммы отладочные средства (например, операторы вывода; их можно за комментировать). Выводные данные должны быть такими, чтобы их можно было, не редактируя, поместить в отчет. Наиболее распространенные ошибки ввода/вывода  это неправиль но выбранные форматы, ошибки в записи данных, неверное исполь зование операторов readln, write и scanf (опущен знак &, строковое данное содержит пробелы). Разветвление Разветвление требует особоrо внимания. Экономьте время, для чеrо выполняйте тождественные преобразования выражений, входящих в условия. Нет разумной альтернативы постоянству приемов кодиро вания (например, используйте переключатели одинаковым образом: О или false  для обозначения состояния "выключено" (условие не соблюдается), а 1 или true  для обозначения "включено" (условие выполняется) ). Особенно тщательно стройте узлы проверки 1 . ДOBO 1 Поразительно леrко написать условие, противоположное тому, которое Tpe буется в узле проверки, или поменять, скажем, знак < на знак <= и наоборот. Накапливая опыт в решении задач, вы не раз будете удивляться своим (нередко "rлупым") ошибкам. 
521 дите формулировку условий ветвления до совершенства. Не жалей те скобок (к примеру, отношение (В  А) < Eps читается леrче, чем эквивалентное ему неравенство В  А < Eps). С помощью скобок обеспечивайте старшинство операций (например, условие Х Е (а; Ь) в Паскале следует записать в виде (А < Х) and (Х < В)). Пиши те, что думаете (например, вместо (М  N) <== О пишите М <== N, вместо (А < О) or (А > О) пишите А <> О, вместо Flag == true пи шите просто Flag). Критерий "достаточной близости" должен быть относительным (к примеру, IXn+l  Хn'  € Х maX(IXn+ll, Ixnl)), но не абсолютным. Не проверяйте вещ данные на равенство (например, вместо А == В пишите abs(A  В) <== Delta, rде Delta  допуск, т. е. малая величина, выбранная по условию задачи и не меньшая компьютерноrо с). Иноrда при записи условий удается обойтись без вызова функций (например, вместо R < sqr(25.0) пишите R < 625.0, вместо sqrt(X *Х +у *У) < R пишите (Х *Х +У *У) < Н*Н). Помни те, что, вопервых, not является одноместной (унарной) операцией и она выполняется всеrда над первичным лоrическим выражением, и BOBTOpЫX, проверки, содержащие not, обычно реализуются дольше, чем их простые эквиваленты. Иноrда можно сократить время путем соответствующеrо размеще ния операндов в лоrическом выражении. Пусть А, В, С  лоrи ческие первичные выражения. Компилятор прекращает обработку выражения (А or В) or С при истинном значении выражения А or В, так как тоrда значение исходноrо выражения истинно независимо от значения С (если проrраммист не использует побочные эффек ты, связанные с нахождением значения С, то в ТОМ, что вычисление С не производилось, нет ничеrо плохоro). При этом, если С часто принимает значение true, В  реже бывает истинным, А  совсем редко, то выражение (А or В) or С лучше сразу представить в виде (С or В) or А. И наоборот, если используется операция and, первым в выражении должно быть самое "маловероятное событие". При описании ветвления спланируйте проверку условий так, чтобы леrко произошло отделение одной ветви от друrой. Сначала обраба тывайте Те ветви, условия в которых MorYT быть чаще друrих ис тинными. Избеrайте взаимоисключающих или повторных, лишних проверок (к примеру, вместо if (А < Х) and (Х < В) then ... пиши те if А < Х then if Х < В then ..., тем самым экономится время, 
522 ибо не производятся лишние проверки ). В операторе if оrраничивай те число вложенных операторов if (например, тремя операторами). Иноrда удается вообще отказаться от условноrо оператора (напри мер, вместо if Х < о then Х :== X пишите Х :== abs(X), вместо if М == N then Р:== true else Р:== false пишите Р:== (М == N). Делайте как можно меньше переходов. Не используйте оператор goto в условном операторе и для орrанизации повторений. Не пре вращайте проrрамму в f/ лоrическое спаrетти". Частота применения goto обратно пропорциональна квалификации проrраммиста. Целе сообразность использования goto должна решаться в каждом OT дельном случае (должно быть очевидным преимущество ero исполь зования перед друrими средствами; например, при описании необыч ных, исключительных ситуаций, для орrанизации специальноrо BЫ хода из тела цикла (коrда надо сказать просто goto), но переход дe лайте вперед, а не назад). Оператор перехода нередко удается заме нить оператором продолжеНИЯ, прерывания или возврата (см. разд. "Операторы цшсла" 2лавы 7). Впрочем, само по себе Проrраммиро вание без goto  это еще не структурное проrраммирование. Вот перечень наиболее вероятных ошибок при кодировании развет влений: О неполный учет возможных условий; О неправильная проверка (к примеру, использование в отношении знака == вместо знака ==== (Си)); о забыт оператор end if (Фортран); о несколько операторов не объединены в составной оператор; О непарные операторные скобки (чаще не хватает end или}); о несоответствие if . .. else (каждому else должно соответствовать то if, которое else непосредственно предшествует); О тип выражения в операторе выбора не порядковый; 1:] пропущено of; о не обрабатывается ветвь elsejdefault. Локализуя ошибки и проводя тестирование, применяйте трассиров ку (функциональные клавиши <F4>, <F7> и <F8» и отладочный вывод. Вставляйте операторы вывода во все ветви; печатайте дaH ные, определяющие выбор ветви, и сообщения о том, какая ветвь 
523 отработала. Так подберите данные, чтобы все ветви про['раммы бы ли проверены. Используйте отладчики. Повторения Повторения мно['очисленны и разнообразны, поэтому проблему "скорость  память" надо решать для них особенно тщательно. Ис пользуйте каждый оператор цикла стро['о по назначению (циклы с пред и постусловием, операторы цикла пока выполнять, дЛЯ BЫ полнятъ И выполнять пока). Например, цикл 1:== 1; while 1 <== N do begin операторы; inc(I) end несомненно более ['ромоздок, чем эквивалентный цикл for 1:== 1 to N do begin операторы end Если Х  параметр цикла типа вещ, изменяющийся по закону Х == Ха (Xk) h, то из трех выписанных далее операторов цикла: 1. Х:==ХО; whileX<Xk+H*O.5do begin...;X:==X+Hend 2. read(..., Delta); ...; X:==XOH; repeat Х:==Х+Н;... until abs(XXk)<==Delta 3. for 1 :==0 to round ((XkXO)IH) do begin X:==XO+I*H; ... end лучше использовать оператор for (эти примеры ни в коей мере не отрицают факта, что операторы while и repeat в определенной си туации чрезвычайно полезны). Совершенствуйте до предела математическую модель решаемой задачи. Используйте рекуррентные соотношения. Ино['да неслож ный анализ дает, что для кодирования повторений лучше вооб ще не применять оператор цикла. Например, значение полинома Рn(Х) == Ea aiXni в точке Х можно найти по правилу ropHepa: Pi==Pilx+ai, ['де Ра==аа (i==l, 2, ..., п), следующим образом: Р :== А[О]; for 1 :== 1 to N do Р:== Р * Х + A[I] Однако для п  5 (например, при п == 5 ) вычисления по развернутой формуле Р :== ((((А[О] * Х + А[l]) * Х + А[2]) * Х + А[3]) * Х + А[4]) * Х + А[5] требуют меньше времени. Итак, развернuте короткий цикл. 3амени 
524 те ero эквивалентом в явном виде. Например, вместо for 1:== 1 to 3 do А[1] :== 1 пишите А[l] :== 1.0; А[2] :== 2.0; А[3] :== 3.0. Друrой пример: при вычислении алrебраическоro дополнения [21] требуется значе ние k == (  1 )i+ j . Эффективным будет следующее решение: К:== 1  (1 + J) mod2 * 2 { Паскаль} J{ == 1  (1 + J) % 2 * 2; // Си J{ == 1  mod (I + J,2) * 2 ! Фортран И еще пример: при суммировании ряда S == Lk=1 (  l)k k лучше ис пользовать условный оператор: if odd (N) then S :== trunc (N/2)  N else S :== N/2 Время трансляции и выполнеljИЯ проrраммы, ее длина в большой степени зависят от выбранной структуры данных. Понижайте раз мерности и размеры массивов. Отдавайте предпочтение скалярам, т. е. придерживайтесь правила замены: "параллелепипед" -----+ матри ца -----+ вектор -----+ скаляр. Например, в задаче вычисления значения полинома можно еще сэкономить ресурсы, если вместо массива KO эффициентов использовать простые переменные АО, А1, А2, А3, А4 и А5. Если в теле цикла к элементу массива нужно обратиться более одноrо раза, присвойте ero значение скаляру и работайте с ним. Избеrайте вычислений со сложной индексацией. Например, опера тор for 1 :== 1 to N do А[2 * 1  1] :== В[2 * 1  1] + с замените оператором for 1 :== 1 to N do begin J:== 1 + 1  1; АР]:== ВР] + с end или операторами 1 :== 1; while 1 < N + N do begin А[1]:== В[1] + с; inc(I,2) end Кратные циклы крайне расточительны. Вкладывайте их оптималь ным образом. Дело здесь в следующем. Цикл в отличие от линейной, развернутой части проrраммы требует дополнительноro времени на свою подroтовку и завершение (на продвижение, проверку и переда чу управления). А сэкономить здесь можно, если по условию задачи кратные циклы переставимы. Тоrда предпочтительной будет такая вложенность, при которой цикл с наибольшим числом повторений 
525 окажется самым внутренним. Действительно, двойной цикл вида for 1 :== 1 to 20 do for J :== 1 to 10 do . . . требует 21 подrотовки и 220 завершений, а эквивалентный ему цикл for J :== 1 to 10 do for 1 :== 1 to 20 do . . .  11 подrотовок и 210 завершений. Кроме Toro, если возможно, применяйте развертку, объединение или разъединение циклов. Например, при четном n цикл for 1 :== 1 to N do A[I]:== 1.0 разверните так: 1 :== 1; while 1 < N do begin A[I] :== 1.0; AfI + 1] :== 1.0; inc(I,2) end Здесь коэффициент развертывания равен двум. Экономится поло вина проверок. Еще пример развертки цикла, в котором откажитесь от KopoTKoro внешнеrо цикла, т. е. цикл вида for 1 :== 1 to 3 do for J :== 1 to N do C[I, J] :== A[I, J] + B[I, J] замените циклом for J :== 1 to N do begin С[l, J] :== А[l, J] + В[l, J]j С[2, J] :== А[2, J] + В[2, J]j С[З, J] :== А[З, J] + В[З, J] end Теперь приведем пример оббединения: два цикла for 1 :== 1 to N do A[I] :== 1.0; '" ; for 1 :== 1 to N do B[I] :== С соедините в один эффективный цикл for 1 :== 1 to N do begin A[I]:== 1.0; B[I] :== С end Обратный прием называется раЗбединением. Он полезен в циклах, содержащих инвариантные, т. е. никак не связанные с параметром цикла, выражения. Например, цикл for 1 :== 1 to N do if М <> О then A[I] :== 1.0 else B[I] :== С 
526 в котором значение выражения М < >0 остается постоянным на протяжении всех повторений цикла, замените двумя циклами: if М <> О then for 1 :== 1 to N do A[I]:== 1.0 else for 1 :== 1 to N do B[I]:== С Итак, здесь выполнена тривиальная чистка цикла. Уделяйте ей oco бое внимание. Выносите за цикл все инвариантные выражения (под выражения, в том числе и индексные). Здесь можно добиться MHoro ro. К примеру, выполнив чистку цикла в следующем суммирующем цикле: S :== о; for 1 :== 1 to N do s:== S + A[I] * Х + в получите эффективный цикл: S:== о; for 1 :== 1 to N do s:== S + A[I]; S:== S * Х + N * В Иноrда удается повторно воспользоваться общими подвыражения ми, даже если они зависят от параметра цикла. Знайте, что часто большая часть времени тратится на выполнение небольших участков проrраммы (приблизительно 5% ее объема), Ha зываемых рити'Чесими областями. Ими являются прежде Bcero MHoroKpaTHbIe циклы. Экономить за некритическими областями не так важно, но сами критические области кодируйте тщательно, yдe ляя особое внимание внутренним циклам, так как наличие в них "лишнеrо" действия может заметно увеличить общее время решения задачи. К примеру, алrоритм умножения матриц можно представить так: for 1 :== 1 to М do for J :== 1 to L do begin C[I, J] :== о; for К :== 1 to N do C[I, J] :== C[I, J] + A[I, К] * В[К, J] end { ео умножения матриц} Однако в оптимальном решении этой задачи (см. разд. "Матри'l.{а" zлавы 4) ссылка на элемент массива C[I, J] заменена простой пере менной s (ибо индексы i, j не зависят от параметра k). Что это дает? Если сравнить время, необходимое для перемножения двух KBaдpaT ных матриц размера 3 х 3, 10 х 10 или 50 х 50, то вариант решения с 
527 элементом C[I, J] требует следующих затрат  4, 105 и 13319 отн. ед., а в варианте с переменной s  соответственно 3, 74 и 9147 отн. 2 ' ед. . Кодируйте надежные циклы (обратите внимание на то, как это делается в задачах последовательных приближений; см. разд. "итератu61tы'1 u,ur;;л" u "Cтene1t1toi1 р.яд"2ла6ыl 3, а тar;;JfCe разд. "Модуль" 2ла6ыl 8). Используйте операторы while и repeat дЛЯ KO дирования итеративных циклов только тоrда, коrда есть полная YBe ренность в конечности числа повторений. Если проrрамма ненадеж ная, то ее быстродействие не имеет значения. Кодируйте универсальные циклы. Используйте вместо чисел пере менные. Применяйте, rде это возможно, массивовые выражения, так как они леrко читаются и транслятор выбирает самый эффективный метод (код) их обработки. Например, вместо двойноrо цикла for 1 :== 1 to М do for J :== 1 to L do Acopy[I, J] :== A[I, J] пишите просто Acopy:== А (Паскаль) или Acopy == А (Фортран). Частой ошибкой при работе циклов является "зацикливание". Вот внешние признаки "вечноrо" цикла: долrо не выдаются результа ты, выводятся одни и те же числа или объем выходной информации больше, чем запланировано. Для локализации указанной ошибки проверьте подrотовку цикла, просмотрите ero заrоловок, проверьте тип параметра цикла, ero начальное и конечное значения, шаr из менения и проанализируйте условие окончания цикла. Если ошибка еще не найдена, просмотрите тело цикла, проверьте рекуррентную формулу (если таковая используется), убедитесь, что новые зна чения переменных заменяют предыдущие, проверьте правильность расположения операторных скобок (begin и end, { и }). До и после "подозрительноrо" участка проrраммы вставьте операторы вывода специальных сообщений. Используйте при отладке клавиши <F4>, <F7> и <F8>. Приведем пример "вечноrо" цикла: #include <iostream.h> void main (void) // Eternalcycle 2См. Мик Б., Хит П., Рашби Н. и др. Практическое руководство по проrрам мироваllИЮ.  М.: Мир, 1986.  168 с. 
528 { unsigned 1; for (1 == 13; 1 >== 1; 1  == 2) cout« "\nuu" « 1; } Выводятся числа 13, 11, 9, 7, 5, 3, 1, 65535, 65533, 65531 ... Здесь неверно объявлена переменная 1. Вот правильное объявление: int Ij. Паскальпроrрамма Eternalcycle program EternaCcycle; var 1 : word; { var 1 : integerj } begin 1 :== 13; while 1 > О do begia write (#13#10, I Uu/ 1); inc (1, 2) end end. тоже "зацикливается"З. Иноrда за "зацикливание" можно принять медленно сходящийся ите ративный процесс; в такой ситуации введите на время отладки фик тивное значение допуска (например, увеличьте поrрешность е до значения, paBHoro 1e1, и убедитесь, что выход из цикла будет cдe лан при соблюдении заданноrо условия). Если и после этоrо ошибка не обнаружена, начните проверку с постановки задачи и проанали зируйте все этапы ее решения. Друrие распространенные ошибки  использование в теле цикла неопределенных величин и выход значений индексов за rраницы ин дек сов (например, если массив А состоит из 10 элементов, то при 1, большем пяти, значение А[2 * 1  1] не определено). Упомянем об ошибке, называемой "ошuба на 1", коrда цикл выполняется на один раз больше или меньше, чем требуется. Помните, что три раза по 1.0/3.0 не равно единице, что параметру цикла не разрешается BЫ ступать в роли мишени в теле цикла для или в качестве формаль Horo параметра. Обратите внимание на то, что разделитель; в конце заrоловка цикла делает тело цикла пустым. 3Если объявить unsigned М = 1, N = 2, К = М  N;, получим К = 65535. Такой же результат ждет нас в Паскальпроrрамме. Вот правильное объявление: int J{ = м  N; или var К: integer;. 
529 rлава 14 Подпроrрамма Нам осталось в хорошем стиле закодировать подчиненные алrорит мы и проrрамма будет rOToBa. Процедура и функция Вычленяйте из задачи подчиненные алrоритмы. Соответствующие проrраммы будет леrче отлаживать, тестировать и модифициро вать. Именно принцип "разделяй и властвуй" позволяет справиться с большими проектами. Но не кодируйте первый пришедший в ro лову алrоритм. Как бы вы тщательно не выполняли тактическую (выбор подходящей структуры данных) и техническую (применение специальных приемов кодирования) оптимизации, добиться MHoro ro не удастся, если страте2ическоi1 оптимизации (разработке или выбору подходящеrо алrоритма) не было уделено должноrо внима ния. Тривиальный пример: вычисление суммы S == Lk=l Р можно описать буквально, посредством команды повторения, но лучше при менить эффективный в абсолютном смысле алrоритм, состоящий из одной команды присваивания s:== sqr(N * (N + 1) * 0.5). Несколь ко менее тривиальный случай  внутренняя сортировка. Известно, что обменная сортировка массивов удобна при небольшом числе ero элементов (п < 20). Сортировка д. Шелла работает почти в два pa за быстрее при п == 200 и в девять раз  при п == 2000 (здесь рост BpeMeHHblx расходов не превышает п 1 . 2 вместо п 2  в сортировке 
530 обменом). Еще лучший результат (при больших значениях n) дают сортировки Дж. Уильямса, Р. Флойда и Ч. Хоара [13, 31]. Разрабатывайте короткие алrоритмы. Рекомендуемая длина алrо ритма  не более 60 строк текста. В подпроrрамме, состоящей бо лее чем из 50 операторов, количество ошибок и степень сложности их выявления растут экспоненциально. Планируйте тестирование алrоритмов. Составляйте тесты после раз работки проекта, но до этапа кодирования. Такой подход помоrа ет раньше выявить большинство ошибок алrоритмизации. Подтвер ждайте правильность решения с помощью компьютера (пусть он выполняет черновую работу). Знайте, что несовпадение результа тов решения и тестирования может быть вызвано ошибками в Te сте (нет ничеrо хуже, чем неправильный тест). Для каждой подпро rpaMMbI определите область допустимых входных значений, множе ство выходных значений, побочные эффекты и возможные исклю чительные ситуации. При этом в редких случаях аварийные ситуа ции должны прерывать выполнение проrраммы. Вместо этоrо нужно выявить ошибку и передать управление вызывающей проrраммной единице, а последняя должна сама решить, прерывать или продол жать работу. Такой подход rарантирует проrрамме универсальность. Итак, подпроrрамма при любых входных данных должна доработать до конца и выдать результат, либо информацию о невозможности получить результат (передав ее через сиrнальные параметры). Yдe ляйте должное внимание побочным эффектам, так как изменение значений aprYMeHToB и rлобальных переменных может привести к некоммутативности операций. Рекурсивная подпроrрамма может во MHoro раз увеличить затраты времени и памяти, что является платой за лаконичную и наrляд ную запись алrоритма, а соответствует ли такая цена получаемому выиrрышу или нет, решайте отдельно для каждоrо случая. В HeKO торых ситуациях без применения рекурсии трудно описать процесс обработки (к примеру, при использовании польской записи выраже ний, предназначенных для трансляции; вычислении кратных инте rралов и т. д.). Выполняйте функциональное упорядочение формальных параме тров  в списке параметров сначала размещайте входные параме тры, потом имена подпроrрамм с возможными спецификациями и, 
531 наконец, выходные параметры. Имена параметров и локальных пе ременных выбирайте в соответствии с формальным (например, Ma тематическим) описанием алrоритма. Делайте поменьше вызовов во внутренних ЦИКЛах. Так, на критиче ском участке можно, например, заменить встроенную функцию sin х отрезком ряда sin х  х  х з /6 + х 5 /120  х 7 /5040, Ix\  7r /4, что в области определения дает ошибку, не превосходящую по MO дулю 3.1 х 107; еще один способ  внести в память таблицу значе ний функции или, наконец, можно критический участок закодиро вать Ассемблером!; правда, такие подходы должны предпринимать- ея только после тщательноrо равнительноrо анализа. С большой осторожностью используйте rлобальные объекты. Комментируйте такие действия. Приемы оптимизации проrрамм надо знать и при необходимости уметь разумно использовать, несмотря на то, что они ухудшают чи- таемость проrрамм. Частые ошибки при кодировании подпроrрамм  это ошибки несо- rласования фактических и формальных параметров (несоответствие их типа, порядка следования и даже количества), поэтому вставляй те отладочные операторы вывода в точках вызова и возврата, а TaK же в начале и в конце исполняемой части подпроrраммы и таким образом контролируйте "сырье" и "продукцию". При большой rлуби- не рекурсии возможно переполнение стека возврата. Кроме Bcero, не всеrда правильно объявляется тип значения функции, опущено сло- во var или символ * перед именем параметрарезультата, нет сим вола & перед именем арrументарезультата (Си), не учитываются (и не комментируются) побочные эффекты или имени функции не присваивается результат. Аккуратно обращайтесь со встроенными функциями (к примеру, помните, что тип значений функций Паска ля abs(x) и sqr(x) такой же, как тип aprYMeHTa х, что Си имеет че- тыре функции нахождения абсолютной величины  abs(x), labs(x), fabs(x) и fabsl(x)). 1 Перечислим в порядке увеличения времени выполнения проrраммы опре деления числа 7r методом Монте--Карло (п = 106): Ассемблер, Си-, Паскаль-, Фортран-проrрамма. 
532 Не будьте слишком доверчивыми. Знайте: неправильная проrрам ма (для какоrонибудь варианта исходных данных) может выдать правильный результат. Запись проrраммы Кодируйте алrоритмы так, чтобы проrрамма леrко читалась людь ми, а не только компьютерами. Включайте в нее комментарии  вводные, оrлавление и пояснительные. Вводн,ые 1Со,М,Мен,тарии MorYT содержать дату написания проrрам мы, сведения о ее авторе и назначении, указания по ее вызову и использованию, список и назначение переменных и наборов данных, например, unsigned Nstr; / / Nstr  номер текущей строки указания по вводу/выводу, названия методов, ссылки на литератур ные источники, сведения о требуемом объеме памяти, BpeMeHHblx затратах и пр. Оzлавлен,uе nросра'м'мЫ должно содержать имена и описание функ ций каждой проrраммной единицы. Местоположение оrлавления  в r лавной проrрамме. По,я,сн,uтелън,ые 1Со,М,Мен,тарии характеризуют каждый лоrически выделенный фраrмент проrраммы (узлы проверки, циклы и т. д.) И те части фраrмента, которые трудно понять без пояснений. Hop мой можно считать не менее одноrо комментария на 16  24 строки проrраммноrо текста. Комментарии должны быть деловыми и лако ничными. Содержание комментариев крайне важно. Не надо пере водить с анrлийскоrо операторы, перефразировать проrрамму и по ясн ять синтаксис языка проrраммирования. Примеры плохих при мечаний  комментарий, который представляет собой Bcero лишь "шум",отrолосок проrраммы: inc (1); и неверный комментарий: if not odd (1) then 5 :== 5 + A[I]; { добавить 1 к параметру цикла 1 } { проверить: 1  нечетное? } Комментарии должны содержать некоторую дополнительную ин формацию, объяснять цель и лоrику rруппы операторов, необычные и неочевидные моменты. 
5ЗЗ Комментарии леrче читать, если их KaKTO выделить, например, за ключить в прямоуrольники из специально подобранных символов (таких, как , ==, 1). Для вертикальной разрядки текста пользуйтесь "пустыми" комментариями (пустыми строками; комментариями, co держащими только символы  или ==). Пояснительные комментарии размещайте с какойнибудь одной позиции в конце строк. Везде, rде это приводит к леrкочитаемой проrрамме, делайте про белы и отступы (один отступ есть uu), ставьте скобки, выравни вайте знаки ==, : или :==. Пишите проrрамму лесенкой, причем чем позже оператор должен появиться в тексте проrраммной единицы, тем правее он запишется. Смещайте операторы, которые MorYT про пускаться при выборе следующеrо. оператора. Применяйте" правило рельефа": сдвиrайте текст в строке так, чтобы выделить команды "цепочка", "ветвление", "выбор" и "повторение". Краткий if можно поместить в одну строку, а длинный пишите столбцом, располаrая связанные слова if, then и else друr под друrом. Короткие опера торы цикла размещайте в одной строке, а rромоздкие  пишите со смещением тела цикла, выравнивая при этом операторные скобки. Обязательно комментируйте каждый end или }. Метки операторов пишите поближе к левому краю строки, чтобы их было леrко найти. Одноrо оператора в строке достаточно. Следуя этому правилу, мож но облеrчить локализацию ошибок и редактирование оператора, так как такой процесс не затраrивает остальной текст. Правда, несколь ко коротких, лоrически связанных операторов можно разместить и в одной строке. Кодируя выражения, не пишите длинных ОПерато ров: семь  вот наибольшее количество операндов в выражении. Пользователь может варьировать длину операторов в зависимости от условий задачи и собственноrо опыта. Леrкочитаемая проrрамма создает впечатление, что ее разработчик хорошо знал, что делал. Вопросы и задачи для проверочной работы Приведем вопросы и задачи, которые можно использовать дЛЯ KOH троля знаний по Паскалю в 15минутной проверочной работе. После небольшой переделки они будут rодны в работе с друrими языками 
534 проrраммирования. 1. Для чеrо в проrрамме используются символы . , ; : == .. () [] {} и'? Приведите неделимые цепочки символов (например, <». 2. Как в проrрамме написать комментарий? 3. Какие слова допустимы в роли имен объектов проrраммы: 8 АН, is, not, gold, that, glitters; 8 АН, roads, lead, to, Lesnoe. 4. rде используются цел, длин цел, вещ, двточн, лоr, симв и строк данные? 5. Может ли запись числа содержать более одноro знака + или  ? Масса атома водорода равна 0.0000000000000000000000017 r. Пред ставьте это число короче. Запишите рациональную дробь 2/3 и дe сятку в степени минус десять. 6. Перечислите знаки операций. Каков их paHr? 7. Перечислите арифметические, лоrические, преобразующие и по рядковые функции. Коrда удобна функция sqr? Коrда значения функций round( х) и trunc( х) совпадают? 8. Вычислите: 8 неотрицательный остаток от деления m на n; 8 loga Х; 8 аrсsш Х; 8 arccos Х; 8 arcctg х; 8 разность натуральных чисел, используя только операции +; 8 частное от деления m на n, используя только операции +; 8 n!, используя только операции +. 9. Из числа Х найдите корень: 8 нечетной степени; 8 четной степени; 8 nй степени. 10. Преобразуйте: 8 Х В цел данное; 8 n в вещ данное. 11. Равны ли значения выражений: 8 M*N/L и M/L*N; 8 М * N div L и М div L * N; 8 сов(3.0 * Х) и сов(Х) * (4.0 * sqr(cos(X))  3.0); 8 У :== 1.0/Х и Х:== 1.0/У; 8 У :== sqrt(X) и Х:== У * У; 8 У :== In(X) и Х:== ехр(У); 
535 . Х и exp(ln(sqrt(sqr(X)))); . У :== tan(X) и Х:== arctan(Y); . У :== sin(X) и Х:== arctan(Y/sqrt(1.0  У * У)); . У :== Х * Х * Х и Х:== Y/abs(Y) * ехр(lп(аЬs(У))/З.О). 12. Два значения поменяйте местами без промежуточноrо копирова ния одноrо из них. 13. Из целоrо числа n выделите k ю циф ру от конца. 14. Нужно вычислить у == х  V X2  а 2 , rДе положительное число х велико, а число а мало. Какой фраrмент проrраммы быстрее и/или точнее выполнится: . У :== Х  sqrt(X * Х  А * А); . А2 :== А * А; У:== А2/(Х + sqrt(X * Х  А2)); . АХ :== А/ Х; У:== А * АХ/(1.0 + sqrt(1.0  АХ * АХ)). 15. Приведите эффективную проrрамму вычисления sinx  х  х з /6 + х 5 /120  х 7 /5040, /х'  7r /4. 16. Найдите площадь эллипса х 2 /а 2 + у2/Ь 2 == 1. 17. Приведите самую эффективную проrрамму в мире. 18. Как задать пробелы между выводными данными? 19. Некоторый текст (к примеру, "Человек думает, компьютер делает.") выведите на экран по одному слову в строке. 20. В тексте "Большую систему проrраммноrо обеспечения невоз можно оттестировать до конца даже за несколько лет ее эксплуа тации. Доказательства правильности проrрамм MorYT содержать ошибки." выведите первое предложение "по строкам" (длина CTpO ки  не больше 60 символов), а второе  "по столбцам". 21. Чему эквивалентен оператор readln(A, В, С)? 22. Что будет выведено на экран: . const Warcry: string ==' Ура!'; ...; writeln(' Warcry'); . а) writeln(' Крах'+'мал.'); б) writeln(' Нарру'+' new'+' year!'); в) writeln(' Вау... '+' Поди'+'ум.'#13#10'... Медаль'+'он.'); . const NI == #13#10; ..., write(NI,' То ли дождь,', NI, , то ли cHer.'). 
5Зб 23. Постройте квадрат, стороны KOToporo образованы пятью звездоч ками. 24. Напечатайте свою визитку (орrанизация, фамилия, имя, отче ство, должность, адрес, телефон, факс, email, http). 25. Напишите JIor выражение, принимающее значение истина, если: . точка Р(х,у) попала внутрь эллипса x2j9 + y2j16 = 1, в ту ero часть, которая принадлежит левой ПОЛУПЛОСКОСТИj . точка Р(х, у) принадлежит второй четверти единичноrо KPy ra, не включая rраницы, или той части плоскости, которая расположена вне Kpyra; . точка Р(х, у) принадлеит 45rрадусному сектору первой че тверти Kpyra единичноrо радиуса; . переменная х имеет значение, целая часть KOToporo, деленная на 255, не больше Б; . rод с порядковым номером уууу является високосным. 26. Укажите множество точек, для которых JIor выражение х  О ИМПJI У  О истинно. 27. Каково значение JIor переменной Р: . Р := 'Petersburg' = 'Petropol'; . Р := 'Пантикапей' < 'Петрополь'. 28. Верно ли написано: . Р := Q = R; . Р := odd(N) and false; . Р := abs(Delta) < Eps; . Р := false < true. 29. Переменной Q присвойте значение истина, если: . прямые ах + 'Ьу = с и dx + еу = f: . параллельны, . перпендикулярны; . из отрезков а, Ь, с можно построить тупоуrольный треуrоль ник; . точка Р(х,у) находится внутри квадрата с квадратным BЫ резом х+у=2, xy=2, x+y=2, xy=2, х+у=1, xy=1, x+y=1, xy=1; . ближайшее к значению х цел число четно и отлично от двой ки; . точка Р (х, у) находится внутри "бесконечноrо креста"  1 < х + 
537 +у<1, 1<xy<1, 1< x+y<1, 1<xy<1; . точка Р (х , у) лежит внутри кольца с центром в точке А (  1 , О) и с радиусами 1 и 2 или в нижней полуплоскости. 30. Проиллюстрируйте блоксхемой работу условноrо оператора: . if Ь 1 then if Ь 2 then 81 else 82; . if Ь 1 then if Ь 2 then 81 else 82 else 8з; . if Ь then; begin 81; 82; 8з end; . if Ь then else; begin 81; 82; 8з end; . if Х < 1.0 then begin У:== А; writeln(' У ==', У) end else if и > О then else W:== В; Т:== 1.0. 31. С помощью условноrо оператора и функции усечения поясните работу функции окруrления. 32. Выведите текст" Oh, yes", если переменная k делится на 4 или дает в остатке 1, 2 или 3; в противном случае выведите" Oh, по". 33. Числовая ось разбита точкама а, Ь, с (а < Ь < с) на четыре про межутка. Составьте фраrмент проrраммы, который для заданноrо х определяет номер промежутка, содержащеro х. 34. Вычислите значение полинома Лежандра Рп(х): ро(х) == 1 при n == О, Р1(Х) == Х при n == 1 и Р2(Х) == (3х 2  1)/2 при n == 2. 35. Подсчитайте температуру Т в КО на разных высотах h (м): T(h) == [(О  h < 11000) ------+ 286.6  0.0065h, (11000  h  25000) ------+ 216.66, (25000 < h  46000) ------+ 216.66 + 0.002761(h  25000), вывод сообщения ' h < О или h > 46000']. 36. Найдите уrол между двумя прямыми. 37. Решите уравнение ах == Ь, rде а, Ь Е R. 38. Составьте тест для проrраммы решения квадратноrо уравнения (х Е С). 39. Замените условный оператор эквивалентным оператором выбора: . if Ь then 8; . if Ь then 81 else 82' 40. Используйте операторы условный и выбора: . для вычисления у(х) == [(О  х < 0.1) ------+ ах + Ь, (0.1  х < 0.2) ------+ ах 2 +Ьх+с, (0.2х<0.з) ------+ ах, (0.3x<0.4) ------+ (ах+Ь)/ /(сх + d), (0.4  х < 0.5) ------+ а + Ь/х + с/х2, х/(ах 2 + Ьх + с)]; 
538 . для создания спрщючника "Все монархии мира": Европа (Бельrия, Великобритания, Дания, Испания, Лихтенштейн, Люксембурr, Монако, Нидерланды, Норвеrия, Швеция), Азия (Бахрейн, Бруней, Бутан, Иордания, Камбоджа, Катар, Ky вейт, Малайзия, Непал, ОАЭ, Оман, Саудовская Аравия, Таи ланд, Япония), Африка (Лесото, Свазиленд), Океания (ToHra, Западная Самоа); . для создания "Меховой энциклопедии": водоотталкивающий (росомаха), дешевый (кролик), длинноволосый (барсук, волк, медведь, росомаха), дороrой (шиншилла), коротковолосый (белка, суслик), леrкий (заяц, кролик, крот, суслик), ноский (бобер, выдра, морской котик), теплый (медведь, северный олень), тяжелый (волк, выдра, медведь, росомаха, овчина), холодный (rорностай, крот, сурок, суслик). 41. Напишите фраrмент проrраммы, печатающий в зависимости от месяца rода текст "Зима", "Весна" и т. д., используя: . вложенные операторы if; . не вложенные операторы if; . оператор case. 42. Какая разница между операторами if Х > о then writeln( х) и while Х > о do writeln(x)? 43. Вычислите у == sin х, rдe х == 100 (3600) 100. 44. Параметр цикла k при обратном отсчете принимает значения 10, 9, . . . , О. Используя операторы while, repeat и for, выведите на экран значения k и два предложения: "Пуск!" "Поехали... " 45. Орrанизуйте цикл с переменным шаrом, в котором параметр ци кла принимает значения 1, 3,6, 10, 15, 21, 28, ..., п. 46. Для значений х==О.l (1)0.1, кроме х==0.5 и х==0.7, вычислите аrсs1П х. 47. Найдите следующие суммы: . S == 2 Lk=l k; . S == Lk=l k 2 ; . S == Lk::o 1/2k. 48. Тело с начальной температурой io остывает по закону i n == == inl/(l + k) (п == 1, 2, .. .). Для заданных io, k и с определите MO мент времени, при котором выполнится неравенство i n  cio. 
539 49. Выясните, упорядочены ли по невозрастанию символы HeKOTO рой строки (к примеру, , Шел Саша по шоссе... '). 50. Получите массив В, элементы KOToporo равны модулям разности двух соседних элементов массива А длины п, деленным на модуль наибольшеrо из пары. 51. Используя оператор randomize и функцию random (2), задайте JIor массив А == (ai) (i == 1, 2, ...,200). Получите массивы В == (b k ) И С == (Ck) (k == 1,2, ..., 100), элементы которых равны COOTBeTCTBeH но аl, аз, . . ., а199 и а2, а4, . . ., а200' 52. Задан массив А длины 1. . Найдите наибольший нечетный элемент и ero номер. . Подсчитайте число четных элементов, номера которых при надлежат отрезку [т; п]. . Определите порядковый номер BToporo элемента, не меньше ro Iml. . Подсчитайте сумму дюжины отрицательных элементов, HOMe ра которых кратны п. . Найдите номер TpeTbero отрицательноrо элемента, модуль KO Toporo принадлежит отрезку [т; п]. . Определите номер первоrо четноrо элемента среди элементов с нечетными номерами. . Выберите элементы, номера которых кратны трем, и найдите куб суммы из выбранных чисел, не принадлежащих полуин тервалу (т; п). . Запишите ero элементы в обратном порядке. . Перепишите ero элементы в массив В длины m (l :::;; т) так, чтобы: . последний элемент массива А стал kM элементом Mac сива В, . аl стал b k (1:::;; k :::;; m  l + 1). . Выполните циклический сдвиr массива на k элементов влево. . Совершите циклическую перестановку ан! +---- ak (k == 1, 2, ..., l  1). . Сожмите массив, удалив из Hero каждый kй элемент (kE [2; l]). 
540 53. Получите и напечатайте единичную матрицу Е. 54. В матрице А размера n х n найдите наименьший по модулю эле мент, стоящий на rлавной диаrонали, и укажите ero координаты. 55. Вычислены элементы симметричной матрицы А nro порядка, расположенные не ниже rлавной диаrонали. Заполните всю матри цу. 56. Квадратная матрица А порядка n хранится "по строкам" в одномерном массиве. Протранспонируйте ее (в узле перестановки, очевидно, будут участвовать элементы вида A[(I  1) * N + J] и A[(J  l)*N +1]). 57. В трехмерном массиве (/параллелепипеде") найдите rлавный (наибольший по модулю) элемент и ero координаты. 58. Выведите символы, представимые в вашем компьютере, и их по рядковые номера. 59. В заданном тексте . Хороший компьютер в доме  непременный а,трибут COBpe менной семьи подсчитайте число rласных букв и выведите их на экран; . Компьютер можно использовать как электронный арифмо метр, но это равносильно прослушиванию передач радио по TVset найдите слова, начинающиеся с заданной буквы; . В хорошем задачнике по проrраммированию часть задач должна быть плохо сформулирована выведите на принтер по два слова в строке; . Работайте с внутренними (локальными) переменными, а внешними объектами пользуйтесь только в случае крайней необходимости найдите самое короткое и самое длинное сло во; . Прежде чем приступать к решению задачи, убедитесь, что вы поняли условие задачи сцепите каждое слово с части цей TO; . Язык мой  Bpar мой. Лучшее  Bpar хорошеrо замените слово Bpar словом друr; . Формула неудачи  стремление нравиться всем подсчитайте число слов; 
541 . из План на июнь получите План на июль, а из паро плав  пароход; . Бал бес Бар сук Вар вар Вот ум rаз ель rори зонт Каша лот Кол ода Мот ель Пан ель Пас порт Пи он Пол як Пост ель Префект ура Свет ёлка Тюль пан Цикл он Яр марка подсчитайте число пар слов, а затем сцепите парные слова; . Бибиrон Боримир Борислав Будимир Вадимир Велимир Вла димир Казимир Любомир Максимилиан Модест Новомир Остромир Радомир Тихомир подсчитайте, сколько раз BCTpe чается подслово мир. 60. Установите иллюстративную связь между постановкой пьесы (aB тор, роли,  актеры, режиссер, звукорежиссер, художник, костюмер, rример, суфлер, осветитель, машинист сцены) и алrоритмом (автор, фактические и формальные параметры, константы, rлобальные и локальные переменные). 61. Объявите функцию Float, преобразующую цел значение в вещ. 62. Объявите функцию, вычисляющую: . [х); . {х}; . 19x; . log2 Х; . ctg х; . секанс; . косеканс; . arCSIll х; . arccos х; . apeaTaHreHc Arthx == ln((1 + x)j(1  x))j2, Ixl < 1; · (vfX)'; · (lg х )' ; . (loga х)'; . (аХ)'; . (arccos х)' ; . (chx)'; 
542 . nю производную sin(n) kx; . (аХ)(n); . log(n) ах; . sh(n) х. 63. Объявите функцию: . Sign  "знак"; . Signum  "передача знака": модуль первоrо aprYMeHTa YMHO жается на знак BToporo; . Dim  "положительная разность" х  min(x, у), rде минимум нах?дится по формуле min(x,y) == ((х + у)  \х  YI)/2; . Ndoublefact, находящую n!! (n Е N); . Digit(n, k), которая при k == О выдает цифру целых числа n, при k == 1  цифру десятков и т. д., при k ==  1  цифру десятых частей, при k ==  2  сотых и т. д.; . Ssegm, определяющую площадь KpyroBoro cerMeHTa; . АтеаА, вычисляющую площадь четырехуrольника, описанно ro около окружности радиуса т; . Sumabs, находящую сумму модулей отрицательных элемен тов одномерноrо массива; . Prodentier, вычисляющую произведение целых частей эле ментов одномерноrо массива; . Вр, находящую след (шпур) квадратной матрицы А (числа, paBHoro сумме элементов rлавной диаrонали); . Nozero, определяющую количество строк прямоуrольной Ma трицы, содержащих хотя бы один ненулевой элемент; . Num7, подсчитывающую количество элементов, кратных 7, расположенных не ниже побочной диаrонали квадратной Ma трицы; . Distance23, вычисляющую расстояние между двумя точка ми в трехмерном пространстве. 64. Объявите лоr функцию, реализующую операцию: . "штрих Шеффера" (т. е. отрицание конъюнкции); . "стрелка Пирса" (отрицание дизъюнкции); 
543 . отрицание импликации. 65. Объявите лоr функцию, вычисляющую истина, если: . точка Р( х, у) находится внутри Kpyra раДиуса r с центром в точке А( а, Ь) или вне Kpyra радиуса (! с центром в точке В( с, d); . точка Р(х, у) находится под параболой у == ах 2 + Ьх + с и BHY три Kpyra радиуса r с центром в точке A(d, е); . нечетное число т не делится нацело на пили k; . при делении т на n в остатке получается четное число; . остаток от деления т на n нацело делится на kj . цел?tя часть х не деЛИТСll нацело на целую часть ln Х; . некоторая строка (например, , А уди А6') совпадает хотя бы с одним элементами CTpoKoBoro массива (например, 'Митсубиси 3000 GT', 'Мазда626', 'Мерседес SLC 600', 'Фольксваrен rольф', 'Альфа Ромео', 'Ауди А6', 'Опель OMera', 'БМВ 740', 'VW Пассат', 'Фольксваrен Пассат', 'Опель Вектра 156', , Яrуар XJ320', 'Хонда Леrенд', 'Тойота MR 2' , 'Джип rранд Чероки "Лимитед" '). 66. Объявите функцию для вычисления суммы: . S == 32:.:k=1(1)k1/2kj . S == 32:.:o(1)k/2k. 67. Объявите функции для вычисления средних величин: Аn == тА == == 1/n х 2:.: 7=1 ai, СП == та ==  Пi=l ai , М n == тм == n/ 2:.:i=l 1/ ai, Qn == == mQ == J 1/n х 2:.:i==l a. Для заданной последовательности (xk) (Xk > о; k == 1, 2, "" т) найдите средние величины. Упорядочьте их в порядке неубывания. 68. Объявите процедуру: . Divcmplx деления комплексных чисел; . Convinch перевода дюймов в м, см и мм (1 inch == 2.54001 сm); . Crylov, вычисляющую значения функций Крылова: S(x)==(chx+ cosx)/2, T(x)==(shx+ sinx)/2, U(x)==(chx cosx)/2, V(x)==(shx sinx)/2, Ixl<1l354.047j . Cramer, решающую по правилу Крамера систему линейных алrебраических уравнений (n == 2); 
544 8 Coтpr, осуществляющую сжатие одномерноrо массива удале нием из Hero нулевых элементов; 8 расчета рейтинrа участников шахматноrо турнира: n ож == (т  1)cickcp /(1 + Cickcp), а == 30.005, k и == kc + J.L(ni  n ож ) (i == 1,2, ..., т), rде k и и kc  соответственно новый и старый рейтинrи; J.L == 10 (в системе Эло); ni и n ож  набранное и ожидаемое число очков; т  число участников турнира; k cp  средний рейтинr турнира; 8 sиbstit, которая в прямоуrольной матрице заменяет каждый отрицательный элемент ero модулем; 8 Addтatr, складывающую две прямоуrольные матрицы; 8 Minиsтatr, изменяющую знаки элементов квадратной матри цы на противоположные. 69. По заданным n и х сформируйте матрицу А: .AU 2 n.1} 1 1 ( 11 12 .) 8 А== .1. 22 n1 n2 nn 1 х xn1 . A ( .  х 2 х" ) x2(1) xn1 х n 70. Приведите рекурсивное решение следующих ниже задач. 8 Вычислите: 8 a n +l==a n +d; 8 b n + 1 ==b n xq, b1:f:0, q:f:O, nEN. 8 Найдите сумму натуральных чисел, принадлежащих отрезку [т;n]. 8 Вычислите х n == ) 2 + -/2 + ... + J2 (n корней). 
545 . Вычислите значения полиномов Чебышева 2ro рода (Cheby shev) : Uо(х) == 1, U 1 (х) == 2х, U n + 1 (х) == 2хU n (х)  Unl(Х)' . Вычислите а 1 / т по формуле Хn+1 == с.р(х n ), rде с.р(х) == х((т  1)хт + (т + 1)а)/((т + 1)х т + (т  1)а). . Вычислите а n (п Е N): { а если п == l' N " а   а n mod2(andiv2)2, если п > 1. . Вычислите значение функции арксинус: arcsin х == 1r /2  vr=x (аох 7 + а1х6 + а2ХS + азх4 + а4ХЗ + аsх2 + +а6Х + а7) (О  х  1), rдe ао == 0.0012624911, а1 == 0.0066700901, аз == 0.0308918810, а4 == 0.05017 43046, а6 == 0.21459 88016, а7 == 1.5707963050 а2 == 0.01708 81256, аs == 0.0889789874, (€ == 2 х 1O8). . Вычислите значение функции Бесселя: lo(x) == ао()12+а2(Л10+а4()8+а6(Л6+а8()4+а10(Л2+а12 (Ixl  3), rдe ао == 0.0002100, а2 == 0.00394 44, а4 == 0.0444479, а6 == 0.3163866, а8 == 1.2656208, а10 == 2.2499997, а12 == 1 (€ == 5 х 108). Задачи для самостоятельной работы 1. Вычислите 19992001 (см. [60]). 2. Для разных типов данных (single, real, double, extended) BЫ числите 5 == 1.0  1.0/2.0 + 1.0/3.0  ...  1.0/10 n (п == 7, 11, 15, 19), суммируя члены ряда в порядке: . последовательно слева направо; . слева направо, все положительные, затем  отрицательные; . справа налево; . справа налево, все положительные, затем  отрицательные. Какой способ даст более точный результат? Значение 5 с 30ю 
546 верными цифрами таково [14]: 0.69309 71830 59945 29691 72323 71458 3. Используя знаки Морзе (см. уnра-жненuе 22 2лавъt 7), расшифруй те следующее сообщение: . 'UU'' 'UU .UU.. 'uu'uu'uuuu'uU" 'UU' .UU в нем символы отделяются друт от друта двумя пробелами. 4. Из заданноrо слова (например, Постфактум) посредством функ ции вырезки Cиtting выделите всевозможные подслова. 5. Объявите функцию Strpos, которая в заданной строке 'Irene (Ni colas, Andrew, John), Catherin (Yaroslav), Jirnrny' выделяет часть строковото данното, начиная с заданной позиции символа. 6. Сожмите строки, выбросив из них совпадающие символы: 'Larnbor ghini Jota', 'Ferrari F50', 'BMW 850i', 'Ford GT90', 'Chrysler Voyager', , Jaguar XJ220', 'Mercedes Benz MClass', , Alfa Rorneo 8pider', 'Dodge Viper GT8', 'Porsche Boxster', '8ubaru Legacy', 'Mustang Mach III', 'Volvo 880', '8ААВ 95', 'BMW Z3 Roadster', 'Renault Avantirne', 'Mazda Prernacy', 'Range Rover', 'Ford focus', '8aturn L8', 'Cadillac DeVille'. 7. Объявите процедуру: . "Беrущая строка"; . шифровки методом: . перетасовки, . посимвольноrо наложения (см. [60]). 8. Объявите и используйте структуру "Метеоролоrическая сводка" (Weatherreport) за последние n лет по месяцам (Months), co стоящую из следующих подструктур и элементов: температура (Ternperature: Everyday, Low, High, Average), давление (Pressure), осадки (Precipitations: Everyday, Average, Total), ветер (Wind: Direc tion, Velocity), влажность (Hurnidity) и высота волны (Wavealtitude). 9. Объявите подпроrрамму обработки текстовото файла: . Print для вывода файла Квалификация ПРОI'раммиста опре деляется и тем, сколько информации об ошибках он получает и обрабатывает за один ПрОI'он по k слов в строке; 
547 . Insert, которая перед каждой буквой слова вставляет букву э (например, рф и эрэф); . LenJ, подсчитывающую длину файла Если вы умный, то почему вы такой бедный? . Strident для вывода в строке экрана п одинаковых символов; . Space для rенерации заданноrо количества пробелов; . Center для вывода на экран файла Слон  мышь с операци онной системой по одному слову и центрирования ero; . Align для вывода файла Проrраммист может иноrда OTKa заться от "достижений куль Typbl' с выравниванием начала строк по заданной позиции; . AmoиnCConsonantal для нахождения в файле Не пишите про rpaMM в стиле "спаrетти" соrласных букв и подсчета их KO личества; . Instr для определения в файле "Изобретение велосипеда" в проrраммировании  дело довольно обычное первоrо BXO ждения заданной комбинации символов; . Doиblef для нахождения в файле Выдача информации о том, что не случилось, так же важна, как и подробности Toro, что произошло сдвоенных символов и подсчета их количества; . Lejt для выделения из kro слова слева заданноrо подсло ва (файл Побольше предварительной подrотовки (работы за столом), поменьше "творчества" за клавиатурой); . Right для выделения в файле Следование стандарту  чет кая политика. Ее, очевидно, каждый может понять из kro слова заданноrо подслова справа; . Workиp, определяющая максимальную, среднюю и мини мальную длины строк, число слов и строк файла То, что вообще может быть сказано, должно быть сказано ясно, а о чем невозможно rоворить  о том следует молчать. Людвиr Витrенштейн. 10. Приведите рекурсивное решение следующих ниже задач. Подсчи тайте rлубину рекурсии. . Найдите нок (т, п) == тп!нод(т, п). . Проинвертируйте заданную строку (например, , Пишите про 
548 rpaMMY так, как будто для KoroTo друrоrо, ибо через rод вы можете стать "этим друrим".'). . Уравнение х З + рх 2 + qx + r == О решите методом: . итераций, . хорд, . секущих, . касательных, . модифицированным методом касательных, . бисекций (см. [21,26,45,61]). Проrраммы должны быть надежными. Для сравнения приве дите нерекурсивные (итеративные) решения (в [21] даны Ha дежные алrоритмы нахождения корня уравнения 1( х) == О). 1 . Найдите значения интеrралов 1k == 1/ е х f xke x dx по форму О лам 1k == 1  k1k1, 10 == 1  l/е; k == О(n)1, n == 15. . По формулам Виета (Vieta) ро == 2, qo == ро/2, Pk == '1' 2 + Pkl, qk == Pkqk1/2, 7rk == 2/qk вычислите Число 7r; l7rk  7rkll  Е, k Е N. . Проверьте парность (баланс) скобок в арифметическом Bыpa жении. . Переведите арабские числа в римские. . Функция f(n) задана рекуррентным ссотношением: 1(n) == Р(1(n  1), 1(n  2), 1(n  3)), rде 1(1) == Р, 1(2) == q, 1(3) == r. Приведите рекурсивное и He рекурсивное решения задачи вычисления значения функции 1(n). Заметьте, что в рекурсивном решении происходят пере вычисления. . Найдите число разбиений Р( n) (см. упражнение 4 2лавы 1 или упражнение 94 2лавы 4). . Возрастающая последовательность обыкновенных правиль ных несократимых дробей, знаменатели которых не превыша ют n, называется оmрез1'СОМ ряДа Фарея nоряд1'Са n (например, 0/1, 1/7, 1/6, 1/5, 1/4, 2/7, 1/3, 2/5, 3/7, 1/2, 4/7, 3/5, 2/3, 5/7, 3/4, 4/5, 5/6, 6/7, 1/1  отрезок ряда Фарея порядка 7). 
549 Пусть Ха/Уа, Xl/Yl, Х2/У2, . ..  дроби, составляющие отрезок ряда. Имеем [31] Ха==О, Уа==l; xl==l, Yl==n; ХН2 == l(Yk + n)/Yk+lJXk+l  Xk, Yk+2 == l(Yk + n)/Yk+lJYk+l  Yk. Вычислите отрезок ряда Фарея порядка n. . Ха'Н,о71ск;ие баш'Н,u [1, 13]. Даны стержни А, В, С и n различ ных дисков. Диски можно надевать на стержни, образуя из них башни. Пусть сначала все диски находятся на стержне А (в убывающем порядке (по размеру)). Нужно перенести n дисков со стержня А на стержень С, сохранив их первоначаль ный порядок. При этом следует придерживаться следующих правил: . за один шаr можно перемещать один диск; . нельзя помещать больший диск над меньшим; . для промежуточноrо хранения можно использовать диск В. Постройте башню на диске с; n == 64. . Напишите проrрамму преобразования арифметическоrо BЫ ражения в постфиксную нотацию, т. е. польскую запись 2 . 11. Объявите функцию Length для определения в текстовых файлах длины каждоrо словаЗ. . "Что я знаю о Kpyrax?" . "Кто и шутя и скоро пожелаетъ, пи узнать, число ужъ зна етъ." . "Это я знаю и помню прекрасно: пи мноrие знаки мне лиш ни, напрасны." . "Que j'aime а faire apprendre un nombre utile aux sages, Immortel Archimede, artiste ingenieur, Qui de ton jugement peut priser la valeur? Pour moi, ton probleme eut de pareils avantages." 12. Банк данных содержит сведения об n персонах: ФИО, пол, воз раст, рост, вес, цвет волос и rлаз, специфические приметы. Введите данные о некотором субъекте и выведите наиболее близкое к нему 2См. Йенсен К., Вирт Н. Паскаль. Руководство для пользователя и описание языка.  М.: Компьютер, 1993.  256 с. ЗПоследний способ вычисления числа 7r [19]. 
550 описание из уже имеющихся в коллекции. 13. Приведите проrрамму, подбирающую брачные пары по HeKOTO рым признакам: пол, возраст, рост, цвет волос и rлаз, характер, pe лиrия, материальное положение, образование, интересы. 14. Все слова, получающиеся перестановкой букв в данном п бук венном слове, слейте в одно слово, разделяя пробелом. 15. Даны натуральные числа т и п (т < п). Сформируйте массив из цифр d 1 , d 2 , ..., d t , rде числа l и k такие, что d 1 , d 2 , ..., d k  цифры непериодической части, а dk+l, dk+2, ..., d t  цифры периодической части десятичной дроби т/п. 16. Используйте аналоr алrОРl!тма бисекций в решении следующей задачи: дан массив чисел аl  а2  .. .  а n и число Ь; найдите т, равное п + 1, если а n  Ь, и равное наименьшему числу k, дЛЯ KOTO poro Ь < ak, в противном случае. 17. Решите систему п линейных алrебраических уравнений с Tpex диаrональной матрицей коэффициентов [14]: all X l + а12Х2 == Ь 1 , ak,klxkl + akkXk + ak,k+lxk+l == b k (k==2, 3, ..., п1), an,nlXnl + аnnх n == Ь N ' Здесь А  и: ::: а" an,n1 a.). На kM этапе исключения неизвестных надо вычислять два коэффи циента ail+l == a11,Hl a11,kal+1/a и bil) == b11 a11,kbk) /a. Матрица А объявляется как var А: array[1. .N, 1. .N] of extended, rде индексированная переменная A[I, JI] представляет коэффици ент aJ). В [21] дано эффективное решение этой задачи 4 . 4См. также Мудров А. Е. Численные методы дЛЯ ПЭВМ на языках Бейсик, Фортран и Паскаль.  Томск: МП Раско, 1992.  272 с.; AreeB М. И., Алик В. П., rалис Р. М., Марков Ю. И. Библиотека алrоритмов 1  250.  М.: COBeT ское радио, 1975.  834 с.; Уилкинсон, Райнш. Справочник алrоритмов на языке Алrол. Линейная алrебра.  М.: Машиностроение, 1976.  392 с.; Сборник Ha учных проrрамм на Фортране: Пер. с анrл.  М.: Статистика, 1974.  540 с. 
551 18. Решите систему п линейных алrебраических уравнений с Tpe уrольной матрицей коэффициентов 2::)=1 aijXj == b i (i == 1, 2, ..., п) [14]. В данном случае матрица А имеет вид А  ( : а22 О )  а п 1 а пп . Ее надо объявлять так: var А : array[1. .М] of extended; rде т == п( п + 1) /2, а коэффициент aij представляется индексиро ванной переменной А[I *(1  1)div 2+J]. 19. Всем известно решение задачи о волке, козе и капусте [1]. Pe шите задачу о переправе через реку п рабов и п хозяев. Условия переправы таковы: . лодка предназначена только для двух людей; . число рабов не должно превышать числа находящихся с ними хозяев (в противном случае рабы MorYT напасть на хозяев). 20. Напечатайте календарь уууу rода. Заключение Подошло время остановиться. Мы в книrе затронули мноrие аспек ты проrраммирования, но часть из них осталась необсужденной. В некоторых случаях причиной этоrо было оrраничение на объем книrи, но основная часть была опущена умышленно (по алrоритмам и, особенно, по языкам существует немало книr, доступных тем, кто хочет изучать их в большем объеме). Нашей же целью являлось обучение хорошему проrраммированию, а добились ли мы этоrо  судить вам, читатели. 
553 Приложение 1 Приведем блоксхему алrоритма Мише'Н,ъ (см. разд. "OaHOMepn'btf1 массив" 2лавы 3): Начало ОК;ОЛЪ'К:О (Р, n, rl, Т2) kO n, Р, r!, r2 i  1, n, 1 двойная линия, заrоловки, n, Р, r!, r2, линия t  {!; заrоловки, k, двойная линия i> n]  k С1СОЛЪ1СО (Р, n, rl, r2) [ i  n Конец С1СОЛЬ1СО  k Конец Рис. Пl.l. Блоксхема алrоритма Мишень 
554 Она состоит из блоков начала, ввода с клавиатуры, вывода на экран, вызова подчиненноrо алrоритма, конца, обработки, заrоловка цикла с параметром, проверки и комментариев (см. также рис. 1.1, 2.1  2.3 и 3.33.5). Кроме Toro, в описании алrоритма MorYT быть блоки ввода/вывода (обобщенный), принтера и диска, а также соедините ли (для связи разорванных линий потока, принадлежащих данной странице) и межстраничные соединители (рис. П1.2). ввод/ ВЫВОД диск 6 Q соединители Рис. Пl.2. Элементы блоксхем принтер 6 9 межстраничные соединители Блоки MorYT нумероваться. Номера проставляются слева вверху, в разрыве контура блока, прописными буквами и/или цифрами. Име нами соединителей MorYT быть буквы и числа, к примеру, номера блоков или номера страниц. Блоксхемы rромоздки, но зато наrлядны. При пошаrовой детализа ции можно привлекать и друrие rеометрические образы, например, "деревья" (рис. П1.3). аJ1rоритм Решенuе уравненuя ах = Ь вещ а, ь, х начаJ10 ввести а, Ь решить уравнение ах = Ь { вывести ответ конец Рис. Пl.З. Решение уравнения ах = Ь  а=О Hya xb/a ь=о a xEI21 xER 
555 п риложение 2 Системы счисления I\.омпьютер может оперировать с числами, записанными в десятич ной, двоичной, восьмеричной и шестнадцатеричной системах счисле ния. Системоi1 с'Ч.ислени-я называется способ наименования и записи чисел. Перечисленные выше системы, в отличие от римской, явля ются позиционными, так как значение (или вес) каждой цифры, BXO дящей в запись числа, зависит от ее позиции в последовательности цифр, изображающих число. Количество различных цифр, исполь зуемых в системе счисления, называется ее основанием. В дес-яти'Ч.ноi1 системе числа записываются следующими десятью цифрами: О, 1, 2, 3, 4, 5, 6, 7, 8, 9. В двои'Ч.ноi1 системе две цифры: О и 1. Ее основание изображается как 10 и читается "один  ноль". Сложение в этой системе выпол няется по правилам О + о == О, О + 1 == 1, 1 + о == 1 и 1 + 1 == 10, а умножение  по правилам О х О == О, О х 1 == О, 1 х О == О и 1 х 1 == 1. Как видим, эти правила предельно просты. Двоичные цифры или, Подруrому, биты (бит  аббревиатура от binary digit) удобно представлять электронными элементами (вентилями, пере ключателями), принимающими два устойчивых состояния: одному из состояний, например, "в1Слю'Ч.ено", можно сопоставить цифру 1, а второму, "въt1Слю'Ч.ено"  О. Цифры восъмери'Ч.ноi1 системы  от О до 7. Эту систему можно ис пользовать для представления символов кодовой таблицы (например, rрафических символов или управляющих символьных констант Си). Для изображения шестнадцатери'Ч.ных 'Ч.исел при меняются цифры от О до 9 и буквы латинскоro алфавита от А до F (табл. П2.1). 
556 Таблица П2.1. Соответствие чисел в системах счисления Десятичное Двоичное Восьмеричное UJестнадцатеричное О О О О 1 1 1 1 2 10 2 2 3 11 3 3 4 100 4 4 5 101 5 5 6 110 6 6 7 111 7 7 8 1000 10 8 9 1001 11 9 10 1010 12 А 11 1011 13 В 12 1100 14 С 13 1101 15 D 14 1110 16 Е 15 1111 17 F 16 10000 20 10 UJестнадцатеричную систему можно использовать так же, как BOCЬ меричную, и при адресации памяти (например, для обращения к областям памяти, для вывода значений указателей и т. п.). Формы представления чисел В любой системе счисления число можно представить либо в eCTe ственной форме (с фиксированной точкой), либо в экспоненциаль ной форме (с плавающей точкой). В форме с фu'Х:сuрован:н,О'fj, mо'Ч'Х:оi1 неотрицательное число х записывается последовательностью цифр aj (i ==  k,  k + 1, .. . , п), разделенных точкой на целую и дробную части х == anan1 . . . ao.ala2 . . . ak rде о::; aj < 10 (i==k, k + 1,..., п), а n i- О. 
557 в фор-ме с nлавающеil то'Чr;,оil это же число имеет вид х == а х 1 ОТ или х == а . 1 ОТ rде показатель степени r называется nор.ядr;,о-м 'Ч исла, а 1 О  OCHOBa ние системы счисления. Число а должно быть представлено в фик сированной форме, порядок r  целое число. Если а Е [1; 10), то чи сло х имеет стандартныil вид (записано в нау'Чноi1 нотации). Если а Е [о; 1), то дробную часть числа называют (в компьютерных Ha уках) MaHmuccoil, а порядок  xapar;,mepucmur;,oil. При а Е [о; 0.1) rоворят, что число х представлено в ненор-мализованно-м виде, а при а Е [0.1; 1)  в нор-мализованно-м. Пример 1 Десятичная константа 7r в фиксированной форме при k == 6 имеет вид 3.141593. Ее стандартный вид  3.141593 х 100, а нормализован ный  0.3141593 х 101. Перевод из p ичной системы в q ичную Обычно из всех систем счисления одна является "своей", а любая друrая  "чужая". Выполним перевод цело,ю 'Числа из своей, ричной системы в чужую, qичную. Цифрами, представляющими число х в qиЧНОЙ системе, будут остатки от последовательноrо деления это ro числа на основание q, записанное в исходной, ричной системе. Последнее частное есть старшая цифра числа. Остальные цифры получаются при записи остатков справа налево. Частное и остатки следует заменить цифрами в системе с основанием q. Пример 2 Представим десятичное число 157 в шестнадцатеричной системе счи сления. Решение 157  144 9 13/ 
558 Остаток 13 представим шестнадцатеричной цифрой D. Torдa 15710 == == 9D 16 . Индексы 10 и 16 указывают систему счисления. Для перевода правильно1:/, дроби из ричной системы в qичную дробь последовательно умножаем на основание q, записанное в ричной си стеме. В процессе перевода перемножаем только дробные части. To rда дробь в qичной системе запишется в виде целых частей произве дений, начиная с первоro. Целые части следует заменить цифрами в системе с основанием q. Пример 3 Переведем десятичную дробь 0.375 в шестнадцатеричную систему счисления. Решение О. 375 х 16  2250 + 375  6 .000 т. е. 0.37510 == 0.616' При изменении основания системы счисления конечная дробь при одном основании может не иметь конечноrо представления при дpy roM основании. Контрольная задача Переведите 157.37510 в восьмеричную систему счисления. Ответ: 235'38' Перевод из qичной системы в p ичную П риведенными выше правилами можно пользоваться для обратно ro перевода чисел из чужой, qичной системы в свою, ричную. To rда все действия должны выполняться в qичной системе. Приведем друrое правило, позволяющее производить действия в своей системе счисления: для получения ричноrо изображения числа Xq==ananl ... ao.ala2... ak== 
559 ==а n Х 10 n +an1 х 10n1 +. . .+ao+al х 101 +a2 х 102+. . .+ak х 10k следует цифры ai (i == k, k + 1, ..., п) и основание 10 заме нить ричными эквивалентами и найти сумму произведений aiqi (i==k, k+ 1, ..., п). Пример 4 Переведем шестнадцатеричное число 9D.6 16 в десятичную систему счисления. Решение 9D.6 16 == (9 х 10 + D + 6 х 101)16 == (9 х 16 + 13 + 6 х 161)10 == == (144 + 13 + 3/8)10 == (157 + 0.375)10 == 157.37510' Контрольная задача Переведите 235'38 в десятичную систему счисления. Ответ: 157.37510' При переводе числа из десятичной системы в двоичную и обратном переводе промежуточной может быть шестнадцатеричная (BOCЬMe ричная) система. Это "усложнение" процесса перевода на практике экономит количество операций. К примеру, для перевода шесm1tад цаmери'тО20 (восъмери'тО20) 'Чuсла в двоичную систему следует за менить каждую шестнадцатеричную (восьмеричную) цифру COOTBeT ствующей двоичной тетрадой (триадой; см. табл. П2.1). При обраm пом переводе двоu'Ч1tое 'Чuсло разобьем на тетрады (триады), начиная от точки влево и вправо, и каждую тетраду (триаду) заменим COOT ветствующей шестнадцатеричной (восьмеричной) цифрой. Пример 5 Переведем десятичное число 157.375 в двоичную систему счисления и обратно. Решение 1 157.37510 == 9D.6 16 == 10011101.0110 == 10011101.0112 10011101.0112 == 10011101.0110 == 9D.6 16 == 157.37510' Решение 2 157.37510 == 235'38 == 0100l1101.011 == 10011101.0112 10011101.0112 == 010011101.011 == 235'38 == 157.37510' 
561 Список u дополнительнои литературы 1. Абрамов С. А. Математические построения и проrраммирова ние.  М.: Наука, 1978.  192 с. 2. Ахо А., Хопкрофт Дж., Ульман Дж. Построение и анализ вычи слительных алrоритмов.  М.: Мир, 1979.  544 с. 3. Варрон Д. Рекурсивные методы в проrраммировании.  М.: Мир, 1974.80 с. 4. Бартеньев О. В. Современный Фортран.  М.: ДИАлоrмиФи, 1998.  400 с. 5. Бартеньев О. В. Visual Fortran: новые возможности.  М.: ДИА лоrмиФи, 1999.304 с. 6. БартеньевО. В. Fortran для CTyдeHTOB.M.: ДИАлоrмиФи, 1999.  400 с. 7. Бартеньев О. В. Фортран для профессионалов. Математическая библиотека IMSL.M.: ДИАлоrмиФи, 2000.448 с. 8. Бердж В. Методы рекурсивноrо проrраммирования.  М.: Маши ностроение, 1983.  256 с. 9. Брудно А. Л., Каплан Л. И. Олимпиады по проrраммированию дЛЯ ШКОЛЬНИКОВ.М.: Наука, 1990.208 с. 10. Брукс Ф. П. Как проектируются и создаются проrраммные KOM плексы.  М.: Наука, 1979.  160 с. 
562 11. Буч r. Объектноориентированный анализ и проектирование с примерами приложений на С++. M.: БИНОМ, СПб.: HeB ский диалект, 2000.  560 с. 12. Ван ТасселД. Стиль, разработка, эффективность, отладка и ис пытание проrрамм.  М.: Мир, 1985.  336 с. 13. Вирт Н. Алrоритмы + структуры данных == проrраммы.  М.: Мир, 1985. 368 с. 14. Вирт Н. Систематическоепроrраммирование.  М.: Мир, 1977.  192 с. 15. Вьюков а Н. В., rалатенко В. А., Ходулев Л. Б. Систематический подход к проrраммированию.  М.: Наука, 1988. 208 с. 16. rласс З. Руководство по надежному проrраммированию.  М.: Финансы и статистика, 1982.  256 с. 17. rрызловв.И., rрызловаТ.П. Турбо Паскаль 7.0. M.: ДМК, 2000. 416 с. 18. rудман С., ХидетниемиС. Введение в разработку и анализ алrо ритмов.  М.: Мир, 1981.  368 с. 19. Дрейфус М., rанrлоф К. Практика проrраммирования на Фор тране.  М.: Мир, 1978.  224 с. 20. Ефимова О. В., Моисеева М. В., Шафрин Ю. А. Практикум по компьютерной технолоrии.  М.: АБФ, 1997. 560 с. 21. ЖитомирскийМ.С., ШелестВ.Д. НАЧАЛА ВЫЧИСЛИТЕЛЬ НОЙ МАТЕМАТИКИ. Введение в численный эксперимент.  СПб.: Издво СПб rTY, 1999.  208 с. 22. Задачи по проrраммированию / С. А. Абрамов, r. r. rнездилова, Е. Н. Капустина, М. И. Селюн.  М.: Наука, 1988.  224 с. 23. Зелковиц М., Шоу А., rэннон Дж. Принципы разработки про rpaMMHoro обеспечения. M.: Мир, 1982. 368 с. 24. Касаткин А. И., Вальвачев А. Н. От Turbo С к Borland С++.  Минск: Вышэйшая школа, 1992. 240 с. 25. Касьянов В. Н., Сабельфельд В. К. Сборник заданий по практи куму на ЭВМ.  М.: Наука, 1986.  192 с. 26. Каханер Д., Моулер к., Нэш С. Численные методы и проrрам мное обеспечение. M.: Мир, 1998. 576 с. 
563 27. КерниrанБ., РитчиД. Язык проrраммирования Си. M.: Финан сы и статистика, 1992.  272 с. 28. Киммел П. Borland С++ 5.  СПб.: BHV, 2000.  976 с. 29. Кирюхин В. М., Лапунов А. В., Окулов С. М. Задачи по информа тике. M.: АБФ, 1996. 192 с. 30. Клатте Р., Кулиш У., Heara М., РацД., Улльрих Х. Pascal  XSC. Язык численноrо проrраммирования.  М.: ДМК Пресс, 2000.  368 с. 31. Кнут Д. Искусство проrраммирования дЛЯ ЭВМ. Т. 1: OCHoBHbre алrоритмы. M.: Мир, 1976. 736 с. Т. 2: Получисленные ал rоритмы. M.: Мир, 1977. 728 с. Т. 3: Сортировка и поиск.  М.: Мир, 1978. 848 с. 32. Кормен т., Лейзерсон Ч., Ревист Р. Алrоритмы. Построение и aHa лиз.  М.: МЦНМО, 2000.  960 с. 33. Культин Н. Б. Проrраммирование в Turbo Pasca17.0 и Delphi.  СПб.: БХВПетербурr, 2000. 416 с. 34. Культин Н. Б. Turbo Pascal в задачах и примерах.  СПб.: БХВ Петербурr, 2000.  256 с. 35. Лавров П. С., Матиясевич Ю. В. Задачи ленинrрадских олимпиад по информатике и вычислительной технике. Л.: ЛМИ, 1988  96с. 36. Линrер Р., Миллс Х., Уитт Б. Теория и практика CTPYKTypHoro проrраммирования. M.: Мир, 1992. 416 с. 37. Лорин r. Сортировка и системы сортировки  М.: Наука, 1983.  384с. 38. Лэнrсам Й., Оrенстайн М., Тэненбаум А. Структуры данных для персональных ЭВМ. M.: Мир, 1989. 304 с. 39. Малоземов В. Н., Певный А. Б. Рекуррентные вычисления.  Л.: ИЗkВО лrу, 1976. 56 с. 40. Марченко А. И., Марченко Л. А. Проrраммирование в среде Turbo Pascal.  Киев.: ВЕК+, 1999. 464 с. 41. Мейер Б., Бодуэн К. Методы проrраммирования. M.: Мир, 1982. Т. 1.  356 с. Т. 2.  368 с. 42. Меткалф М., РидДж. Описание языка проrраммирования Фор тран 90. M.: Мир, 1995. 304 с. 
564 43. Немнюrин С. А. Turbo Pascal.  СПб.: Питер, 2000.  496 с. 44. Немнюrин С. А. Turbo Pascal: практикум. СПб.: Питер, 2001.  256 с. 45. НиверrельтЮ., ФеррарДж., РейнrольдЭ. Машинный подход к решению математических задач.  М.: Мир, 1977.  352 с. 46. Паппас к., Мюррей У. Visual С++6.  Киев.: ВНУ, "Ирина", 2000.  336 с. 47. Пильщиков В. Н. Сборник упражнений по языку Паскаль.  М.: Наука, 1989.  224 с. 48. Подбельский В. В. Язык С++.  М.: Финансы и статистика, 2000.  560 с. 49. Подбельский В. В., Фомин С. С. Проrраммирование на языке Си.  М.: Финансы и статистика, 1999.  600 с. 50. Пол А. Объектноориентированное проrраммирование на С++.  СПб.: Невский диалект, M.: БИНОМ, 1999. 464 с. 51. Рейнrольд Э., Ниверrельт Ю., Део Н. Комбинаторные алrоритмы. Теория и практика. M.: Мир, 1980. 480 с. 52. Рыжиков Ю. И. проrРАММИРОВАНИЕ на Фортране PowerSta tion для инженеров.  СПб.: КОРОНА принт, 1999.  160 с. 53. Соболь И. М. Численные методы МонтеКарло.  М.: Наука, 1973.  320 с. 54. Ставровекий А. Б. Турбо Паскаль 7.0.  Киев.: ВНУ, "Ирина", 2000.  400 с. 55. Страуструп Б. Язык проrраммирования С++.  Киев: ДиаСофт, 1993. Ч. 1. 272 с. Ч. 2. 288 с. 56. Тихомиров Ю. Visual С++ 6: Новые возможности для проrрам мистов.  СПб.: ВНУ, 1999.  480 с. 57. Уэзерелл Ч. Этюды для проrраммистов.  М.: Мир, 1982.  224 с. 58. Фаронов В. В. Турбо Паскаль 7.0 Начальный курс.  М.: Ho лидж, 1997.  616 с. 59. Фаронов В. В. Турбо Паскаль 7.0 Практика проrраммирова ния.  М.: Нолидж, 1997. 432 с. 
565 60. Филичев С. В. Занимательный Basic для старшеклассников и не только... M.: ЭКОМ, 1997.  192 с. 61. Форсайт Дж., Малькольм М., Моулер К. Машинные методы Ma тематическихвычислений. M.: Мир, 1980. 280 с. 62. Фортран 90. Международный стандарт.  М.: Финансы и стати стика, 1998.  384 с. 63. Хинчин А. Я. Цепные дроби. M.: Наука, 1978.  112 с. 64. Хованский А. Н. Приложение цепных дробей и их обобщений к вопросам приближённоrо анализа. M.: rостехиздат, 1956.  208 с. 65. Шафрин Ю. А. Основы компьютерной технолоrии. M.: АБФ, 1997.  656 с. 66. Шелест В. Д., Лыдкин В. М., Елецкий Е. В. Основные системные ресурсы. Методика разработки проrрамм.  Л.: ЛПИ, 1984. 80 с. 67.Шилдт r. Самоучитель С++.СПб.: ВНУ, 1999. 688 с. 68. Шнейдерман Б. Психолоrия проrраммирования.  М.: Радио и связь, 1984. 304 с. 
567 Предметный указатель А Абсолютная величина 246pl 248 С , , 251F,531C Адаптер 476 Адрес 249С, 275С, 303Р, 304С, зззс, 351С, 364Р, 377С, 378С Азбука Морзе 360 Алrебраические кривые 105 107 Алrоритм 19, 25 без параметров 132 "Библиотека" 189 ввода/вывода матрицы 141, 142 выбор алrоритма 511 выделения разряда числа 173 вызываемый 126 вызывающий 126 вычисления арксинуса 43, 56 значения полинома 80 остатка от деления 81, 130 частичноrо произведения 93 частичной суммы 80 1 Буква Р за номером страницы оз начает Паскаль, буква С  Си и F  Фортран. числа 7r 87, 187,549 экспоненты 111113, 1бl164 fepoHa 64, 71, 201, 319Р, 322С, 324F ''rистоrрамма'' 122 rлавный, rоловной 125 ''rрафик'' 120,477,488 'Тенератор случайных чисел" 185 , 186, 247Р, 250С, 257F,258F декларативная часть 23, 133, 292Р, 511 деления с любой точностью 173 Евклида 169, 200 заrоловок 23, 131 "Изоrрамма" 103 имя 23, 25, 126, 131, 513 исполняемая часть 25, 133, 292Р, 515 кодирование 221 "Компьютерный е" 72, 232, 258F линейный 19,41 "Маrический квадрат" 145 надежность 85, 88, 108 нахождения наибольшеrо члена последовательности 80 нелинейный 50, 63 объявление 2325, 130132 подпроrрамма 130 подчиненный 124, 126, 130 преобразования числа в цепную 
568 дробь 166 принцип уточнения 143 произведения матриц 138, 139 процедура 130, 135 разветвляющийся 50 разработка 17, 32, 143 расшифровки цифр числа 173 свойства 20 "Скорость и расстояние" 29, 30 "Сортировка" 180 спецификация имени 134 табулирования 73 тело 131, 132 "Факториал" 96, 198, 318Р, 368Р, 376С, 390F "Фибоначчи" 91 функция 130, 135 ch х 94 ошибок 109 циклический 63 численный 401, 415 Алфавит rреческий 192 Альтернатива 52 Апостроф 280F AprYMeHT 118, 119, 134,246 Арифметика 169 Аттестация 34 Б Байт 333 Бит 333, 555 Блок 263 в проrрамме 291Р в процедуре 291 Р в функции 291Р, 295С, 366Р, 373С, 379С интерфейсный 388F, 390F схемы 42, 5355, 6870, 125, 553, 554 Буква 225, 235 Буль Дж. 237 Буфер, очистка 273С, 276С, 444Р, 451С Бэкус Дж. 13 в Ввод 26, 265, 266Р, 271С, 280F, 458С, 476,519 вещественноrо числа 266Р, 272С, 280F записи/структуры 428431, 448Р, 449Р, 455С, 456С, 465F,466F лоrическоrо значения 281F массива 329Р, 333С, 343F, 344F массивовый 343F матрицы 370Р, 378С, 403Р, 414С надежный вариант 72, 319Р, 322С, 324F неформатный 272С, 280 F порт 271 потоковый 271С, 458С символа 267Р, 272С, 275С, 276С, 278С, 279С, 280F, 281F, 285F, 286F, 452С с клавиатуры 266Р, 271С, 275С, 276С, 280F, 283F список циклический 343F стандартный 265 строки 266Р, 272С, 276С, 279С, 281F, 285F, 286F, 452С управление клавиатурой 267Р управляемый неименованным списком 280F файла 445Р, 446Р, 449Р, 450Р, 453С, 454С, 459С, 463F, 464F, 466Р, 467С, 468F форматный 275С, 283F целоrо числа 266Р, 272С, 275С, 280F, 282F, 284F, 453С 
Вектор 75, 137, 393F, 494 Верификация 35 "Ветвление" 52 Ветвление мноrозначное 55 Ветвь 50 Видеопамять 476 Вирт Н. 12 Возвращение результата процедуры 126, 131, 369Р, 377С, 391393F функции 126, 131, 133, 364Р, 367Р, 373С, 387F "Выбор" 55 Вывод 27, 267Р, 272С, 277С, 282F, 284F, 458С, 476, 519 вещественноrо числа 268271 Р, 272С, 276278C, 282285F, 289F записи/структуры 428431, 449Р, 456С, 465F, 466F лоrическоrо значения 268Р, 271P, 282F285F манипулятор 273С, 274С матрицы 142, 329Р, зззс, 343F, 344F, 392F, 404Р, 415С на принтер 271P, 280С, 283F, 450С, 466468 на экран 267Р, 272С, 277С, 282F, 284F,475 неформатный 267Р, 272С, 282F потоковый 272С, 273С, 458С символа 267Р, 268Р, 270Р, 272С, 276С, 277С, 279С, 282F, 283F, 284F, 285F, 452С список циклический 344F стандартный 265 строки 268Р, 271P, 272С, 275С, 277С, 279С, 280С, 281285F, 452С управляемый неименованным списком 282F файла 445449P, 450456C, 458С, 459С, 463466F,466P, 467Р, 467С, 468F 569 форматный 268270P, 276278C, 284F, 285F, 286289F,453C целоrо числа 268Р, 269Р, 272С, 275С, 282284F Вызов алrоритма 119, 134 макроса 384 модуля 267Р, 271P, 293Р, 294С, 297F, 401Р, 412С, 416F, 417F, 483Р, 488С процедуры 134, 369Р, 377С, 391F функции 119, 133, 367Р, 373С, 385F, 387F, 521 Выражение 22, 258, 301, 515 адресное 340С арифметическое 258 выбор 310Р, 310С, 311F индексное 338С, 340С, 524 константное 228Р, 330332C лоrическое 301303, 521, 522 отношение 51, 301, 521 первичное 258, 301 перенос 260 правила записи 259, 302305, 515517, 521 сцепление 235, 350Р, 354С, 357F Выход из тела цикла нормальный 91,95,316,318 специальный 73, 86, 91, 95, 316, 522 r rраница шдексов 76, 237Р, 327Р, ззос, 341F, 345F верхняя 76, ззос, 341F нижняя 76, ззос, 341F rраф 495, 498 rрафик 116, 475 reHepaTop случайных чисел (rсч) 185, 186, 248Р, 250С, 258F 
570 д Данное 20, 24, 144, 227 арифметическое 20, 21 внешнее, rлобальное, общее 131133 внутреннее 132 входное 28, 144 ВЫХодное 28, 144 динамическое 327, 383С, 416С, 494 комплексное 233, 250С, 257F скалярное 20, 227 составное 76, 326, 418 тестовое 36, 515 тип 20, 227 Дата 49,174,197,219 Дек 498 Деление на нуль 21, 231 нацело 149, 259261 по модулю 259261 Дерево 495, 498 Дескриптор, код форматный 248Р, 268271P, 273С, 275277C, 283289F, 335С Детализация 11, 2731, 56, 143155 Диапазон порядка 232 чисел 228, 232 Дизъюнкция 51, 302 Директива компилятора 228PF, 232Р, 242Р, 297F, 303Р, 328Р препроцессора 244С, 294С, 373С, 384С, 412С Дисплей 475 Длина записи/структуры 424Р, 425С массива 76, ззос строки 237Р, 350Р, 354С, 357F файла 447Р, 455С Драйвер 476 Дробь десятичная 227 правила записи 260 цепная 160 з Заrоловок алrоритма 23, 131 проrраммы 291Р, 294С, 296F процедуры 134, 369Р, 377С, 391F функции 294С, 363Р, 372С, 385F, 386F цикла 315 Задача классификация 32 rеометрическое место точек 101 переборная 173 постановка 31 сrлаживания 81, 212 Запись проrраммы 291Р, 293С, 296F, 532 структура 423Р, 424С, 425F файла 459F Зацикливание 84, 527 Знак специальный 225 Значение начальное 24, 239С, 241, 242Р, 243Р, 244С, 245F, 328Р, 331С, 332С, 336С, 340С, 342F, 420Р, 423Р, 425С, 427F массива 328Р, 330Р, 331С, 332С, 340С, 342F, 343F множества 420Р структуры 423Р, 425С неопределенное 26, 517, 518, 528 
полинома Рп(Х) 249С среднее 543 фиктивное 38, 71, 120 и Идентификатор 199, 226 Импликация 52, 302 Имя 22, 235, 263 выбор 26, 513 дополнительное 263F индексированное 25, 76, 78, 136, 326Р, 328Р, 329Р, ззозззс, 337341C, 341344F, 540, 550, 551 коллизия 200, 366Р, 390F модуля 400 неиндексированное 77, 86 составное, уточненное 422, 423Р, 425С, 426F указателя 336С файла 441 Инвариант цикла, чистка цикла 65, 86, 94, 100, 526 Индекс 76, 86, 136, 338С, 340С, 524, 540 Инициализация 24, 239С, 241, 242Р, 243Р, 244С, 245F, 328Р, 331С, 332С, 336С,340С, 342F,420P,423P, 425С, 427F массива 328Р, 330Р, 331С, 332С, 340С, 342F, 343F множества 420Р структуры 423Р, 425С Интерпретатор 40 Интерфейс 11, 128, 129, 146, 267Р, 293С, 296F, 388F Исключающее или 51, 302 Испытание rраничное 37 571 статистическое 184 Итерация 33, 84, 201 к Кавычка двойная 234, 277 Квадрат маrический 142 Класс 227С, 418 памяти 379С автоматический 381С внешний 372С, 380С реrистровый 382С статический 382С Клуджпроект 129 Кнут д. э. 169, 396 Кодирование 39, 221, 511 алrоритмов линейных 223, 5l5518 подчиненных 362, 529 приемы 509 разветвлений 301, 520 циклов 315, 523 Код форматный 248Р, 268271P, 273С, 275277C, 283289F,335C Команда 25 ввода 26 "ветвление" 52 полная 52 сокращенная 53, 54 возврата 133 "выбор" 55 вывода 27 вызова 134 задержки 173 останова 25, 57 очистки экрана 173 перехода 11, 52, 86 "повторение" 67 с постусловием 70, 86 с предусловием 67, 68, 73, 86 
572 прерывания 73, 86 присваивания 25 простая 25, 52, 86 сложная, серия 25, 50, 52, 55, 6770, 85 "цепочка" 42 Комментарий 25, 226, 292Р, 296F, 532, 533 Компилятор 40 Компьютерный Е: 72, 232, 258F Конец строки 248Р, 445Р, 446Р файла 173, 248Р, 251С, 258F, 282F, 444Р, 445Р,451С, 462F,463F Конкатенация 23, 235, 350Р, 354С, 357F Константа 22, 24, 227, 241Р, 243С, 244F,514 11" 45, 46, 241Р, 243С, 244F, 245F арифметическая 21, 227 беззнаковая 228, 229 вещественная 21, 22, 229, 231, 270Р, 278С, 289F восьмеричная 229, 275С, 277С, 284F, 555, 556 выбор 310Р, зоос, 311F двоичная 555,556 двойной точности 21, 232, 275С, 276F, 283F, 284F десятичная 229, 275С, 555 длинная целая 228, 229, 275С комплексная 21, 233, 250С, 257F лоrическая 22,51,52,233, 271P, 272F, 281F, 301 математическая 243С множество 420Р нетипизированная 242Р, 244С перечисляемая 238Р, 239С, 247Р, 327Р символьная 22, 233, 234, 330Р, 342F строковая 22, 235, 330Р, 331С, 332С, 332F структурная 423Р, 424Р, 425С типизированная 242Р, 244С целая 21, 227229 шестнадцатеричная 229, 275С, 284F, 555, 556 указатель 333341C, 374С, 412416C, 425С Концепция умолчания 14, 70, 239С, 240F, 244С, 260, 274С, 277С, 287F, 292Р, 295С,321Р, 325F, 328Р, 331С, 380С Конъюнкция 51, 302 Коэффициент повторения 245F, 280F, 342F "Куб" 330Р, 332С, 340С, 341С, 343F л Леrкочитаемость 24, 26, 27, 34, 42, 67, 68,72, 133, 143,329, 375С, 511, 513517, 530, 533 Лоrическое произведение 51,302 Лоrическая сумма 51, 302 м Макроопределение 384С Максимум 47,80, 254F, 302С, 306РС, 307F, 345F, 384С,385С Манипулятор 273, 274 Мантисса 230, 557 Массив 75, 326, 327Р, ззос, 341F двумерный 136, 328Р, 329Р, 331С, 332C,341F динамический 327, 412416C длина 76, 424Р записей/структур 423Р, 425С, 427F имен функций 365Р, 376С инициализация 328Р, 330Р, 331С, 
332С, 342F, 343F мноrомерный 328Р, ЗЗОР, 331С, 332С, 342F, 343F множеств 420Р одномерный 75, 327Р, ЗЗОР, ззос, 331С, 342F открытый 364Р пере мен ной длины 329Р произведение элементов 345F размер 137, 326 размерность 326 размещаемый 344F, 392F размещение по "CTpOKaM" 328Р, 332С, 343F, 344F "столбцам" 342F, 343F сечение 345 символьный ЗЗОР, 331С, 342F статический 327, 329Р строковый ЗЗОР, 331С, 332С, 342F, 346349 сумма элементов 345F трехмерный ззоР, 332С, 340С, 341С, 343F указателей 340С на функцию 376С Матрица 137 ввод/вывод 329Р, зззс, 343F, 344F, 370Р, 378С, 392F, 403Р, 404Р, 414С, 415С rлавный элемент 158 единичная 328Р, 332С, 343F кососимметрическая 157 объявление 328Р, 329Р, 332С, 343F ортоrональная 159 произведение 138, 345F, 404Р, 526 седловая точка 214 симметрическая 157 след, шпур 159 соrласованная 342F сцепленная 137 транспонирование 159, 345F "Меню" 267Р, 309, 365Р, 376С 573 Метапеременная 14, 386 Метка 11,20,52, 109,263, 284F, 288F, 291F, 297F, 305, 326, 391F, 463F, 514, 533 Метод бисекций 406Р Веrстейна 406Р raycca вычисления интеrрала 407Р решения системы 408Р rауссаЗейделя 409Р, 416С замещения 408Р МонтеКарло 184 неопределенных коэффициентов 214 обсуждения проекта 36 проrонки 410Р ручной прокрутки 36, 154 сверху вниз 11, 124, 143 "сжатuераст.яже1tuе" 113 степенной, Мизеса 411Р, 412Р юrовосток 144 Минимум 47, 80, 254F, 345F, 384С Множество 418 точек плоскости 101 Множитель масштабный 287F Моделирование 188 Модель 32, 77, 107, 188, 523 Модуль 400Р, 412С, 416F подключение 267Р, 271Р, 293Р, 294С, 297F, 401Р, 412С, 416F, 417F rрафическоrо модуля 478Р, 483Р, 488С н Неэквивалентно 52, 302 Нод(т, п) 169,200,548 Нок (т, п) 548 Норма вектора 83 
574 матрицы 157 159 Нультерминатор 239С, 273С, 351С, 352С, 354С, 356С, 378С, 452С о Область действия 366Р, 379С, 390F допустимых значений 126, 530 критическая 139, 526, 531 Обработка исключительной ситуации 37, 228 Обращение к алrоритму 119, 134 к модулю 267Р, 271Р, 293Р, 294С, 297F, 401Р, 412С, 416F, 417F, 483Р, 488С к процедуре 134, 369Р, 377С, 391F к функции 119, 133, 367Р, 373С, 385F, 387F, 521 Объединение 432С Объявление 24 внешнеrо имени 389F внутренней функции 118, 385F, 390F записи/структуры 423Р, 424С, 426F массива 76, 327329P, 330332C, 341343F начальноrо значения 24, 239С, 241, 242Р, 243Р, 244С, 245F, 328Р, 331С, 332С, 336С, 340С, 342F, 420Р, 423Р, 425С, 427F массива 328Р, 330Р, 331С, 332С, 340С, 342F, 343F множества 420Р структуры 423Р, 425С неявное 24F, 240F, 513F переменной 24, 236238P, 238240C, 240F, 241F предварительное 294С, 370Р, 373С, 380С процедуры 369Р, 377С, 390F спецификаций 131 формата 27, 288F функции 362Р, 372С, 385F, 386F, 390F явное 240F, 241F Окруrление 231, 269Р Операнд 23 Оператор ввода 266Р, 272С, 275С, 280F, 284F, 445Р, 447Р, 450Р, 452С, 453С, 454С, 463F возврата 316, 367Р, 373С, 374С, 377С, 387F, 391F, 522 выбора 310РС, 311F вывода 267Р, 272С, 277С, 282F, 284F, 445Р, 447Р, 450Р, 452С, 453С, 463F выполняемый 262 задержки 290 закрытия файла 443, 444Р, 451С, 462F записи в поток 272С извлечения из потока 272С инициализации rсч 186, 248Р, 250С, 258F невыполняемый 262 останова 290 открытия файла 442, 444Р, 446Р, 450С, 458С, 460462F очистки буфера 276С, 444Р, 451С экрана 267Р, 275С, 297F паузы 290F перехода 305, 444, 522 подключения модуля 267Р, 271Р, 293Р, 294С, 297F,401P,412C, 416F, 417F прерывания 311, 316, 522 присваивания 262265, 328Р, 517 присоединения 424Р продолжения 316, 522 
простой 262 процедуры 369Р, 377С, 391F пустой 262, 291, 528 расширения файла 445Р сложный 262 смещения указателя 447Р, 455С, 457С, 462F составной 262, 306 условный 306, 307F, 420, 521, 522, 524, 533 формата 284F, 288F. 296F цикла 315326, 523 эквивалентности 393F Операция аддитивная 21, 259 адресная 249С, 275С, 303Р, 304С, 334С, 377С арифметическая 259, 516 базовая 494, 497 битовая зозс, 304С взятия, нахождения остатка 47, 81, 133, 249С, 255F, 259 в степени 249С, 259261 декремента 265 деления 259 нацело 149, 259261 по модулю 47, 81, 133, 249С, 255F, 259 двуместная 259 запятая 304С, 323С индексации 303, 339  инкремента 265 массивовая 328Р, 343F, 345F мультипликативная 259 конкатенации, сцепления 235, 350Р, 354С, 357F лоrическая 51,52, 302 над множествами 420 над указателем 336С, 337С одноместная 259, 521 отношения 51,301, 521, 522 постфиксная 265 575 префиксная 205 приоритет 260, 303305, 425С, 521 разадресации, разыменования 335С, 377С, 378С сдвиrа 259, 303Р, 304С точка 422, 424Р, 425С, 425F трехместная 259, 302С, 384С, 385С условная 302С Описание опережающее 370Р прототип 294С, 373С, 380С Отладка 33,40,41,518 Отношение 51, 301, 521, 522 Отступ 268, 533 Отрицание 51, 302, 521 Отчет 38,41 Очередь 498 Ошибка 21, 29, 34, 35, 230, 231 ввода 276С, 282F, 444Р, 451С, 452С, 458С, 461F, 520 в имени 227, 235, 394, 441, 513 в индексе 327Р в комментарии 532 в лоrическом выражении 302, 303, 521,522 в подпроrрамме 373С, 531, 532 в присваивании 264Р, 327, 352С, 518, 519 в разветвлении 520, 522 в формуле 261, 384С, 515517 в цикле 84, 85, 316, 317, 527, 528 вывода 276С, 288F, 289F, 520 наведенная 519 на единицу 528 объявлений 240, 318, 329Р, 514, 528 окруrления 90, 230, 231 переполнения 318 семантическая 40, 261 синтаксическая 40, 264 усечения 74,230 формата 268Р, 269Р, 277С, 289F 
576 п Память 174 динамическое выделение 337С, 338С, 383С, 412С, 498 "куча" 383С, 495 Параметр 126, 131 входной/выходной 31, 126, 131 530,531 передача по адресу, ссылке 135, 363Р, 364Р, 373С, 387F по значению 135, 363Р, 373С процедурный 131, 363Р, 365Р, 389F фактический 118, 134, 363Р, 367Р, 373С, 387389F формальный 118, 131, 341С, 363Р, 366Р, 372С, 385391F, 530, 531 функциональный 131, 363Р, 365Р, 375С, 376С, 389F цикла 63,65,66,84, 100,315,316, 320Р, 323С, 325F, 514, 523 Переменная 22, 235 автоматическая 381С буферная 292Р вещественная 24, 236Р, 238С, 240F внешняя, rлобальная, общая 119, 132, 331С, 366Р, 379С, 380С, 392F, 531 внутренняя 132, 366Р, 371Р, 379С, 381С, 387F динамическая 337С, 383С записная/структурная 421, 423Р, 424С, 426F, 495 комплексная 238С, 240F лоrическая 24, 236Р, 238С, 240F, 302С локальная 132, 366Р, 379С, 386F простая 25, 77, 86, 226Р, 236Р, 238С, 240F,494 реrистровая 382С символьная 24, 236Р, 239С, 240F с индексом 25, 76, 78, 136, 326Р, 328Р, 329Р, 330333C,337C, 338341C, 341344F, 540, 550, 551 статическая 382С строковая 24, 237Р, 239С, 241F указатель 333341C, 374С файловая 364Р, 441, 442, 443Р, 450С, 459F целоrо типа 24, 236Р, 238С, 240F Перенос части выражения 260 строки текста 245F, 263F, 296F Переполнение порядка 231, 232, 319 целочисленное 228, 318 Пиксел 475 "Повторение" 67 Подпроrрамма 130, 362Р, 372С, 385F, 476, 483, 529 без параметров 371Р внешняя 371Р внутренняя 371Р, 385F, 390F рекурсивная 368Р, 376С, 390F, 530 Поле вывода 268271P, 277С, 278С, 285F Полиморфизм 516 Полином Лаrrера 58, 81, 203 Лаrранжа 415 Лежандра 537 отделение корней 83 правило [орнера 523 функция 249С Чебышёва 74, 202, 210, 545 Эрмита 203 Порт ввода/вывода 271 Порядок выравнивание 261, 516 лексикоrрафический 178 
разработки алrоритма иерархический 129 комбинированный 129 операционный 128 следования разделов 292Р числа 230, 232, 557 Последовательность бесконечная 86 Фибоначчи 90 Постусловие 65, 66, 71, 317Р, 321С, 324F Правило ijklmn 240 Джексона 513 fopHepa 43, 56, 80, 202, 523 замены массивов 524 перевода чисел 557, 558 выполнения команды "повторение" 69 рельефа 533 умолчания 14, 70, 239С, 240F, 244С, 260, 274С, 277С, 287F, 292Р, 295С, 321Р, 325F, 328Р, 331С, 380С Предложение 23, 25, 50, 130, 131, 296F Предусловие 65, 67, 319Р, 320Р, 322С, 323С, 324F, 325F Преобразование типа 246Р, 250С, 256F, 257F, 336С, 516 Препроцессор 293С, 294С, 383С Префикс 275С, 383С Приближение экспоненты полиномиальное 112 рациональное 112 Принцип КISS 39 локализации 366Р, 367Р, 379С Присваивание 2426, 517 имени подпроrраммы 365Р источник 25, 265, 352, 518 массивовое 329Р, 345F 577 мишень 25, 265, 352, 518 MHorOKpaTHoe 264 структурное 422, 423 Проверка проекта 34 верификация 35 тестирование 35, 37 Проrрамма 19, 27, 512 BS 11, 132,380,522 "Ввод/вывод вектора" 403Р, 414С "Ввод/вывод вещ, симв и строк данных" 267Р, 272С, 276С, 281F, 285F "Ввод/вывод матрицы" 329Р, зззс, 344F, 370Р, 392F, 403Р,404Р, 414С, 415С "Вечный цикл" 527С, 528Р "Вещественные типы" 243Р "Внешняя переменная" 380С "Встраиваемая функция" 384С выдача результатов 41 выполнение 39 "fepoH" 319Р, 322С, 324F "fлобальный/локальный" 371Р, 381C,392F "fрафик" 478Р, 488С "Длинный список форматов" 277С "Жесткая реакция Фортрана" 289F "Закон" 282F "Законы эколоrии" 279С, 288F запись 291Р, 293С, 296F, 532 "Инвертирование строки" 351Р, 356С, 357F "Календарьвыбор" 312Р, 312С, 313F "Календарьесли" 307Р, 308С, 309F классификация 39, 40 "Конецошибка" 282F "Копирование строки" 378С леrкочитаемость 24, 26, 27, 34, 42, 67,68,72, 133, 143, 329, 375С, 511, 513517, 530, 533 "Макросы" 384С 
578 "Меню" 267Р, 309, 365Р, 376С надежность 24, 27, 72, 85, 86, 88, 108, 127, 238Р, 240F, 319Р, 322С, 324F, 388F, 423,511, 513, 527 "Нахождение остатка" 368Р, 369Р, 374С, 377С, 388F, 391F "Наша первая проrрамма" 223, 224 "Нравоучение" 453С "Односвязный список" 499С "Операторная функция" 386F оптимизация 42, 511533 "Переименование книrи" 298РС, 299F "Платежная ведомостьмассив" 346Р, 347С, 348F "Платежная BeДOMOCTЬCTpYKTypa" 427Р, 429С, 430F "Подсчет различных цифр числа" 421Р "Поэма" 281F правильная 34, 38 "Примитивные ошибки" 242Р "Принтер" 283F "Размер книrи" 446Р, 454С, 458С, 463F "Размещаемый массив" 344F "Скорость и расстояние" 292Р, 295С, 297F "Статическая переменная" 382С стиль 13,511,513 "Текстовый файл" 466Р, 467CF "Тестирование численных методов" 401Р,412С "Транслятор" 448Р, 455С, 464F "Указатели" 335С, 337С, 338С универсальность 27, 28, 77, 85, 127, 132, 145,241,329,333,344, 375С, 378С, 495, 511, 527, 530 "Факториалрекурсия" 368Р, 376С, 390F "Форматы вещ данных" 270Р, 278С, 288F "Функциональный параметр" 365Р, 369Р, 375С, 389F характеристики 27 эффективность 27, 30, 43, 77, 86, 104,108,111,119,139, 164, 179, 183, 185, 202, 243Р, 334С, 356С, 364Р, 377С, 380С, 392F, 400, 420Р, 443,494,511,512,516,517, 519521, 524531 Проrраммирование 10, 27, 31, 90, 359 ветвлений 50, 301 "закон" 9, 10, 13, 3439, 42, 44, 73,85,86,90, 119, 124, 130, 132, 133, 143, 154, 155, 183, 201, 241, 332, 358360, 397, 399, 512, 513, 517,519,520,522,526,527,529, 530, 532, 535, 540, 547 повторений 63, 315 подчиненных алrоритмов 124,362 сверху вниз 11, 143 структурное 11, 522 формул 41, 259262 Проrраммист 10, 12,21,32,33,35,36, 38,40,41,43,84, 155,231,235,237, 260, 261, 293, 311, 353, 388, 424, 513, 515,517,521,522 Произведение бесконечное 93 Прокрутка 36, 154 Прототип 294С, 373С, 380С Процедура 130, 369Р, 377С, 390F, 529 вызов 369Р, 377С, 391F Процент 277 Псевдокод 10, 23, 34, 42, 44, 52, 53, 55, 57, 67, 69, 70 р Разветвление 50, 301, 520 Раздел объявлений 262, 291Р, 296F, 365Р, 
386F, 387F, 391F операторов 291Р, 294С, 296F, 367Р, 386F, 387F, 391F Разделитель 226 PaHr операций 260, 303305, 425С, 521 типов 228, 232, 260 Расшифровка 173 Рекурсия 198, 368Р, 376С, 390F, 426, 530 шубина 198, 199, 531 Ритчи Д. 12 Ряд степенной 64, 107, 111 с Сечение золотое 98, 166, 202 массива 345 Сиrнум 58, 258F Символ двойная кавычка 234С, 277С продолжения строки текста 245F, 263F,297F процент 277С пустой 226 специальный 225 управления кареткой 287F, 520 управляющий 233, 234С, 272С, 287F Система счисления 555 восьмеричная 555, 556 двоичная 555, 556 десятичная 555, 556 основание 555 перевод чисел 557, 558 позиционная 555 шестнадцатеричная 555, 556 Эло 544 Ситуация исключительная 37, 261, 579 522, 530 Скобка квадратная 326, 327, 330, 331 командная 54, 71, 132, 318Р, 320Р круrлая 245F, 260, 261, 306С, 307F, 310С, 311F, 321323C, 325F, 326, 328P,341F, 343F, 384С,425С, 426С, 515, 519, 521 множественная 418Р, 419Р операторная 224, 262, 291, 295С, 318Р, 320Р, 522, 527, 533 фиrурная 224С, 226Р, 239С, 262С, 263С, 291С, 295С, 310С, 322С, 323С, 331С, 332С, 372С, 376С, 424С, 425С Словарь языка 226 Слово длинное 333 зарезервированное 226 ключевое 23, 226 Сложность 32 Сортировка 178 метод Дж. фон Неймана 192 Спецификатор типа 238С, 375С Список ввода 266Р, 272С, 275С, 280F вывода 268Р, 272С, 277С, 282F, 284F, 519, 520 двусвязный 496 значений 131 кольцевой 496 односвязный 496, 498 параметров 127, 131, 363Р, 371Р, 372С, 387F результатов 131, 136, 364Р, 373С, 377C,387F, 391F,392F структура линейная 495С нелинейная 495С фактических параметров 118, 134, 367Р,369Р, 373C,385F, 387F, 391F формальных параметров 118, 131, 
580 132, 363365P, 369Р, 372С, 374С, 385F, 386F, 391F, 530, 531 формата 275277C, 284F циклический 281, 343F, 344F Сравнение 51, 302, 521, 522 Среднее значение 81 арифметическое 543 rармоническое 543 rеометрическое 543 квадратическое 543 Стек 200, 373С, 379С, 531 структура данных 497 Стиль проrраммирования 511, 513 Стрелка Пирса 542 Строка форматная 275С, 277С, 284F продолжения 296F, 297F сцепление 235, 350Р, 354С, 357F Структура 421427 данных 75, 135, 136, 202, 326, 418Р, 441,494,524 запись 423Р, 424С, 425F проrраммы 291Р, 293С, 296F, 532 Суффикс 229С, 232С, 248С Схема ropHepa 43, 56, 80, 202, 523 операционная 125 функциональная, иерархии 11, 125, 126 Счетчик, параметр цикла 63,65,66, 84, 100,315,316, 320Р, 323С, 325F, 514, 523 т Таблица 73, 107 кодов 233, 357 Текст 495, 498 Тело макроса 384С процедуры 369Р, 377С, 391F функции 294С, 364Р, 372С, 385F, 387F цикла 65, 317, 319Р, 323С, 325F, 528 Тестирование 33, 3538, 57, 78, 92, 95, 104, 110, 121, 129, 140, 154, 164, 182, 515, 522, 530 исключительная ситуация 37, 57, 156, 261 условие нормальное 37 экстремальное 37,57, 156 ТеХ 41, 396 Тип 20, 22, 227, 235, 236 базовый 76, 327Р, 418Р, 420Р беззнаковый 228, 238 вещественный 24, 227, 232, 236Р, 238С, 240F встроенный 227 двойной точности 24, 232, 236Р, 238С, 240F, 241F диапазонный 227, 237Р, 238Р, 419Р длинное целое 228, 236Р, 238С, 240F записной/структурный 227, 423Р, 424С, 425F индекса 327Р класс 227 комплексный 227, 233С, 238С, 240F, 250С, 257F лоrический 24, 227, 236Р, 238С, 240F, 301С массивовый 227, 326Р множественный 227, 418Р объединение 227 объектный 227 одинарной точности 232, 236Р, 238С, 240F основной 227 перечисляемый 227, 237Р, 238Р, 239С подпроrраммнЫЙ 227, 365Р, 375С, 389F 
порядковый 227, 236Р, 419Р преобразование 246Р, 250С, 254F, 256F, 336С, 516 производный 227 простой 227 процедурный 363Р, 365Р, 374С, 375С, 389F пустой 227 рекурсивный 386F, 390F символьный 227, 236Р, 238С, 240F, 267Р, 272С,276С, 285F скалярный 227 составной 227 строковый 227, 237Р, 239С, 241F, 267Р, 272С, 276С, 285F указатель 227, зззс файловый 227, 443Р, 450С, 460F функциональный 363Р, 365Р, 369Р, 374С, 375С, 389F целый 24, 227, 228 элементов 327Р Тождество, эквивалентно 52, 302 Точка вызова 133, 367Р, 373С, 377С, 387F контрольная 36, 38, 41, 44, 75, 89, 95, 110, 129, 140, 155, 164 операция 422, 424Р, 425С, 425F с запятой 263, 528 Точность представления 230, 231 Транслятор 40 интерпретатор 40 компилятор 40 Трассировка 41,522 Треуrольник Паскаля 214 у Указатель 249С, зззс, 425С на объект 334С на функцию 334С, 372С, 374С 581 нулевой 336, 451 файловый 442, 447Р, 457С, 462F Универсальность 27, 28, 77, 85, 127, 132, 145, 241, 329, 333, 344, 375С, 378С,495, 511, 527, 530 Управление вертикальное 127 форматное 286F Ускорение свободноrо падения 24, 46 Условие 5052, 65, 68, 85, 301, 315, 521 простое 51 составное 51 Устройство лоrическое 441 ф Файл 265, 364Р, 441, 443Р, 450С, 459F буфер 444Р, 451С внешний 459F внутренний 460F двоичный 443Р, 451С, 460F доступ последовательный 442, 460F прямой 442, 457С, 460F заrоловочный 243С, 248С; 250С, 271С, 273С, 279С, 290С, 293С, 294С, 352С, 355С, 458С закрытие 443, 444Р, 451С, 462F кода 293С компонент 441 конец 173, 248Р, 251C, 258F, 274С, 282, 369, 377, 445, 446Р, 451С, 459, 462F, 46ЗF, 498 нетипизированный 443Р, 449Р открытие 442, 444Р, 450С, 458С, 460F контроль 447Р, 453С, 454С, 459С, 464F переменная файловая, указатель на 
582 файл, номер устройства 265, 442, 460 размер 447Р режим доступа 450С, 461F стандартный, предопределенный 248Р, 251С,265, 280, 442, 446Р текстовый 443Р, 450С, 460F типизированный 443Р, 447Р указатель файловый 442 Факториал 96 большоrо числа 46 двойной 96, 203 ошибки вычисления 318 Флажок 146, 180, 182, 401Р, 402Р, 414С,530 в списке форматов 277С Форма Маккарти 198, 201 Формат 29, 38, 75, 259 rруппа 284F, 286F локальный 288F неявно заданный 268Р переменный 270Р, 273С, 285F с плавающей точкой 270Р, 274278C, 284289F с фиксированной точкой 269Р, 275С, 284F удаленный 288F, 296F управления 286F явный 268Р, 273276C, 284F Форматирование в потокоориентиро ванной передаче 273С, 274С, 413С Формула Бине 46 Броункера 166 Валлиса 99, 207 Виета 100, 548 вычисления нок(т, п) 548 обратной величины 96 среднеrо значения 543 степени 205, 206, 545 raycca 45 запись 259262, 515518, 521, 522 корень квадратный из комплексноrо числа 206 Лаrранжа 97, 415С Ламберта 167 Мэшина 99 Ньютона 97 Ньютона Рафсона 64 понижения степени 59 приведения 113 Рамануджана 167, 207 рекуррентная 64, 86, 88, 90, 93, 95, 108,111,162,165,173,185,523, 527 синтаксическая 14 сложноrо радикала 45 Стирлинrа 46 ТейлораМаклорена 111 удвоения 87 Функция 362Р, 372С, 385F, 386F, 529 АккерманаПетера 204 Бесселя 64, 204, 209, 545 внешняя 371Р, 380С, 386F внутренняя 118, 371Р, 385F, 390F встраиваемая 385С встроенная, стандартная 44, 246Р, 247Р, 248251C, 251258F,345F, 349З57 вызов 119, 134, 367Р, 373С, 387F, 531 rаммафункция 209 rрафик 116, 475 конец строки 248Р, 445Р, 446Р файла 248Р, 251С, 258F, 274С, 445Р, 451C,462F, 463F максимум 254F, 384С, 385С массивовая 345F минимум 254F, 384С, операторная 118, 130, 385F Крылова 543 Куммера 209 Неймана 203 
ошибок 107, 109 прототип 294С, 373С, 380С размер 248Р, 250С, зозс, ззос, 332С, 336340C, 424Р, 425С рекурсивная 198, 368Р, 376С, 386F, 390F сиrнум 58, 258F строковая 349Р, 351С, 356F табулирование 73, 107, 111 факториальная 96, 198,318 ц "Цепочка" 42 Цикл 63, 315, 523 арифметический 63, 73, 95, 102 бесконечный 65, 68, 317, 321Р, 323С, 324F, 326F вложенный 100, 524 внешний 100, 102 внутренний 100, 102 выход нормальный 91, 95, 316, 318 специальный 73, 86, 91, 95, 316, 522 двойной 101, 329Р, зззс, 344F заrоловок 100,303, 317Р, 321С, 324F, 343F итеративный 64, 84, 85, 88, 107 кодирование 315, 523528 кратный 100, 317 объединение 525 параметр 63, 65, 66, 84, 100, 315, 316, 320Р, 323С, 325F, 514, 523 развертка 523, 524 разъединение 525 с параметром 63, 68, 316, 317, 320Р, 323С, 325F, 523 с постусловием 65, 66, 86, 315, 317Р, 321С, 324F, 523 583 с предусловием 65, 66, 86, 315, 317, 319Р, 320Р, 322С, 323С, 325F, 523 структура, строение 65 тело 65, 317, 319Р, 323С, 325F, 528 тройной 138 чистка 65, 86, 94, 100, 526 Цифра 225 ч Чебышёв П. Л. 174 Число 21,227,229,233 7r 45,89,99, 100, 166, 188,207,230, 241Р, 243, 244CF, 245,548, 549 автоморфное 177 ApMcTpoHra 176 беззнаковое 228, 229, 275С Бернулли 207 вещественное 21, 229, 269Р, 275С, 277С, 284F, 285F восьмеричное 229, 234, 275С, 284F, 555, 556 двоичное 229, 555, 556 двойной точности 21, 232, 240F, 241F, 275С,276С, 284F десятичное 229, 275С диапазон чисел 228, 232 длинное целое 229, 275С дружественное 177 естественная форма 228, 229, 269Р, 275С, 284F, 556 кардинальное 76, 420Р Каталана 207 комплексное 21,233 лоrическое 21, 233 мантисса 229, 557 Мерсенна 176 мноrозначное 178 научная нотация 230, 268Р, 274С, 557 Непера 98, 208, 242 
584 нормализованное 230, 557 пар ное 176 Пифаrора 215 порядок 230, 232, 557 размещений 203 случайное 185, 247Р, 249С, 258F совершенное 170 сочетаний 203 с плавающей точкой 229232, 270Р, 276С, 284F, 557 с фиксированной точкой 228, 229, 269Р, 275C,284F, 556 факториальное 46, 96, 203, 318 фибоначчйево 46,91,202 целое 21, 227 количество цифр 228, 232 шестнадцатеричное 229, 275С, 284F, 555, 556 Эйлера 24, 98, 208 ЭйлераМаскерони 98 экспоненциальная форма 229232, 270Р, 276С, 284F, 557 Чистка цикла 58, 80, 88, 94, 512 ш Шаблон rрафический 485 записной/структурный 227, 423Р, 424С, 425F Ширина поля вывода 268270P, 273С, 277С, 285F, 335С Штрих Шеффера 542 э Эйлер Л. 208, 504 Эквивалентно, тождество 52, 302 Элемент записи/структуры 422, 424Р, 425С, 426F, 427F массива 25, 76, 78, 136, 326Р, 328Р, 329Р, 330333C, 337С, 338341C, 341344F,540, 550, 551 множества 419421P списка 495 файла 441 формата 248Р, 268271P, 273С, 275277C, 283289F, 335С Эффективность 27,30,43,77,86, 104, 108, 111, 119, 139, 164, 179, 183, 185, 202, 243Р, 334С, 356С, 364Р, 377С, 380С, 392F, 400, 420Р, 443,494, 511, 512, 516, 517, 519521, 524531 Эффект побочный 11, 126, 132, 135, 363Р, 367Р, 369Р, 366С, 387F, 521, 530, 531 Эхопроверка 44, 88, 94, 102, 119, 162, 180,519 я Язык проrраммирования 12, 39, 221 Ada 12, 22 Modu\a 12, 22 PL/M 22, 24 Бейсик 40, 394 Паскаль 12, 223 Си 12,223 Фортран 13, 223 проектирования 23 блоксхемы 42, 5355, 6870, 125, 553, 554 псевдокод 10, 23, 34, 42, 44, 52, 53, 55,57,67,69,70 Ящик 370Р "черный" 127