Основы программирования Тишин В. И. 2002 год

advertisement
Тишин В. И.
Основы программирования
Программирование в интегрированных средах
Turbo Pascal 7, Borland Pascal for Windows
ЧАСТЬ 1
Для преподавателей, студентов, учащихся
2002 год
2

Учебно-методическое пособие "Паскаль. Основы программирования"
рекомендовано к изданию Постановлением Ученого Совета физикоматематического факультета Брянского государственного педагогического
института им. академика И. Г. Петровского (протокол № 5 от 8 февраля 1993
года).
Рецензенты
Доцент Брянского пединститута, кандидат физико-математических наук
Макаров С. А.
Зав. кабинетом информатики Брянского областного института переподготовки педагогических кадров Агалаков В. Г.
3

Содержание
Глава 1. Структура программы на языке "Паскаль" ..................................................................8
2. Переменные и их имена ......................................................................................................11
Замечания ....................................................................................................................... 11
3. Команда присваивания........................................................................................................12
4. Операторы write и writeln. Процедуры вывода информации ..........................................12
5. Операторы read и readln. Процедуры ввода информации ...............................................14
Глава 2. Ввод и выполнение программ .....................................................................................16
Режим вставки ................................................................................................................. 17
Режим наложения ........................................................................................................... 18
Режим автоотступа.......................................................................................................... 18
Команды редактирования ............................................................................................... 19
Работа с блоком .............................................................................................................. 19
Выполнение программы.................................................................................................. 19
Первые ошибки и их исправление ................................................................................. 21
Запись файла на диск ..................................................................................................... 22
Построчная запись текста программы ........................................................................... 23
Задание............................................................................................................................ 24
2. Программирование в среде Microsoft Windows на языке Pascal.....................................24
Глава 3. Арифметические операции с целыми числами. Переменные целого типа.
Условный оператор if...then...else ... Вещественный тип (real) ...............................................30
1. Арифметические операции с целыми числами и переменными целого типа в языке
Паскаль .....................................................................................................................................30
2. Операции отношения или сравнения.................................................................................30
3. Логические операции ..........................................................................................................31
4. Комментарии ........................................................................................................................33
Задание 1......................................................................................................................... 35
5. Оператор if ... then ... else ....................................................................................................35
Задание 2......................................................................................................................... 37
6. Вещественный тип real в операторах if ... then ... else ... . ................................................37
7. Формы записи вещественных чисел ..................................................................................37
8. Арифметические операции с вещественными переменными .........................................38
9. Форматированный вывод информации .............................................................................41
Задание 3......................................................................................................................... 42
10. Блок-схемы, изображающие условные операторы ........................................................42
Задание 4......................................................................................................................... 44
Упражнения..............................................................................................................................44
Ответы ......................................................................................................................................44
Глава 4. Операторы организации цикла. Цикл "пока...". Оператор while ... do ... . Оператор
перехода goto. Метки ..................................................................................................................46
1. Что такое цикл?....................................................................................................................46
Задание 1......................................................................................................................... 48
2. Целый тип longint ................................................................................................................50
Задание 2......................................................................................................................... 51
3. Условия в программах с циклами ......................................................................................52
3. Досрочное прерывание цикла. Метка. Оператор безусловного перехода goto ............55
Замечания ....................................................................................................................... 56
Задание 3......................................................................................................................... 57
4. Циклы в циклах....................................................................................................................57
Задание 4......................................................................................................................... 59
Упражнения ..................................................................................................................... 59
Ответы ............................................................................................................................. 60
4

Глава 5. Цикл с последующим условием. Оператор repeat...until... ....................................... 62
2. Различия между циклом - while и циклом - repeat........................................................... 65
Задание 1 ........................................................................................................................ 66
3. Программы с совместным использованием циклов repeat и while ... do ... ................... 66
Задание 2 ........................................................................................................................ 67
4. Разные задачи ...................................................................................................................... 67
Задание 3 ........................................................................................................................ 69
Задание 4 ........................................................................................................................ 73
Задание 5 ........................................................................................................................ 76
Задание 6 ........................................................................................................................ 77
Упражнения ..................................................................................................................... 77
Ответы ............................................................................................................................. 79
Глава 6. Циклы с параметрами. Операторы for...to...do... и for...downto...do... ..................... 81
2. Оператор цикла for...downto...do... .................................................................................... 82
Задание 1 ........................................................................................................................ 83
Задание 2 ........................................................................................................................ 84
Задание 3 ........................................................................................................................ 87
4. Разные задачи ...................................................................................................................... 88
Задание 4 ........................................................................................................................ 89
Задание 5 ........................................................................................................................ 90
Задание 6 ........................................................................................................................ 93
5. Преобразование типов ........................................................................................................ 93
Задание 7 ........................................................................................................................ 94
Упражнения ..................................................................................................................... 94
Ответы ............................................................................................................................. 95
Глава 7. Подпрограммы на паскале. Процедуры и функции. Рекурсия ................................ 98
Задание 1 ...................................................................................................................... 104
Задание 2 ...................................................................................................................... 108
Вызов процедуры из процедуры .................................................................................. 112
Задание 4 ...................................................................................................................... 114
Задание 5 ...................................................................................................................... 116
Задание 6 ...................................................................................................................... 118
Упражнения ................................................................................................................... 118
3. Рекурсия ............................................................................................................................. 119
Задание 7 ...................................................................................................................... 122
Задание 8 ...................................................................................................................... 124
Задание 9 ...................................................................................................................... 126
4. Функции ............................................................................................................................. 127
Задание 1 ...................................................................................................................... 132
Применение ряда Фибоначчи .............................................................................................. 132
Задание 2 ...................................................................................................................... 137
5. Задачи с применением НОД ............................................................................................ 138
Задание 4 ...................................................................................................................... 142
6. Решение уравнений с одной переменной методом половинного деления ................. 143
Задание 4 ...................................................................................................................... 147
7. Вычисление корней уравнения нахождением минимума функции на промежутке .. 148
Задание 5 ...................................................................................................................... 149
Библиотека часто встречающихся процедур и функций ............................................ 150
Повторение ................................................................................................................... 163
Упражнения ................................................................................................................... 164
Ответы ........................................................................................................................... 165
Глава 8. Элементы комбинаторики ......................................................................................... 175
1. Размещения ....................................................................................................................... 175
Задание 1 ...................................................................................................................... 178
Задачи, решаемые с помощью размещений ............................................................... 178
Задание 2 ...................................................................................................................... 181

5
Упражнения ................................................................................................................... 181
2. Перестановки .....................................................................................................................181
Задание 3....................................................................................................................... 182
3. Перестановки с повторениями .........................................................................................182
Задание 4....................................................................................................................... 183
4. Сочетания ...........................................................................................................................184
Задание 5....................................................................................................................... 186
5. Сочетания и бином Ньютона ............................................................................................187
Задание 6....................................................................................................................... 189
Задание 7....................................................................................................................... 190
6. Для дополнительных занятий...........................................................................................190
Задание 8....................................................................................................................... 191
Библиотека часто встречающихся процедур и функций............................................. 191
Упражнения............................................................................................................................192
Ответы ........................................................................................................................... 193
Глава 9. Элементы теории вероятностей ................................................................................198
1. Классическое определение вероятности .........................................................................198
Задание 1....................................................................................................................... 201
Задание 2....................................................................................................................... 202
2. Формула Бернулли.............................................................................................................202
Задание 3....................................................................................................................... 204
Упражнения ................................................................................................................... 204
3. Дискретные случайные величины ...................................................................................204
3.1. Дискретная случайная величина, закон распределения вероятностей .............. 204
3.2. Определение законов распределения дискретных величин эмпирическим
(опытным) путем ............................................................................................................ 205
3.3. Числовые характеристики распределения ...................................................................207
3.3.1. Математическое ожидание ................................................................................. 207
3.3.2. Свойства математического ожидания как операции осреднения ..................... 208
3.3.3. Умножение математических ожиданий .............................................................. 208
3.3.4. Дисперсия, среднее квадратическое отклонение и другие характеристики
рассеяния ...................................................................................................................... 208
3.3.5. Правила вычисления дисперсий и средних квадратических отклонений ........ 209
4. Некоторые законы распределения дискретных случайных величин ...........................209
4.1. Биномиальное распределение .............................................................................. 209
Задание.......................................................................................................................... 212
4.2. Числовые характеристики биномиального распределения ........................................213
Задание 4....................................................................................................................... 216
4.3. Наиболее вероятное число событий биномиального распределения ........................216
Задание 5....................................................................................................................... 217
4.4. Гипергеометрическое распределение ...........................................................................217
Задание 6....................................................................................................................... 219
5. Распределение Пуассона ...................................................................................................219
Задание 7....................................................................................................................... 224
5.1. Числовые характеристики распределения Пуассона ..................................................224
5.2. Предельная теорема Муавра-Лапласа ..........................................................................224
Задания 8 ....................................................................................................................... 227
5.3. Интегральная формула Муавра-Лапласа ......................................................................227
Задание 9....................................................................................................................... 232
Задание 10 ..................................................................................................................... 234
Задание 11 ..................................................................................................................... 236
Задание 12 ..................................................................................................................... 238
Упражнения ................................................................................................................... 238
6. Двумерные случайные величины.....................................................................................239
Задание 13 ..................................................................................................................... 244
6

7. Функция распределения случайной величины .............................................................. 244
7.1. Новый способ задания случайной величины........................................................ 244
Задание 14 .................................................................................................................... 248
8. Непрерывные случайные величины ............................................................................... 248
8.1. Второе определение непрерывной случайной величины .................................... 248
9. Примеры непрерывных законов распределения ............................................................ 249
9.1. Равномерное распределение в интервале (a, b) ................................................. 249
9.2. Математическое ожидание и дисперсия непрерывной случайной величины .... 250
10. Нормальное распределение ........................................................................................... 252
Задание 15 .................................................................................................................... 256
Упражнения ................................................................................................................... 256
10. Метод статистических испытаний ................................................................................ 258
10.1. Геометрические вероятности "геометрическая схема" испытания ........................ 258
10.2. Функция random и процедура randomize ................................................................... 259
Задание 16 .................................................................................................................... 265
Задание 17 .................................................................................................................... 268
11. Задача о встрече .............................................................................................................. 268
Задание 18 .................................................................................................................... 270
12. Задача Бюффона.............................................................................................................. 270
Задание 19 .................................................................................................................... 275
13. Применение метода Монте-Карло для вычисления площадей фигур ....................... 275
Задание 20 .................................................................................................................... 279
Библиотека часто встречающихся процедур и функций ............................................ 279
Упражнения ................................................................................................................... 282
14. Дополнительные задания ............................................................................................... 283
Ответы ........................................................................................................................... 288
К заданию 3 ................................................................................................................... 289
Глава 10. Числовые последовательности ............................................................................... 308
Задание 1 ...................................................................................................................... 316
Задание 2 ...................................................................................................................... 320
Задание 3 ...................................................................................................................... 322
Задание 5 ...................................................................................................................... 326
Библиотека часто встречающихся процедур и функций ............................................ 326
Упражнения ................................................................................................................... 327
Ответы ........................................................................................................................... 329
Глава 11. Приближенное вычисление корней уравнений оператор выбора case...of... .
Численное дифференцирование и интегрирование .............................................................. 332
1. Классические методы нахождения изолированного корня .......................................... 332
1.1. Метод хорд (правило пропорциональных частей) ............................................... 333
1.2. Вычисление производных (численное дифференцирование) ............................ 335
Задание 1 ...................................................................................................................... 337
1.3. Правило Ньютона (метод касательных) ............................................................... 342
1.4. Комбинированный метод касательных и хорд ..................................................... 346
Задание 2 ...................................................................................................................... 348
2. Выбор метода. Оператор Case...of................................................................................... 349
Задание 3 ...................................................................................................................... 352
3. Приближенное вычисление интегралов ......................................................................... 352
3.1. Формула прямоугольников .................................................................................... 352
Программа вычисления интеграла по формуле прямоугольников ............................ 355
Задание 4 ...................................................................................................................... 359
3.3. Параболическое интерполирование. Дробление промежутка интегрирования.
Формула Симпсона ....................................................................................................... 360
3.4. Дробление промежутка интегрирования .............................................................. 361
3.5. Об оценке погрешности ......................................................................................... 364
Задание 5 ...................................................................................................................... 365
3.6. Вычисление интегралов методом Монте-Карло................................................ 365

7
Задание 6....................................................................................................................... 369
3.7. Вычисление двойных интегралов методом Монте-Карло .................................... 369
Задание 7....................................................................................................................... 370
Библиотека часто встречающихся процедур и функций............................................. 371
Упражнения ................................................................................................................... 375
Ответы ........................................................................................................................... 376
Глава 12. Числовые и функциональные ряды.........................................................................386
1. Функциональные ряды ......................................................................................................386
Задание 1....................................................................................................................... 390
Задание 2....................................................................................................................... 391
2. Сходимость числовых и функциональных рядов ..........................................................392
Задание 3....................................................................................................................... 393
3. Задачи с использованием последовательностей и рядов ...............................................393
Задание 4....................................................................................................................... 394
4. Бесконечные произведения ..............................................................................................395
4.1. Примеры некоторых замечательных бесконечных произведений ...................... 395
4.2. Формула Валлиса (J. Wallis) .................................................................................. 397
4.3. Полный эллиптический интеграл 1-го рода .......................................................... 398
Задание 5....................................................................................................................... 400
5. Приближенное вычисление интегралов с помощью рядов ...........................................400
Задание 6....................................................................................................................... 405
5.1. Полный эллиптический интеграл 2-го рода .......................................................... 405
Задание 7....................................................................................................................... 407
6. Некоторые замечательные функции ................................................................................407
6.1. Функция Бесселя .................................................................................................... 407
6.2. Гамма-функция Эйлера ......................................................................................... 409
Библиотека часто встречающихся процедур и функций............................................. 415
Упражнения ................................................................................................................... 419
Ответы ........................................................................................................................... 421
Литература .................................................................................................................................424
8

Глава 1. Структура программы на языке "Паскаль"
На этом занятии мы познакомимся с конструкцией программ на языке программирования высокого уровня "Паскаль".
Этот язык разработал сравнительно недавно, в 1970 году, профессор кафедры вычислительной техники Швейцарского федерального института технологии - Николас
Вирт.
Обо всех достоинствах и преимуществах Паскаля перед другими языками мы узнаем
после первоначального знакомства с ним, в конце первой части этой книги, а теперь обратимся к составлению простейших программ на этом языке.
Изучение конструкции программ на Паскале начнем с простого примера.
Пример 1. Составить программу решения следующей задачи.
Саша спросил Сережу: "Сколько тебе лет?" Сережа ответил:
"Если бы число моих лет увеличить в 3 раза, а потом уменьшить на 17, то мне было
бы 16 лет". Сколько лет Сереже?
Обычно решение такого типа задач начинается с "конца".
Число лет, которое было бы Сереже, т. е. 16, увеличиваем на 17, получаем
33 (16  17  33).
Полученный результат уменьшаем в 3 раза, т.е. делим на 3 (33:3  11), получаем 11.
Итак, Сереже было 11 лет.
Посмотрим, как будет выглядеть программа решения этой задачи на языке Паскаль.
Program Serg;
var
a, b, c: integer;
begin
write('Ведите число лет, которое было бы Сереже '); readln(a);
b := a + 17;
c := b div 3;
writeln('Сереже было ', c, ' лет')
end.
Если эту программу ввести в компьютер и выполнить, то на экране появится вначале запрос для пользователя:
Введите число лет, которое было бы Сереже
После ввода числа 16, компьютер выдаст на экран:
Сереже было 11 лет
Рассмотрим более детально построение программы.
Она начинается со слова program. Слово program зарезервировано в Паскале, т.е.
не может использоваться ни в каких других целях, лишь для начала программы.
После служебного слова program записывается имя программы. В нашей программе именем является serg. Имя программы записывается на английском языке по
усмотрению и фантазии автора программы. (В некоторых версиях Паскаля допускается
9

запись имени программы на русском языке). Конечно, желательным является, чтобы имя
программы выражало ее содержание, но как вы сами понимаете, это не всегда возможно.
Имя программы никак в дальнейшем не используется, поэтому требование обязательности объявления имени программы можно считать излишним. Программу можно
выполнять и без имени. С другой стороны, - программа без имени неудобна, а иногда непонятна для пользователей и программистов.
Количество символов в имени программы не ограничивается, но значащими считаются первые 63 символа.
Имя программы должно начинаться с буквы. В нем не должно быть пробелов, запятых, точек.
В конце первой строки, после имени программы стоит ";" - точка с запятой. Этот
знак указывает на то, что некоторая инструкция закончена и за ней будет записана следующая инструкция. Правда, первая "инструкция" является именем программы и не походит на инструкцию в смысле "делай то и делай так", но термин " инструкция" мы
употребляем в более широком смысле, как одно логически завершенное предложение
или его часть. Точка с запятой является обязательным разделительным знаком в языке
Паскаль.
В некоторых версиях языка Паскаль, вы можете встретить такое начало программы:
Program Serg (input, output);
Как видите, в скобках записаны служебные слова input (ввод) и output (вывод).
Они указывают, что в программе будет вводиться и выводиться информация. Для
большинства современных версий языка Паскаль и для Турбо Паскаля эти служебные
слова являются необязательными. Хотя, надо заметить, их запись в программе не приведет к ошибке. В дальнейшем мы не будем использовать их в программах.
Следующая строка программы:
var
a, b, c : integer;
В этой строке обязательно указываются все переменные, участвующие в программе и их типы.
Слово var - это сокращение от слова variable (переменная) и является так же, как и
слово program, зарезервированным словом.
После него записываются имена переменных - идентификаторы, в нашем примере: a, b, c. Они записываются через запятую.
После имен переменных стоит ":" - двоеточие, а затем записано служебное, зарезервированное, слово integer. Integer (целый) указывает тип значений, которые принимают
переменные - целые числа (..., -4, -3, -2, -1, 0, 1, 2, 3, 4, 5,...). Эта строка программы, также
как и предыдущая, заканчивается ";" - точкой с запятой.
Далее в программе следует служебное, зарезервированное, слово begin (начать),
которым начинается новый раздел программы - раздел операторов.
В этом разделе последовательно записываются команды, операторы, которые разделяются ";" - точкой с запятой. Они будут выполняться компьютером.
Программа заканчивается служебным словом end, после которого стоит точка.
Она является обязательной во всех паскалевских программах. Точка оповещает о конце
текста программы.
10 
Заметьте, последняя строка из раздела операторов перед служебным словом end
не заканчивается точкой с запятой. Но, если вы ее поставите, то ошибки не будет.
1. Итак,
КОНСТРУКЦИЯ ПРОГРАММЫ на языке
ПАСКАЛЬ
Program <имя>;
РАЗДЕЛ ОПИСАНИЙ
В нем описываются имена переменных и их типы.
Begin
РАЗДЕЛ ОПЕРАТОРОВ
Ввод данных, последовательность команд, вывод результатов.
end.
Эту конструкцию очень удобно изобразить с помощью блок-схемы. Вспомним, что
блок-схема состоит из отдельных геометрических фигур - блоков, каждый из которых
показывает какие команды или операции надо выполнить.
Вот эти блоки:
Блок начала и
конца программы
Блок ввода и
вывода
информации
Блок выполнения
команд
Блок условия
Блок цикла
Блок вывода
информации на
печать
11

Блок-схема простейшей программы
Начало
Ввод
информации
Выполнение
команд
Вывод
информации
Конец
2. Переменные и их имена
Под переменной в языке Паскаль, как и в других языках программирования, понимают программный объект (число, слово, часть слова, несколько слов, символы), имеющий имя и значение, которое может быть получено и изменено программой.
Если "заглянуть" в компьютер, то переменную можно определить так.
Переменная - это имя физического участка в памяти, в котором в каждый
момент времени может быть только одно значение.
Само название "переменная" подразумевает, что содержимое этого участка может
изменяться.
В качестве имен переменных в Паскале могут быть латинские буквы с индексами.
Причем может быть не одна буква, а несколько.
В качестве числового индекса может быть любое целое число. Всего в обозначении
переменных может быть произвольное число символов, но значащими считаются первые
63 символа. В некоторых версиях Паскаля допускаются имена переменных, содержащие
до 8 символов.
Примеры обозначений переменных: a, b, e, vert, trenin, d, f1, g23, p564, red18 и т.п.
Имена переменных называются идентификаторами.
Замечания
Не имеет значение в обозначении переменных маленькими или большими (строчными или прописными) буквами они написаны!
Имя переменной должно удовлетворять следующим требованиям:
1) всегда начинаться с буквы, после которой при необходимости может следовать
некоторое целое число (индекс);
2) в идентификаторе (имени) не должно быть пробелов, запятых или других непредусмотренных знаков, например недопустимы следующие имена переменных: jan.2
(есть точка); 3x (начинается с цифры); a 2 (имеется пробел); чн (русские буквы);
3) нельзя использовать в качестве имен переменных слова, которые являются служебными или операторами, например: program, begin, write, end и другие.
12 
3. Команда присваивания
В программе, которая была приведена выше, есть следующие записи: b :  a 17,
c :  b div 3. Что означает знак ":="?
Так на языке Паскаль обозначается команда присваивания. В чем ее сущность?
Команда присваивания "стирает" предыдущее значение переменной и "придает"
ей новое значение. На языке Паскаль команда присваивания обозначается: := двоеточие
и знак равно.
В нашей программе, переменной b присваивается значение a + 17, что равно 33,
переменной c присваивается значение частного от деления переменной b на 3, 33:3  11.
Чтобы понять значение терминов "стирает" и "придает" в определении команды
присваивания, надо немного глубже рассмотреть "компьютерную физиологию", т.е., что
происходит в компьютере при выполнении команды присваивания.
Для каждой переменной в оперативной памяти компьютера отводится место - ячейка
памяти, куда компьютер заносит значение этой переменной. Каждая ячейка имеет свое
имя по имени переменной в программе. В нашей программе под переменные отведено
3 ячейки с именами a, b, c.
При выполнении команды присваивания в ячейки с этими именами будут занесены
соответствующие числа. Если в них была записана какая-то информация, то она уничтожится. Происходит процесс похожий на запись на магнитофонную ленту. При записи
новой информации прежняя стирается.
4. Операторы write и writeln. Процедуры вывода информации
Вы обратили внимание, что в программе были использованы операторы write и
writeln. Английское слово write переводится - писать, а слово writeln происходит как
сокращение от двух английских слов write - писать и line - строка.
Кроме операторов write и writeln мы говорим о процедурах вывода информации.
Что же такое процедура?
Понятие процедуры - одно из основных понятий Паскаля. Ему подобна подпрограмма на языке Бейсик.
Процедура - это некоторая последовательность операторов языка Паскаль, имеющая имя и к которой можно обратиться из любого места основной программы, указав ее
имя.
Выше мы говорили об операторах вывода информации, хотя в Паскале, в отличие от
Бейсика нет операторов вывода информации, а через служебные слова write и writeln
происходит обращение к стандартной или встроенной процедуре вывода информации.
Стандартная процедура не нуждается в предварительном описании, она доступна любой
программе, в которой содержится обращение к ней. Вот почему обращение к write или
writeln напоминает оператор PRINT - вывода информации на языке Бейсик.
Разница между оператором вывода и обращением к процедуре вывода состоит в
том, что имя процедуры вывода, как и любой другой процедуры Паскаля не является
зарезервированным словом, а, следовательно, пользователь может написать свою собственную процедуру с именем write или writeln. Но это очень редко используется на
практике.
13

Таким образом, операторы write и writeln являются операторами обращения к
встроенным процедурам вывода информации.
Обе эти процедуры выводят информацию на экран, если эта информация содержится в виде значений переменных, тогда достаточно в скобках в операторах write или
writeln записать имена этих переменных, например: write(a), writeln(f). Если таких переменных несколько, то их записывают через запятую, например: write(a, b, c, d), writeln(e,f,
g, h).
Если информацией являются слова, предложения, части слов или символы, тогда
она заключается между знаками " ' " - апостроф, например:
write('Введите длину пути'),
writeln('Значение скорости равно'
Возможен одновременный вывод и символьной информации и значений переменных, тогда в операторе write или writeln они разделяются запятыми, например:
write('Значение температуры равно ', t),
writeln('Скорость равна ', v, ' при времени движения ', t).
Заметьте, в конце слов, перед апострофом оставлен пробел.
Для чего это сделано? Конечно, чтобы следующая числовая информация была
разделена со словами пробелом.
В чем состоит отличие в работе процедур write и writeln?
Процедура write требует от следующих процедур ввода или вывода, информацию
вводить или выводить ее на ту же строку (в одну строку).
Если в программе указан оператор write и за ним следуют еще операторы write или
writeln, то выводимая ими информация будет присоединяться к строке информации
первого оператора write.
Например: write('Сегодня и завтра будут ');
write('выходные дни ');
На экран выводится:
Сегодня и завтра будут выходные дни
Пробел между словом "будут" и "выходные" обеспечивается за счет пробела в конце первой строки. Если его не будет, то вывод произойдет слитно:
write('Сегодня и завтра будут');
write('выходные дни');
Сегодня и завтра будутвыходные дни
Еще некоторые примеры: t:=20;
write('Время движения равно ');
write(t);
write(' секунд');
Время движения равно 20 секунд
a := 18; b := 12;
write('Сумма чисел равна ');
write(a+b);
write(', а произведение ');
write(a*b);
14 
Сумма чисел равна 30, а произведение 216
Процедура writeln обеспечивает для следующих процедур ввода или вывода информации вводить или выводить ее с начала каждой новой строки.
В программе:
writeln('Сегодня вечером, вечером, вечером,');
writeln('Когда пилотам, скажем прямо, делать нечего');
На экран выводится:
Сегодня вечером, вечером, вечером,
Когда пилотам, скажем прямо, делать нечего
В программе:
a := 25;
b := 17;
writeln('Сумма и разность чисел равны:');
writeln(a + b);
writeln(a - b);
На экране:
Сумма и разность чисел равны:
42
8
5. Операторы read и readln. Процедуры ввода информации
Так же, как и для операторов вывода информации, операторы read и reeadln являются операторами обращения к встроенным процедурам ввода информации.
Операторы read (считывать) и readln, который происходит от двух английских
слов read (считывать) и line (строка) используются в программах для ввода информации в память компьютера и "считывания" значений в переменную.
Рассмотрим работу этих операторов и процедур ввода информации.
В нашей программе есть процедура readln(a). При выполнении программы, встретив
оператор readln, компьютер приостановит работу в ожидании ввода информации. После
того, как мы введем с клавиатуры значение переменной a - 16, компьютер присвоит это
значение переменной a, т.е. отправит его в ячейку памяти с именем a и продолжит выполнение программы. Этот процесс мы называем "считыванием" значения в переменную.
Итак, процедуры read и readln "считывают" значения переменных и присваивают их тем переменным, которые записаны в них.
Таких переменных может быть несколько, тогда они записываются в этих операторах через запятую, например:
read(a, b, c, n, g, j, i), readln(e,f, k, p, d) и т.п.
Чем же отличается работа процедур read и readln?
15

Процедура read потребует после себя ввод или вывод информации в одну строку, а процедура readln дает возможность после себя вводить и выводить информацию с начала новой строки.
Например:
В программе: write('Введите значения a и b '); read(a, b);
write('Ввод информации в одну строку');
При выполнении этой части программы, на экран будет выведено все то, что записано в первом операторе write, затем в той же строке будет находиться курсор, и компьютер
будет ждать ввода значений a и b. Введем их значения - 2 и 3, разделяя их пробелом
или, иначе говоря, через пробел. После этого, в той же строке будет выдана информация
записанная в следующем операторе write.
На экране:
Введите значения a и b 2 3 Ввод информации в одну строку
В программе:
writeln('Введите значения a, b и c); readln(a, b, c);
writeln('Ввод и вывод информации с начала строки');
На экране:
Введите значения a, b и c
234
Ввод и вывод информации с начала строки
16 
Глава 2. Ввод и выполнение программ
1. В интегрированной среде Турбо Паскаль 7.0.
После запуска Турбо Паскаля на экране появится следующая оболочка (см. рис. 3):
Рис. 3
Верхняя строка открывшегося окна содержит "меню" возможных режимов работы
Турбо Паскаля, нижняя - краткую справку о назначении основных функциональных
клавиш. Вся остальная часть экрана принадлежит окну текстового редактора, очерченному двойной рамкой и предназначенному для ввода и редактирования текста программы.
Когда мы вводим программу, то работаем с текстовым редактором, встроенным в
среду Турбо Паскаль. Поэтому ниже мы и познакомимся с работой редактора и основными его командами.
Признаком того, что среда находится в состоянии редактирования, является наличие
в окне редактора курсора - небольшой мигающей черточки.
Для создания текста программы нужно ввести этот текст с помощью клавиатуры
подобно тому, как это делается при печатании текста на пишущей машинке. После заполнения очередной строки следует нажать на клавишу <Enter> "Ввод", чтобы перевести курсор на следующую строку (курсор всегда показывает место на экране, куда будет
помещен очередной вводимый символ программы).
Окно редактора имитирует длинный и достаточно широкий лист бумаги, часть которого видна в окне экрана. Если курсор достиг нижнего края, осуществляется прокрутка окна редактора: его содержимое смещается вверх на одну строку и внизу появляется новая строка "листа". Наибольшая длина строки на Турбо Паскале - 126 символов.
Окно можно смещать относительно листа с помощью следующих клавиш:
17

PgUp
PgDn
Home
End
Ctrl-PgUp
Ctrl-PgDn
-
на страницу вверх (PaGe UP - страница вверх);
на страницу вниз (PaGe DowN - страница вниз);
в начало текущей строки (HOME - домой);
в конец текущей строки (END - конец);
в начало текста;
в конец текста.
Клавишами управления курсора “курсор” можно смещать по тексту на экране (заметьте, только по тексту!). По "чистому" не исписанному экрану курсор не перемещается!
Если Вы ошиблись при вводе очередного символа, его можно стереть с помощью
клавиши, обозначенной стрелкой влево (клавиша Backspace - <Забой>, она располагается
справа и вверху зоны основных алфавитно-цифровых клавиш над клавишей <Enter> “Ввод”). Клавиша <Delete> (Delete - стирать, удалять) стирает символ, на который в
данный момент указывает курсор, а команда Ctrl-Y - всю строку, на которой располагается курсор. Следует помнить, что редактор Турбо Паскаля вставляет в конце каждой
строки невидимый на экране символ-разделитель. Этот символ вставляется клавишей
<Ввод>, а стирается клавишей <Забой> или <Delete>. С помощью вставки/стирания разделителя можно "разрезать”/"склеить" строки.
Чтобы "разрезать" строку, следует подвести курсор к нужному месту и нажать клавишу <Ввод>, чтобы "склеить" соседние строки, нужно установить курсор в конец первой строки и нажать клавишу <Delete> или установить курсор в начало следующей
строки и нажать клавишу <Забой>.
Режим вставки
Нормальный режим работы редактора - режим вставки, в котором каждый вновь
вводимый символ как бы "раздвигает" текст на экране, смещая вправо остаток строки.
Следует учитывать, что "разрезание" и последующая вставка пропущенных символов
возможна только в этом режиме.
Примеры "разрезания", "склеивания" строк и вставки символов в текст.
Пусть по каким-то причинам на экране получена такая запись:
Program Serg; var
a, b, c : integer;
Если говорить об эстетической стороне написания программы, то желательно, чтобы раздел описаний, который начинается со слова var, начинался с красной строки. Для
внесения изменений в текст установим курсор на букву v и нажмем клавишу <Ввод>,
при этом часть текста после курсора и под ним переместится на следующую строку, получим:
Program Serg;
var
a, b, c : integer;
Для большей красоты и наглядности, не перемещая курсора, а оставляя его на букве
v, нажмем несколько раз клавишу <Пробел>. Вся строка передвинется на вправо и запись станет такой:
Program Serg;
var
a, b, c : integer;
Допустим другую ситуацию, когда часть текста "разорвалась" и ее нам надо "склеить", например, получилось так:
write('Введите число лет, кото
рое было бы Серёже ");
18 
Устанавливаем курсор в начало второй строки перед буквой "р" и нажимаем клавишу <Забой>, получим:
write('Введите число лет, которое было бы Серёже ');
Можно поступить иначе, установить курсор в конец первой строки после буквы "о"
и нажимая несколько раз клавишу <Delete> "подтягивать" нижнюю строчку вверх.
С помощью клавиш <Забой> и <Delete> можно "соединять" "разорванную” строку.
Например, в такой ситуации:
write('Вве дите число лет, которое было бы Сереже ');
Устанавливаем курсор перед буквой "д" и нажимаем несколько раз клавишу <Забой> до тех пор, пока слово "Введите" примет нужную конструкцию, или, установив курсор после буквы "е" нажать несколько раз клавишу <Delete>.
Вставка пропущенных символов делается еще проще.
Например, вы пропустили несколько букв:
wrte('Ввете число лет, которое было бы Сеже ');
В первом слове пропущена буква "i", в слове "Введите" пропущены две буквы
"ди", в слове "Сережа" буквы "ер".
Установим курсор на букву "t" в первом слове и наберем с клавиатуры "i", она тут
же вставится на нужное место. Далее установим курсор на букву "т" в слове "Ввете" и
наберем с клавиатуры "ди", слово "раздвинется" и буквы "ди" станут на свои места.
Установим курсор на "е" в слове "Сежа" и наберем "ер",
Режим наложения
Редактор может также работать в режиме наложения новых символов на существующий старый текст: в этом режиме новый символ заменяет собой тот символ, на который указывает курсор, а остаток строки справа от курсора не смещается вправо. Для
перехода к режиму наложения надо нажать клавишу <Insert> (Insert - вставка), если
нажать эту клавишу еще раз, вновь восстановится режим вставки. Признаком того, в каком режиме работает редактор, является форма курсора: в режиме вставки курсор похож на мигающий символ подчеркивания, а в режиме наложения он представляет собой
крупный мигающий прямоугольник, заслоняющий символ целиком.
Режим автоотступа
Еще одной особенностью редактора является то, что обычно он работает в режиме
автоотступа. В этом режиме каждая новая строка начинается в той же позиции экрана,
что и предыдущая.
Режим автоотступа поддерживает хороший стиль оформления текстов программ:
отступы от левого края выделяют различные операторы и делают программу более
наглядной.
Отказаться от режима автоотступа можно командой Ctrl-O I (при нажатой клавише
Ctrl нажимается сначала клавиша O, затем клавиша O отпускается и нажимается клавиша I), повторная команда Ctrl-O I восстановит режим автоотступа.
Ниже перечислены наиболее часто используемые команды текстового редактора
Турбо Паскаля, кроме тех, которые были приведены выше.
19

Команды редактирования
Backspac
Del
Ctrl-Y
Enter
Ctrl-Q L
-
<Забой> - стереть символ слева от курсора;
стереть символ, на который указывает курсор;
стереть строку, на которой располагается курсор;
<Ввод> - вставить новую строку, "разрезать" старую;
восстановить текущую строку (действует, если
курсор не покидал измененную строку).
Работа с блоком
Ctrl-K B
Ctrl-K Y
Ctrl-K V
Ctrl-K R
Ctrl-K P
Ctrl-K H
Ctrl-K K
Ctrl-K C
Ctrl-K W
- пометить начало блока;
- стереть блок;
- переместить блок;
- прочитать блок из дискового файла;
- напечатать блок;
- спрятать/отобразить блок (снять пометку);
- пометить конец блока;
- копировать блок;
- записать блок в дисковый файл;
Выполнение программы
После того, как программа набрана можно попробовать ее выполнить.
Для этого нажимаем клавиши <Ctrl>+<F9> (удерживая клавишу <Ctrl>, нажать
клавишу <F9>). Эту же операцию можно выполнить, перейдя в основное меню, нажав
клавишу <F10>, а затем перемещением указателя выбрать опцию Run и нажать клавишу <Ввода>.
На экране раскроется меню второго уровня, связанное с этой опцией. Новое меню
как бы "выпадает" из верхней строки, поэтому такое меню часто называют выпадающим
(Pull-down). Экран станет таким (см. рис. 4):
Рис. 4
20 
Теперь надо найти в новом меню опцию RUN (пуск) и нажать клавишу <Ввод>.
Если не было ошибки при вводе текста, то, спустя несколько секунд, произойдет
смена изображения на экране. Турбо Паскаль предоставляет экран в распоряжение работающей программы пользователя. Такой экран называется окном программы.
В ответ на запрос:
Введите число лет, которое было бы Серёже, надо ввести 16 и нажать клавишу
<Ввод>.
После завершения прогона (работа программы часто называется ее прогоном) на
экране вновь появится окно редактора с текстом программы. Если Вы не успели разглядеть изображение окна программы, то нажмите Alt-F5. При этом окно редактора скроется и вы сможете увидеть результаты работы программы. Чтобы вернуть экран в режим воспроизведения окна редактора, надо нажать на любую клавишу.
Можно экран сделать более удобным, чтобы видеть результаты работы программы.
Для этого в нижней части экрана можно открыть второе окно.
Для этого нажмите клавишу F10, чтобы перейти к режиму выбора из главного меню,
подведите указатель к опции Debug (отлаживать) и нажмите клавишу <Ввод> - на
экране раскроется меню второго уровня, связанное с этой опцией. Экран станет таким (см.
рис. 5):
Рис. 5
Найдите в новом меню опцию OUTPUT (вывод программы), подведите к ней указатель и нажмите клавишу <Ввод>.
В нижней части экрана появится второе окно, но оно уже не будет исчезать.
Теперь добьемся того, чтобы на экране демонстрировалось два окна одновременно:
снова нажмите клавишу F10, выберите WINDOW, нажмите клавишу <Ввод>, подведите указатель к опции TILE (черепица) и нажмите клавишу <Ввод>.
Если все сделано правильно, экран примет вид (см. рис. 6):

21
Рис. 6
Двойная рамка, очерчивающая окно программы, свидетельствует о том, что именно
это окно активно в данный момент.
Сделаем активным окно редактора: нажмем клавишу <Alt> и, не отпуская ее, - клавишу с цифрой 1 (окно редактора имеет номер 1, окно программы - номер 2, эти номера
написаны в верхних правых углах рамок). Теперь всё готово к дальнейшей работе с
программой.
Первые ошибки и их исправление
1. Не поставлена точка с запятой, например, после оператора readln(a). После пуска
программы, нажатием клавиш <Ctrl>+<F9>, в верхней строке экрана появится написанное красным цветом сообщение:
Error 85: ";" expected.
(Ошибка 85: ";" отсутствует.)
Редактор установит курсор на следующий символ после пропущенного знака, в
нашем примере на переменную b. После нажатия любой клавиши, сообщение об ошибке
исчезает и редактор переходит в режим вставки. Надо подвести курсор к нужному месту, поставить точку с запятой - “;” и продолжить работу.
2. В описании переменных не записана переменная, а в программе она присутствует,
например переменная c. После пуска программы, будет выдано сообщение:
Error 3: Unknown identifier.
(Ошибка 3: Неизвестный идентификатор.)
Курсор будет установлен на эту переменную, в нашем примере на переменную c.
Надо исправить ошибку, т.е. записать переменную c в раздел описаний переменных и
продолжить работу.
3. Не поставлена точка после оператора end в конце программы. Сообщение компилятора будет таким:
Error 10: Unexpected end of file.
(Ошибка 10: Неправильный конец файла.),
курсор установится на букву "e" в слове "end". Надо поставить точку и снова выполнить
программу.
22 
Запись файла на диск
Итак, программа отредактирована и выполнена (прокручена), теперь ее надо записать на диск. Для этого можно воспользоваться основным меню, в котором выбрать опцию "File" (см. рис. 7). Последовательность действий такова: 1) нажать клавишу F10 и перейти в основное меню; 2) переместить указатель на опцию "File" и нажать <Ввод>, откроется второе меню опции "File":
Рис. 7
Вы можете из этого меню выбрать опцию "Save". Она записывает содержимое активного окна редактора в дисковый файл.
Если нажать клавишу <Ввод>, то среда запросит имя файла, если такового не было
установлено и окно было связано с именем NONAME00.PAS. Вы можете изменить имя,
или оставить его прежним.
Эта опция вызывается непосредственно из редактора клавишей <F2>.
Можно выбрать опцию SAVE AS. Она записывает содержимое активного окна редактора в дисковый файл под другим именем.
Диалоговое окно этой опции имеет вид (см. рис. 8):
Рис. 8
23

В поле ввода Вы должны написать имя того файла, в который будет переписано содержимое активного окна редактора. Вы можете выбрать уже существующий файл из поля выбора или из протокола с опциями. В этом случае в зависимости от настройки среды
старое содержимое файла будет уничтожено или сохранено в виде страховой копии с
расширением .BAK.
Построчная запись текста программы
В Паскале нет правил разбивки текста программы на строки.
Однако для записи программы можно дать некоторые
Рекомендации
Очень важно, чтобы текст программы был расположен наглядно не только ради красоты, но (и это главное!) ради избежания ошибок. (Найти ошибки в наглядном тексте
значительно легче.)
1. Каждый оператор следует писать с новой строки, за исключением коротких и по
смыслу связанных операторов.
Например,
write ... readln ... - записываются в одной строке, короткие операторы присваивания
можно записать в одну строку:
a := 23; b := 105; c := -11.2.
2. Операторы одного уровня, находящиеся в разных строках, должны быть выровнены по вертикали, т.е. одинаково отодвинуты от левого края.
Например, запишем последовательность операторов для определения суммы цифр
трехзначного числа:
s := a div 100;
d := a div 10 mod 10;
e := a mod 10;
sum := s + d + e
Здесь все операторы равноценны, последовательно идут один за другим, поэтому все
начинаются с одной и той же вертикальной позиции.
3. Операторы, включенные в другой оператор, следует сдвинуть вправо на несколько
позиций (желательно одинаково).
begin
write ...
readln ...
if ... then
begin
.....
end
else
begin
.....
end;
end.
4. Рекомендуется вертикально выравнивать пары базовых слов: begin и end, с которыми мы уже познакомились, а также слова, с которыми мы познакомимся позже:
repeat и until, record и end, case и end.
5. Оператор if рекомендуется размещать с учетом длины и сложности условия, и
операторов, идущих после слов then и else.
Вот несколько самых популярных вариантов размещения оператора if:
24 
а) if ... then ...
else ...
б) if ... then ...
else ...
в) if ...
then ...
else ...
г) if ...
then ...
else ...
д) if ... then ... else ...
6. Комментарии пишутся либо рядом с конструкцией (идентификатором, оператором, его частью), которую они объясняют, либо в отдельной строке.
7. После знаков препинания: , - запятой, ; - точки с запятой, : - двоеточия рекомендуется оставлять по одному пробелу.
Задание
Наберите программу Serg и выполните ее. Закончите работу в системе Turbo Pascal.
2. Программирование в среде Microsoft Windows на языке Pascal
В этой части занятия описывается программирование с помощью компиляторов Turbo Pascal for Windows и Borland Pascal for Windows.
Ясно, что эта часть занятия будет полезна тем, кто работает в среде Windows.
На этом занятии мы не будем останавливаться на огромных возможностях, которые
предоставляет интегрированная среда Borland Pascal, а узнаем начальные этапы работы.
Прежде выясним, как можно программы, разработанные на Turbo Pascal 7 запустить в
среде Borland Pascal.
Для этого, забегая несколько вперед, познакомимся с тем, что такое модули и каким
модулем надо пользоваться, чтобы программа, написанная в DOS, могла работать в среде
Windows.
Что такое модуль?
Модуль представляет собой набор констант, типов данных, переменных, процедур и
функций. Каждый модуль по своей структуре аналогичен отдельной программе. Вместе с
тем структура модуля позволяет использовать его как своеобразную библиотеку описаний.
В Borland Pascal входит 7 модулей. На этом занятии мы познакомимся с одним из
них - WinCRT.
Модуль WinCRT может быть использован для преобразования DOS-программ и создания небольших Windows программ.
Для этого необходимо включить в начале DOS-программы следующую строку:
uses WinCrt;
Для примера рассмотрим приведенную выше программу Serg. В DOS она имела следующий вид:
25

Program Serg;
var
a, b, c: integer;
begin
write('Введите число лет, которое было бы Сереже '); readln(a);
b := a + 17;
c := b div 3;
writeln('Сереже было ', c, ' лет')
end.
Добавим в начала этой программы модуль WinCrt и программа сможет работать в
среде Borland Pascal. В этом случае она станет такой:
Program Serg;
uses WinCrt;
var
a, b, c: integer;
begin
write('Введите число лет, которое было бы Сереже '); readln(a);
b := a + 17;
c := b div 3;
writeln('Сереже было ', c, ' лет')
end.
Теперь поговорим о среде разработчика. После запуска программы BPW (так в Windows записан Borland Pascal for Windows) на экране появляется следующее окно (см. рис.
9):
Рис. 9
Чтобы набрать текст программы, достаточно выбрать из верхнего меню "File" и
"щелкнуть" один раз левой кнопкой мыши. Окно разработчика примет вид (см. рис. 10):
26 
Рис. 10
Из "выпавшего" меню следует выбрать "New" и нажать <Enter> или "щелкнуть"
один раз левой кнопкой мыши. Окно очистится и предоставит пользователю возможность
набирать текст программы на "чистом" поле (см. рис. 11).
Рис. 11
Перед началом ввода текста программы желательно установить шрифт, с котором вы
будете работать. Желательно выбрать шрифт с кириллицей, т. е. такой, чтобы можно было
бы набирать и русский текст.
Для установки шрифта следует выбрать в верхнем меню опцию "Options" и нажать
<Enter> или "щелкнуть" один раз левой кнопкой мыши. "Выпадает" новое меню, из которого надо выбрать опцию "Environment" ("Среда") (см. рис. 12).
27

Рис. 12
После установки курсорной доски на слово "Environment" справа появляется новое
меню, которое является своеобразным подменю раздела "Environment", которое состоит
из следующих разделов:
Environment Preferences ..
.
Editor ...
Mouse ...
Startup ...
Highlight ...
Из появившегося меню надо выбрать "Editor ..." и нажать <Enter> или "щелкнуть"
один раз левой кнопкой мыши. На экране появится меню, в котором из раздела "Font",
"наступив" на указатель выбора шрифта можно выбрать нужный шрифт, название которого появится в видимом окне (см. рис. 13).
Рис. 13
28 
После выбора шрифта можно набирать текст программы. Текст программы набран.
Как выполнить пуск программы? Для этого из верхнего меню выбираем "Run" ("Пуск"),
"выпадает" меню опции "Run" (см. рис. 14):
Рис. 14
Следует выбрать "Run
Ctrl+F9". Программа будет запушена и выполнена.
Для записи программы на диск, следует выбрать опцию "File" из верхнего меню.
Выбрать "Save" или "Save as" и записать в нужный каталог и под указанным именем свою
программу (см. рис. 15).
Рис. 15
Если программа была уже записана на диск и вам потребовалось ее вызвать для доработки или запуска в работу, тогда следую выбрать из меню опции "File" "Open" ("Открыть"), выбрать нужный каталог, файл и работать с программой (см. рис. 16).
29

Рис. 16
В дальнейшем мы будем составлять и выполнять программы в интегрированной
среде Borland Pascal. Но если кто-то работает на Turbo Pascal 6 или 7, тогда достаточно не
писать в начале программы обращение к модулю uses WinCrt или заключить это обращение в фигурные скобки, т. е. сделать в виде комментария. Все остальное в программах
остается без изменения. И лишь в главах, где рассматриваются модули и объектноориентированное программирование отдельно будет оговорено использование модулей в
DOS и Windows.
30 
Глава 3. Арифметические операции с целыми числами.
Переменные целого типа. Условный оператор
if...then...else ... Вещественный тип (real)
В языке Паскаль используются целые числа, к которым относятся все натуральные
числа, образовавшиеся в процессе подсчета предметов: 1, 2, 3, 4, 5, 6, ...; отрицательные
числа: ..., -6, -5, -4, -3, -2, -1 и число ноль: 0. Целые числа образуют следующий ряд:
..., -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, ...
В Паскале допускается диапазон целых чисел от -32768 до 32767.
Переменные, принимающие целые значения, записываются в разделе описаний с
указанием типа integer (целый).
Например: var a, b, c, a1, b34, nomb: integer;
Значения другого типа этим переменным в одной программе присвоить нельзя.
1. Арифметические операции с целыми числами и переменными
целого типа в языке Паскаль
Операция
Сложение
Вычитание
Умножение
Деление
Обозначение
+
*
a_div_b
Знак "_" означает пробел. Пробелы между именами переменных и названием операции (div) - обязательны. (Происходит от английского division - деление).
Остаток от деления a на b. a_mod_b
Кроме арифметических операций с целыми числами выполняются:
2. Операции отношения или сравнения
Знак
<
<=
>
>=
=
<>
Наименование
Меньше
Меньше или равно
Больше
Больше или равно
Равно
Не равно
Пример
a<6
b <= 23
x>5
y >= 8
c = 10
d <> 3
Пояснение
a меньше 6
b меньше или равно 23
x больше 5
y больше или равно 8
c равно 10
d не равно 3
31

3. Логические операции
Логическая
операция
AND
Ее значение
Логическое "И"
Примеры
записи
(x<7) and (x>3)
OR
Логическое "ИЛИ"
(y>100) or (y<10)
NOT
Логическое "НЕ"
not (x=2)
Значение примера
x меньше 7 и x больше 3 (3<x<7)
y больше 100 или
y меньше 10
(y<10, y>100)
не x равно 2
Правила использования операций AND и OR (Таблица истинности)
a
b
a and b
a or b
истина
истина
истина
истина
истина
ложь
ложь
истина
ложь
истина
ложь
истина
ложь
ложь
ложь
ложь
Остановимся немного подробнее на операции целочисленного деления (div) и операции, выдающей остаток от деления (mod).
Так, результатом целочисленного деления 17 на 5 будет 3:
17 div 5 = 3, а результатом деления меньшего числа на большее, будет 0:
46 div 200 = 0.
Делаем вывод, что при целочисленном деление дробная часть отбрасывается, сам
термин "целочисленное деление" или "деление нацело" говорит сам за себя.
Операция a div b осуществляет целочисленное деление целого a на целое b.
Дробная часть при этом отбрасывается.
Еще одна интересная операция - остаток от деления a на b.
Понятно, что остатком от деления 17 на 5 будет число 2:
17 mod 5 = 2,
а вот чему будет равен остаток от деления меньшего числа на большее, например, 46 mod
200?
Оказывается, в этом случае, результатом операции будет число 46. Вот другие примеры:
34 mod 125 = 34,
120 mod 6 = 0.
Интересно, что остаток от деления любого целого числа на 10 будет равен последней цифре этого числа:
543 mod 10 = 3, 45 mod 10 = 5, 7 mod 10 = 7.
Рассмотрим задачу, которая показывает использование операций целочисленного
деления и остатка от деления.
Пример 1. Найти разность между трехзначным числом и числом, составленным из
тех же цифр, но взятых в обратном порядке.
32 
При решении этой задачи, надо помнить, что компьютер не знает десятичной и позиционной формы записи чисел, так для него совершенно неизвестно, сколько в числе 342
сотен, десятков и единиц. Это известно нам, потому что с раннего возраста мы используем
такую форму записи чисел. Мы условились считать, что на первом месте слева стоит цифра единиц, на втором - цифра десятков, на третьем - цифра сотен и т.д.
Компьютеру это неизвестно! Он любое число переводит на язык двух цифр 0 и 1.
А для решения этой задачи нам необходимо знать цифры единиц, десятков и сотен
заданного числа, чтобы затем переставить их, отсюда возникает первая задача - научить
компьютер находить цифры числа, принадлежащие различным разрядам. Для этого можно использовать два способа.
Способ первый достаточно простой. Сущность которого в следующем.
Для определения цифры сотен делим данное число на 100 и остаток отбрасываем, т.
е. выполняем целочисленное деление.
Для определения цифры десятков надо из данного числа вычесть сотни, результат
разделить на 10 и остаток отбросить.
Для определения цифры единиц надо из данного числа вычесть сотни и десятки. Для
записи числа теми же цифрами в обратном порядке, умножим цифру единиц на 100, сложим с цифрой десятков, умноженной на 10 и с цифрой сотен.
Далее из заданного числа вычитаем полученное новое. Например, для числа 342.
Выполним целочисленное деление числа на 100, получим цифру сотен:
342 div 100 = 3;
вычитаем из 342 сотни 3*100 и результат делим на 10 - получим цифру десятков:
(342 - 3*100) div 10 = 4;
наконец, вычитаем из заданного числа сотни и десятки, получаем цифру единиц:
342 - 3*100 - 4*10 = 2.
Для записи числа в обратном порядке, умножаем цифру единиц 2 на 100 и складываем с цифрой десятков, умноженных на 10 (4*10) и прибавляем цифру сотен 3. Получим
новое число, записанное теми же цифрами, но в обратном порядке:
2  100 + 4  10 + 3 = 243.
Вычитаем: 342 - 243 = 99.
Программа
Program Problem1;
uses WinCrt;
var
a, s, d, e, b, r : integer;
begin
write('Введите трехзначное число '); readln(a);
s := a div 100;
d := (a - s*100) div 10;
e := a - s*100 - d*10;
b := e*100 + d*10 + s;
r := a - b;
writeln('Искомая разность равна ', r)
end.
Программа достаточно проста и понятна.
В разделе описаний переменным a, s, d, e, b, r устанавливается целый тип - integer.
Вводится трехзначное число и присваивается переменной a.
Переменной s присваивается результат целочисленного деления введенного числа a
на 100. Это значение есть цифра сотен. Переменная d получает значение цифры десятков:
33

d := (a - s*100) div 10,
переменная e - это цифра единиц:
e := a - s*100 - d*10.
Дальнейшая работа программы понятна.
4. Комментарии
В программе очень удобно помещать комментарии, чтобы при последующем прочтении она была понятна другим пользователям и программистам.
Комментарии - это тексты, объясняющие программу, но не влияющие на ее исполнение. Это различные объяснения, заголовки отдельных частей программы и т.д. Компьютер печатает комментарии вместе с текстом программы, но, выполняя программу, игнорирует их. Программа выполняется так, словно комментариев нет.
В нашей программе комментариев нет и это делает ее непонятной для других. Паскаль предусматривает располагать комментарии между фигурными скобками { ... } или
между круглыми скобками со звездочками (* ... *). Всё, что находится в скобках, при выполнении программы игнорируется, но сохраняется в программе.
Почему допускается два способа записи комментариев?
Представьте себе ситуацию, когда внутри одного комментария надо разместить еще
комментарий. Если внутри фигурных скобок будут размещены такие же скобки
{...{...}...}, то будет выдана ошибка, тоже произойдет и при такой записи:
(*...(*... *)...*) , т. е. запись комментария в комментарии с помощью одинаковых обозначений комментария недопустима.
Зато совершенно свободно вы можете сделать запись комментария в комментарии с
помощью разных обозначений, например:
{ ... (* ... *) ... } или так (* ... { ... } ... *).
Правил для написания комментариев не существует. Однако, можно дать некоторые
рекомендации
по использованию комментариев в различных частях программы.
Вот несколько характерных случаев, когда комментарии желательны.
1. В начале программы сразу после заголовка целесообразно указать назначение
программы, автора, дату написания и другие данные о программе, например:
Program bid;
{Программа определения большего из двух чисел}
{автор программы Иванов Александр Петрович}
{программа составлена 12.10.1993}
{программа доработана 20.10.1993}
{программа протестирована 20.10.1993}
2. В описаниях переменных указывается назначение переменных:
var
a,{первое число}
b,{второе число}
c,{их наибольший общий делитель} ...
34 
3. Объясняются действия, смысл и назначение которых непонятны:
c := a mod b {остаток от деления a на b}
d := b*b - 4*a*c {вычисление дискриминанта квад. ур-я}
В программе желательны короткие и ясные комментарии. В противном случае текст
программы может затеряться среди комментариев и программа станет еще менее ясной.
Составим программу для первого примера на основе второго способа.
Он основан на применении двух операций с целыми числами - деления (div) и
нахождения остатка от деления (mod).
Посмотрите на примере, в чём состоит математика этого способа.
Находим цифру единиц:
342 mod 10 = 2.
Делим заданное число на 10, при этом уже найденная цифра единиц "отбрасывается":
342 div 10 = 34.
Находим цифру десятков:
34 mod 10 = 4.
Делим, оставшееся число 34 на 10, при этом цифра десятков "отбрасывается", а результатом будет цифра сотен:
34 div 10 = 3.
Дальнейшие операции такие же, как и в первом способе.
Программа
Program Problem;
uses WinCrt;
var
a, c, s, d, e, b, r : integer;
begin
write('Введите трехзначное число '); readln(a);
c := a; {Запоминается первоначальное число}
e := a mod 10; (* Цифра единиц *)
a := a div 10;
d := a mod 10; (* Цифра десятков *)
s := a div 10; (* Цифра сотен *)
b := e*100 + d*10 + s;
(* Число, записан. в обратном пор. *)
r := c - b; (* Разность чисел *)
writeln('Искомая разность равна ', r)
end.
35

ВЫВОДЫ
В программе можно использовать комментарии, которые записываются в фигурных
скобках { ... } или в круглых скобках со звездочкой (* ... *). Повторная запись одних и тех
же скобок недопустима. При записи комментария в комментарии надо использовать разные скобки.
Операция a mod b выдает остаток от деления a на b. Если деление происходит нацело, то результат операции равен нулю.
Задание 1
1. Введите эти две программы в компьютер и выполните. Измените вторую программу так, чтобы для определения цифр трехзначного числа надо было бы делить только
на 10 (в приведенных программах используется деление на 100 и на 10).
2. Применяя этот способ, составьте программу, которая подсчитывает сумму и произведение цифр введенного четырехзначного числа.
5. Оператор if ... then ... else
Многие представляют ЭВМ как чисто вычислительную машину, что является заблуждением. ЭВМ способна, подобно человеку, принимать решения.
Вот некоторые простые решения, которые принимает человек в зависимости от
условия.
Если пойдет дождь, тогда надо взять зонтик,
иначе, зонтик не брать.
Если в комнате темно, тогда надо включить свет.
Человек, принимая какое-то решение, может сомневаться, взвешивать, прикидывать,
машина принимает решения категорически: либо - да, либо - нет и никаких сомнений.
Для реализации принимаемых решений на языке Паскаль могут быть использованы
операторы if (если), then (тогда) и else (иначе).
После оператора if записывается условие, а после операторов then и else - команды,
которые необходимо выполнить.
Для более ясного понимания использования этих операторов, рассмотрим следующий пример.
Пример 2. Составить программу, после выполнения которой меньшее из двух неравных чисел будет увеличено вдвое, а большее оставлено без изменения.
Программа
Program Problem2; { Увеличения меньшего из двух целых чисел вдвое }
uses WinCrt;
var
a, b, c : integer;
begin
write('Введите первое целое число '); readln(a);
write('Введите второе целое число '); readln(b);
36 
if a < b then c := 2*a
else c := 2*b;
writeln('Меньшее число ', c div 2);
writeln('Оно же увеличенное вдвое ', c)
end.
После пуска программы вводятся два целых числа и их значения присваиваются переменным a и b. Далее, в операторе if проверяется условие (a<b), если оно выполняется,
т.е. a меньше b, тогда выполняются команды в операторе then, переменной c присваивается значение удвоенного числа a, иначе выполняются команды в операторе else, переменной c присваивается значение удвоенного меньшего числа - b.
После этого выводится на экран меньшее число и это же число, но увеличенное
вдвое.
Заметьте, в процедуре writeln, кроме вывода информации, выполняется еще и деление переменной c на 2.
В процедуре write (writeln) можно записывать выполнение арифметических операций.
Ещё одно существенное замечание. Вы уже заметили, что перед оператором else
точка с запятой не ставится.
Программа имеет один недостаток. В ней не учитывается то, когда введенные числа
будут равны. В этом случае на экран надо выдать сообщение: "Числа равны".
Программа
Program Problem2a; {Программа удвоения меньшего из двух чисел}
uses WinCrt;
var
a, b, c : integer;
begin
write('Введите первое число '); readln(a);
write('Введите второе число '); readln(b);
if a = b then writeln('Числа равны')
else
begin
if a < b then c := 2*a
else c := 2*b;
writeln('Меньшее число ', c div 2);
writeln('Удвоенное меньшее число ', c)
end
end.
В этой программе два условных оператора, первым проверяется условие равенства
чисел и, в случае его выполнения, будет выдано сообщение о равенстве чисел, которое
находится в операторе then.
В операторе else записано несколько команд, поэтому в нём установлены операторные скобки:
begin
........
end;
37

Такие же операторные скобки в необходимых случаях могут быть использованы и в
операторе then.
ВЫВОДЫ
В операторах then и else могут быть использованы операторные скобки:
begin ... end;,
где записывается еще одна группа операторов.
Перед оператором else точка с запятой не ставится.
Задание 2
1. Введите первую программу примера 2 и выполните ее. Измените программу так,
как это было сделано во втором случае, т. е. с учетом равенства вводимых чисел.
2. Составьте программу определения большего из двух чисел.
3. Составить программу определения модуля числа.
6. Вещественный тип real в операторах if ... then ... else ... .
Для дальнейшего составления программ на Паскале нам недостаточно целых чисел.
Например, мы хотим составить программу решения квадратного уравнения вида:
ax2 + bx + c = 0.
Коэффициенты этого уравнения могут принимать не только целые значения, но любые действительные (a не равно нулю), также значения корней этого уравнения принимают значения из множества действительных чисел.
Действительные или вещественные числа объединяют в себе целые числа и дробные
числа (рациональные и иррациональные).
Переменные, принимающие вещественные значения, имеют тип, который на языке
Паскаль обозначается: real.
Например: var a, b, c : real;
Это означает, что переменные a, b и c принимают вещественные значения.
7. Формы записи вещественных чисел
В математике
На Паскале
1. Естественная форма записи
135; 89245; -2,356; 0,28;
135; 89245; -2.356; 0.28
Как видите, отличие заключается в том, что вместо запятой используется точка.
2. Экспоненциальная форма записи или форма записи с плавающей запятой
3,7  105; 1,67  10-12
3.7E05; 1.67E-12.
При такой записи, множитель, стоящий перед степенью с основанием 10 называется
мантиссой, а показатель степени десятки - порядком числа.
В наших примерах: 3.7 и 1.67 - мантиссы, а 5 и -12 - порядки чисел.
Мантисса может иметь 11...12 значащих цифр, а порядок от -39 до 38. (Это в Турбо
Паскале версии 7.0 и Barland Pascal.)
38 
8. Арифметические операции с вещественными переменными
Операция
Сложение
Вычитание
Умножение
Деление
Запись на Паскале
a+b
a-b
a*b
a/b
Как видите, единственным отличием от операций с целыми числами - это операция
деления, которая обозначается наклонной чертой.
Кроме арифметических операций, в Паскале существуют так называемые стандартные или встроенные функции, которые выполняются сразу после указания их имени, заведомо объявленных в Паскале, после которого в скобках записывается аргумент
функции.
Функция
Математическое
обозначение
x2
|x|
Ее объявление на Паскале
Квадратичная
sqr(x)
Абсолютная величина
abs(x)
Квадратный корень
sqrt(x)
x
Синус
sinx
sin(x)
Косинус
cosx
cos(x)
Арктангенс
arctgx
arctan(x)
Натуральный логарифм
lnx
ln(x)
x
Показательная функция
exp(x)
e
(экспонента)
Некоторые из перечисленных встроенных функций могут быть использованы с целыми числами или переменными целого типа (аргумент имеет тип integer).
К таким функциям относятся:
Квадратичная: x2 - sqr(x). Абсолютная величина: |x| - abs(x).
На Паскале нет функций вычисления arcsinx, arccosx, arcctgx. Как с помощью уже
известных встроенных функций вычислить значения функций arcsinx, arccosx, arcctgx?
Для этого надо совершить небольшую экскурсию в математику и выразить значение
функций arcsinx, arccosx, arcctgx через функцию arctgx.
Arcsinx
Пусть arcsin x  y, где |x| | x |  1 и   / 2  y   / 2 , тогда tg(arcsin x )  tgy, отсюsin(arcsin x )
sin(arcsin x )
x
да
 tgy, или

tgy
,
 tgy получаем,
cos(arcsin x )
1  sin 2 (arcsin x )
1 x 2


x 
x 
 окончательно имеем: arcsin x  arctg
.
y  arctg
 1 x 2 
 1 x 2 
Функция
Математическая обозначение
Арксинус
arcsinx
Ее объявление на Паскале
 x
arctan 

2
 1 x




39

Аналогичными рассуждениями можно получить выражения для arccosx и arcctgx.
Функция
Математическое обозначение
Ее объявление на Паскале
Арккосинус
arccosx
 1 x 2 

arctan 
x 

Арккотангенс
arcctgx
arctan(1 / x ) или pi / (2  arctan(x ))
Пример 3. Составить программу решения квадратного уравнения
ax2 + bx + c = 0.
Наметим план составления программы или, иначе говоря, алгоритм.
Под алгоритмом мы будем понимать последовательность указаний для составления программы.
Алгоритм
1. Начало.
Описание переменных и их типов.
2. Ввод значений коэффициентов.
3. Вычисление значения дискриминанта (d).
Если d < 0, тогда уравнение не имеет корней,
иначе,
если d = 0,
тогда уравнение имеет один корень,
вычислить значение этого корня и выдать его на экран,
иначе, уравнение имеет два корня,
вычислить их и выдать на экран.
4. Конец.
Составим программу, пользуясь алгоритмом.
Program Problem3; { Программа решения квадратного уравнения }
uses WinCrt;
var
a, b, c, d, x1, x2 : real;
begin
write('Введите коэффициенты уравнения ');
readln(a, b, c);
d := b*b - 4*a*c;
if d < 0 then writeln('Уравнение не имеет корней')
else
if d=0
then
writeln('Уравнение имеет один корень ',-b/(2*a))
else
begin
x1 := (-b - sqrt(d))/(2*a);
x2 := (-b + sqrt(d))/(2*a);
write('Уравнение имеет два различных корня ');
writeln('x1 = ', x1, ' x2 = ', x2)
end
end.
40 
Разберем структуру программы и посмотрим как она будет работать.
ИМЯ ПРОГРАММЫ И КОММЕНТАРИЙ
Имя программы "Problem3;", после этого в комментарии записано содержание программы: "{Программа решения квадратного уравнения};".
РАЗДЕЛ ОПИСАНИЙ
В разделе описаний указаны имена переменных и их типы. Понятно, что переменные
a, b, c нужны для значений коэффициентов уравнения, переменная d для значений дискриминанта, а x1 и x2 для корней уравнения. Понятно, что все они принимают вещественные значения, ограничиться целыми невозможно, и имеют тип: real.
РАЗДЕЛ ОПЕРАТОРОВ
Раздел операторов начинается вводом информации. С помощью оператора:
write('Введите коэффициенты уравнения '); readln(a, b, c);
на экран выводится информация, записанная в этом операторе write:
Введите коэффициенты уравнения
В ответ на этот запрос, пользователю надо ввести коэффициенты уравнения, разделяя их пробелами (проще говоря, ввести через пробелы).
Обратите внимание на такую мелочь, в операторе writeln, перед вторым, "заканчивающим" запись апострофом, оставлен пробел. Для чего? Только из эстетических соображений. Следующий оператор readln(a, b, c); будет вводить информацию, которую вы
наберете с клавиатуры. Если этого пробела не будет, то вводимое число будет писаться
вплотную к слову "уравнения", что, конечно, некрасиво.
Далее вычисляется значение дискриминанта и присваивается переменной d.
Первым условным оператором if проверяется условие d < 0, если оно выполняется,
тогда на экран выдается сообщение, записанное после then в операторе writeln: "Уравнение не имеет корней", иначе после else, новое условие if d = 0, тогда выполняются операторы после then, т.е. выдается сообщение, что уравнение имеет один корень, вычисляется
его значение и выдается на экран, так как всё это записано в скобках оператора writeln,
иначе, остается одно, - когда дискриминант больше нуля, тогда надо выполнить несколько
операторов, которые записаны после else. Но поскольку их несколько, то необходимо открыть операторные скобки begin, в которых и записать вычисление значений корней и
вывод их на экран. После чего необходимо закрыть операторные скобки служебным словом end.
После этого программа заканчивается служебным словом end с обязательной точкой
в конце.
Каждая операторная скобка, начинаемая словом begin должна обязательно "закрываться" словом end. Если это слово оказывается перед оператором else или является
предпоследним, то точка с запятой после end не ставится. Во всех других случаях end
заканчивается точкой с запятой, а заканчивающий программу - точкой.
41

9. Форматированный вывод информации
Если вы выполните программу, то столкнетесь с неприятным явлением - результат,
т.е. числовые значения корней, будут выдаваться на экран в экспоненциальной форме.
Так, после ввода значений коэффициентов: 2 3 -10, на экран будет выдан результат:
Уравнение имеет два различных корня
x1 = -3.1084952830E+00
x2 = 1.6084952830E+00
Во-первых, такой результат неудобно читать и запоминать, во-вторых, нам не всегда
нужна высокая точность вычисления и, в-третьих, даже целые значения корней будут
выдаваться тоже в экспоненциальной форме, что уже совсем неудобно.
Чтобы избежать всех этих неприятностей, можно использовать форматированный
вывод информации.
В Турбо-Паскале предусмотрен вывод данных с форматами. В общем случае формат
имеет следующий вид:
r:f1:f2
Здесь r - имя переменной, значение которой выводится (в данном случае - x1 или x2),
формат f1 указывает, сколько позиций нужно для всего числа, включая знак числа, целую
часть, точку и дробную часть числа; f2 - число позиций дробной части числа (после точки).
Если формат указан, то значение переменной r выводится в виде константы с фиксированной запятой, например: 12.35, .123. Если параметры f1 и f2 опущены, то вещественная переменная выводится в виде константы с плавающей запятой, например:
2.534E03, 5.67E-12 и т.п. В этом случае значения f1 и f2 устанавливается по умолчанию.
Надо вообще заметить, что вещественное число в формате с фиксированной точкой
печатается так:
несколько пробелов; знак минус (-) или пробел; последовательность цифр (целая
часть); точка; последовательность цифр (дробная часть).
Рассмотрим несколько примеров форматированного вывода результатов для вещественных переменных.
Пример. Пусть переменная r получает значение частного от деления вещественных
переменных a на b.
Составим небольшую программу и выполним ее несколько раз, устанавливая различные значения для форматированного вывода результата.
Program Problem;
uses WinCrt;
var
a, b, r : real;
begin
write('Введите значение переменной a '); readln(a);
write('Введите значение переменной b '); readln(b);
r := a/b;
writeln('Результат равен ', r)
end.
При первом выполнении программы не устанавливайте параметров для форматированного вывода. Вы получите результат в форме с плавающей запятой. При следующем
42 
выполнении для a введите значение 1, для b 3, а для вывода результата установите следующий формат: r:6:2; затем, r:1:5; r:0:4 и т.п.
Форматированный вывод возможен и для переменных целого типа, но в этом случае
нужен только один параметр:
r:f1
Если значение формата f1 больше, чем необходимое число позиций для записи числа, то перед числом добавляется соответствующее число пробелов. Если значение f1
меньше, оно автоматически увеличивается до числа позиций, необходимого для вывода
числа.
Изменим в программе две строки вывода информации:
writeln('Уравнение имеет один корень ', -b/(2*a):6:3) и
writeln('x1 = ', x1:6:3, ' x2 = ', x2:6:3)
Теперь понятно, что для выводимых результатов отведено 6 позиций, а для дробной
части - 3 позиции, т.е. до тысячных долей (думается этого достаточно для школьных задач).
Задание 3
1. Наберите программу в первоначальном ее варианте и выполните, а затем измените
ее, применив форматированный вывод результата, и выполните еще раз. Сравните результаты.
2. Составьте программу решения линейного уравнения ax = b и выполните ее.
10. Блок-схемы, изображающие условные операторы
Вы уже знаете, что составление программы можно изображать геометрическими фигурами - блоками, в результате чего образуется схема программы. Такая конструкция
называется блок-схемой.
Какой геометрической фигурой принято обозначать условие? Посмотрите на ниже
приведенную конструкцию и вы увидите, что условие изображается ромбом (см. рис. 17).
Условие
Серия команд 2
Условие
Серия команд 1
Серия команд
Рис. 17
Пример 4. Два прямоугольника заданы длинами сторон. Написать программу, после
выполнения которой выясняется, можно ли первый прямоугольник целиком разместить во
втором. (Рассмотреть только случай, когда соответствующие стороны прямоугольников
параллельны.)
Математика этой задачи проста, возможные случаи изображены на рисунке 18, блоксхема на рис. 19:
43

b1 b2
a1
a1
b1
a2
a2
b2
Рис. 18
Блок-схема для составления
программы
Начало
Ввод длин сторон
прямоугольников
a1, b1, a2, b2
нет
Если
a1<a2 и b1<b2
или
b1<a2 и a1<b2
Первый прямоугольник не
размещается во втором
да
Первый прямоугольник целиком
размещается во втором
Конец
Рис. 19
Пользуясь блок-схемой составим программу
Program Problem4;
uses WinCrt;
var
a1, b1, a2, b2 : real;
begin
write('Введите длину и ширину первого прямоугольника ');
readln(a1, b1);
write('Введите длину и ширину второго прямоугольника ');
readln(a2, b2);
if ((a1 < a2) and (b1 < b2)) or ((b1 < a2) and (a1 < b2))
then writeln('Первый прямоугольник размещается во втором')
else writeln('Первый прямоугольник не размещается во втором')
end.
44 
Задание 4
1. Введите эту программу и выполните.
2. Составьте программу, в результате выполнения которой выясняется, входят ли
четные цифры в запись данного трехзначного числа.
Упражнения
1. Дано целое число n  10. Написать программу получения последней и предпоследней цифр записи этого числа.
2. Даны три числа a, b, c. Написать программу, в результате которой числа удвоятся,
если a  b  c, и числа будут заменены на их абсолютные величины в прочих случаях.
3. Составьте программы определения большего (меньшего) из трех чисел.
4. Написать программу, при выполнении которой выводится 1, если данное число x
принадлежит отрезку [a, b], где a и b заданные числа, и выводится 0 в противоположной
ситуации.
5. Точка плоскости задана своими координатами x, y. Написать программу, при выполнении которой определяется, принадлежит ли данная точка плоской фигуре, являющейся кольцом с центром в точке (0, 0), с внутренним радиусом 3 и с наружным радиусом
4.
6. Даны положительные числа x, y, z. Выяснить, существует ли треугольник с длинами сторон x, y, z?
7. Определить является ли данное целое число четным.
8. Определить, верно ли, что при делении целого неотрицательного числа a на целое
положительное число b получается остаток r или s.
9. Составить программу решения биквадратного уравнения
ax 4  bx 2  c  0.
Ответы
К заданию 1
Program Task1;
uses WinCrt;
var
a, e, d, s, t, s1, p : integer;
begin
write('Введите четырехзначное число '); readln(a);
e := a mod 10; a := a div 10;
d := a mod 10; a := a div 10;
s := a mod 10; t := a div 10;
s1 := e + d + s + t; {Сумма цифр}
p := e*d*s*t; {Произведение цифр}
writeln('Сумма цифр числа равна ', s1);
writeln('Произведение цифр равно ', p)
end.
45

К заданию 2
Задача 2
Program Task2_2;{Определение большего из двух чисел}
uses WinCrt;
var
a, b, c : integer;
begin
write('Введите первое число '); readln(a);
write('Введите второе число '); readln(b);
if a = b then writeln('Числа равны')
else if a > b then writeln('Большее число ', a)
else writeln('Большее число ', b)
end.
Задача 3
Program Task2_3;{Определение модуля числа}
uses WinCrt;
var
a : integer;
begin
write('Введите целое число '); readln(a);
if a >= 0 then writeln('Модуль числа ', a, ' равен ', a)
else writeln('Модуль числа ', a, ' равен ', -a)
end.
К заданию 3
Program Task3; { Решение уравнения ax = b }
uses WinCrt;
var
a, b : real;
begin
write('Введите первый коэффициент '); readln(a);
write('Введите свободный член '); readln(b);
if a <> 0 then writeln('Уравнение имеет одно решение ', b/a:6:3)
else if (a = 0) and (b <> 0)
then writeln('Уравнение не имеет решений')
else writeln('Уравнение имеет б/м решений')
end.
К заданию 4
Program Task4; { Входят ли четные цифры в запись трехзначного числа? }
uses WinCrt;
var
a, s, d, e : integer;
begin
write('Введите трехзначное число '); readln(a);
e := a mod 10; a := a div 10; d := a mod 10; s := a div 10;
if (s mod 2 = 0) or (d mod 2 = 0) or (e mod 2 = 0)
then writeln('Четные цифры входят в запись этого числа')
else writeln('Четные цифры не входят в запись числа')
end.
46 
Глава 4. Операторы организации цикла. Цикл "пока...".
Оператор while ... do ... . Оператор перехода goto. Метки
1. Что такое цикл?
Давайте отвлечемся на некоторое время от программирования и попытаемся на природных явлениях, примерах из повседневной жизни человека, а затем и его мыслительной
деятельности дать понятие цикла.
Если вас спросят, что такое цикл, то, наверное, вы не задумываясь ответите, что это
повторяемость чего-то.
И это совершенно правильно!
Повторяемость времен года в природе - это цикл, кругооборот воды в природе - это
цикл, смена дня и ночи - это цикл и многие другие процессы в природе повторяются, образуя циклы или, что чаще нами употребляется, цикличность.
Циклы в математике - явление очень часто встречающееся.
Например, пока натуральные числа меньше 10, тогда надо суммировать их.
Другими словами, мы находим сумму чисел от 1 до 10.
В этом примере повторяется сложение натуральных чисел, пока выполняется условие (числа меньше 10).
Такие циклы называются циклами с предыдущим условием или, коротко, с предусловием, потому что условие записывается перед выполнением повторяющейся группы
операторов.
Цикл в программировании - это многократно выполняемая группа команд,
часть программы.
Сразу заметим, что в программе может быть такая ситуация, когда цикл вообще
не выполняться ни разу.
На языке Паскаль возможны циклы с предусловием, которые организуются с помощью оператора:
while (пока) ... do (выполнять) ...
Формат оператора: while <условие> do <операция>.
Работа оператора заключается в том, что операция выполняется до тех пор, пока будет выполняться условие, указанное в операторе while.
Если операция содержит не один оператор, а несколько, то их объединяют с помощью ОПЕРАТОРНЫХ СКОБОК begin и end, например;
while <условие> do
begin
S1; S2; S3; ...
end;
В этом примере символами s1, s2, s3, ... обозначены операторы.
Действие цикла while ... do ... можно изобразить графически следующей схемой (см.
рис. 20):
47

Условие
Оператор
Рис. 20
Рассмотрим работу оператора while ... do ... на примере.
Пример 1. Определить и вывести на экран цифры целого числа n.
Разберем математику этого вопроса на частном примере.
Найдем цифры числа 4538. Для этого надо найти остаток от деления 4538 на 10 с
помощью операции нахождения остатка от деления целых чисел (mod):
4538 mod 10 = 8, получим последнюю цифру числа (она же является первой справа).
Выдаем сообщение: "1 - я цифра справа равна 8".
После этого выполним целочисленное деление заданного числа 4538 на 10, получим
453 (остаток отбрасывается):
4538 div 10 = 453.
Далее процесс повторяем:
2 - й раз;
453 mod 10 = 3
2 - я цифра справа равна 3,
453 div 10 = 45,
3 - й раз;
45 mod 10 = 5,
3 - я цифра справа равна 5,
45 div 10 = 4,
4 - й раз;
4 mod 10 = 4,
4 - я цифра справа равна 4,
4 div 10 = 0.
Обратите внимание! Процесс будет продолжаться пока число n не равно нулю. Как
только оно станет равно нулю цикл заканчивается.
В программе еще надо указывать какая по счету цифра в числе справа. Для этого
надо завести еще одну переменную в качестве счетчика. Эта переменная каждый цикл
должна увеличиваться на 1.
48 
Программа
Program Problem1; {Опред. и вывод на экран цифр числа.}
uses WinCrt;
var
n, p, i : integer;
begin
write('Введите натуральное число n <= 32767 '); readln(n);
i := 1;
while n <> 0 do
begin
p := n mod 10;
writeln(i, ' - я цифра справа равна ', p);
n := n div 10;
i := i + 1
end
end.
Построение программы и ее работа.
В разделе описаний
Переменная n для целого числа, p - для цифр числа, i - счетчик цифр.
В разделе операторов
С помощью оператора write выводится на экран запрос для пользователя о вводе целого числа. Оператор readln заносит его значение в память и присваивает переменной n.
Счетчику i устанавливается первоначальное значение 1.
В операторе while записывается условие (пока n не равно 0), при котором цикл будет
выполняться.
Так как в цикле несколько операторов, то используются операторные скобки
begin ... end.
В них записаны операторы:
p := n mod 10; - определяется последняя цифра;
writeln(i,' - я цифра справа равна ', p); - выводится на экран порядковый номер цифры
справа и сама эта цифра;
n := n div 10; - от числа "зачеркивается" последняя цифра;
i := i + 1; - счетчик увеличивается на 1.
Задание 1
1. Введите эту программу и выполните.
2. Составьте программу, которая подсчитывает сумму цифр заданного числа.
Пример 2. Составить программу перестановки первой и последней цифр введенного
натурального числа.
Математику этого вопроса разберем на частном примере.
Пусть пользователем введено число 4538. После перестановки первой и последней
цифр число станет таким: 8534.
Определить последнюю цифру числа нетрудно. Это можно сделать уже известным
нам способом: 4538 mod 10.
Чтобы найти и отделить первую цифру числа, надо использовать прием, который
применялся в предыдущих программах для вывода цифр числа и для подсчета суммы
49

цифр, т. е. отделять по одной цифре справа. Но, если в предыдущих программах такой
процесс продолжался до тех пор пока n <> 0 (n не равнялось нулю), а когда n становилось
равным нулю, то цикл заканчивался т. е. все цифры, включая первую, отделялись, то теперь надо этот процесс остановить на одну цифру раньше и тогда последним значением
переменной n будет первая цифра числа.
В нашем примере она равна 4.
Итак, первая и последняя цифры найдены. Как переставить их в числе.
Для введенного нами числа это можно сделать так. Вычесть из него первую цифру,
умноженную на 1000 и вычесть последнюю цифру:
4538 - 4  1000 - 8 = 530.
К полученному результату прибавить последнюю цифру - 8, умноженную на 1000 и
прибавить первую цифру: 530 + 8  1000 + 4 = 8534.
Две последние операции можно записать в одной строке:
4538 - 4  1000 - 8 + 8  1000 + 4 = 8534.
Возникает одна трудность. Как определить разряд, в котором находится первая цифра числа (первая слева) и на сколько надо умножить ее при вычитании? Тысячи ли это, десятки тысяч или другой разряд?
Для того, чтобы это выяснять заведем переменную, первоначальное значение которой 1, а затем, каждый раз при отделении цифры она умножается на 10.
Посмотрим весь процесс на примере того же числа 4538.
Первоначальные значения: n = 4538, i = 1.
Цикл продолжается пока n  10, 4538  10 - истина, значит операторы цикла выполняются первый раз: i := i*10 = 1*10 = 10; - переменная i получает первое значение,
n := 4538 div 10 = 453.
Проверка условия: 453  10 - условие выполняется, значит цикл выполняется второй
раз: i := i*10 = 10*10 = 100; n := 453 div 10 = 45.
Проверка условия: 45  10 - истина, значит цикл выполняется третий раз:
i := i*10 = 100*10 = 1000, n := 45 div = 4.
Проверка условия: 4>=10 - ложь, значит операторы цикла не выполняются. Цикл заканчивается.
Конечные значения переменных: n = 4 - первая цифра числа, i = 1000. Теперь остается выполнить сам процесс перестановки цифр и выдать результат на экран.
Программа
Program Problem2; { Перест. первой и последней цифр числа }
uses WinCrt;
var
n, n1, p, a, i : integer;
begin
write('Введите натуральное число n '); readln(n);
a := n; i := 1;
p := n mod 10; {последняя цифра введенного числа}
while n >= 10 do
begin
i := i*10;
n := n div 10;
end;
n1 := a - n*i - p + n + p*i;
writeln('Число после перестановки цифр ', n1);
end.
50 
2. Целый тип longint
Турбо-Паскаль имеет возможности для расширения диапазона значений целых переменных.
Так, если тип integer устанавливает диапазон целых значений от -32768 до 32767, то
целый тип longint расширяет его от -2147483648 до 2147483647.
Итак, если установить тип переменных longint, тогда выше приведенные программы
будут работать для значительно большего множества целых чисел.
Программы станут такими:
Program Problem1; { Опред. и вывод на экран цифр числа }
uses WinCrt;
var
n, p, i : longint;
begin
write('Введите натуральное число n '); readln(n);
i := 1;
while n <> 0 do
begin
p := n mod 10;
writeln(i, ' - я цифра справа равна ', p);
n := n div 10;
i := i+1
end
end.
Program Sum; { Сумма цифр числа }
uses WinCrt;
var
a, n, s, p : longint;
begin
write('Введите натуральное число n '); readln(n);
a := n; s := 0;
while n <> 0 do
begin
p := n mod 10; {Определяются цифры числа}
s := s + p; {Находится их сумма}
n := n div 10
end;
writeln('Сумма цифр числа ', a, ' равна ', s)
end.
Program Problem2a; { Перест. первой и последней цифр числа }
uses WinCrt;
var
n, n1, p, a, i : longint;
begin
write('Введите натуральн. число n <= 2147483647 ');
readln(n);
a := n;
i := 1;
51

p := n mod 10; {последняя цифра введенного числа}
while n >= 10 do
begin
i := i*10;
n := n div 10;
end;
n1 := a - n*i - p + n + p*i;
writeln('Число после перестановки цифр ', n1);
end.
Подведем итог о целых типах.
Диапазон возможных значений целых типов зависит от их внутреннего представления, которое может занимать один, два или четыре байта. В таблице приводятся названия
целых типов, длина их внутреннего представления в байтах и диапазон возможных значений.
Целые типы
Длина, байт
1
1
2
2
4
Название типа
byte
shortint
word
integer
longint
Диапазон значений
0 ... 255
-128 ... 127
0 ... 65535
-32768 ... 32767
-2147483648 ... 2147483647
При использовании процедур и функций с целочисленными па раметрами следует
руководствоваться "вложенностью" типов, т.е. везде, где может использоваться WORD,
допускается использование BYTE (но не наоборот), в LONGINT входит INTEGER, который, в свою очередь, включает в себя SHORTINT.
Целый тип данных относится к порядковым типам, которые отличаются тем, что
каждый из них имеет конечное число возможных значений. Эти значения можно определенным образом упорядочить и, следовательно, с каждым из них можно сопоставить некоторое целое число - порядковый номер значения (отсюда название типов - порядковый).
Вещественные типы, строго говоря, тоже имеют конечное число значений, которое
определяется форматом внутреннего представления вещественного числа. Однако количество возможных значений вещественных типов настолько велико, что сопоставить с каждым из них целое число (его номер) не представляется возможным.
Порядковый и вещественный типы, в свою очередь, относятся к простым типам.
Задание 2
1. Выполните эту программу на компьютерах.
2. Написать программу переработки данного целого числа n  10 в целое число, записанное теми же цифрами, но в обратном порядке.
52 
3. Условия в программах с циклами
Рассмотрим два примера, в программах которых используются не только циклы, но
и в циклах необходимо применение условного оператора
if ... then ... else ...
Пример 3. Составить программу разложения натурального числа n на простые множители.
Прежде вспомним, что к простым числам относятся все те натуральные числа,
которые имеют только два делителя - единицу и само себя.
Натуральные числа, имеющие более двух делителей называются составными.
Единица имеет только один делитель - само себя и поэтому она не может относится
ни к простым, ни к составным числам. Если выписать простые числа в порядке их возрастания, начиная от самого меньшего - 2, то получим следующий ряд чисел:
2, 3, 5, 7, 11, 13, 17, 19, 23, 29, ...
А теперь вспомним, как в младших классах мы раскладывали натуральные числа на
простые множители.
Для этого берем первое простое число - 2 и пробуем делить данное натуральное число на 2, если число делится на 2, тогда надо 2 записать, а число разделить на 2 и снова полученный результат пробуем делить на два, если делится, тогда повторяем процесс деления, если не делится, тогда пробовать делить на следующее простое число - 3 и так далее.
Обычно такой процесс мы записывали "столбиком":
Например:
или
360 2
360:2  180,
180 2
180:2  90,
90 2
90:2  45,
45 3
45:3  15,
15 3
15:3  5,
5 5
5:5  1.
1
Таким образом, число 360 можно разложить на следующие простые множители: 360
= 2  2  2  3  3  5.
Самый простой алгоритм для составления программы может быть таким.
Алгоритм
В качестве первого делителя взять 2, присвоить это значение некоторой переменной
i;
начать цикл "пока i <= n";
если данное число n делится на i, тогда выдать на экран значение i и разделив данное число на i, присвоить новое значение той же переменной n (n := n div i);
далее цикл продолжить, но значение i не увеличивать на 1, а проверить деление нового значения n на прежнее значение i;
если n не делится на i, тогда i увеличить на 1 (i := i + 1) и продолжить цикл, т.е. выполнить проверку условия цикла (i <= n), а затем снова проверить деление n на уже новое
значение i.
Обратите внимание, что при таком алгоритме в качестве делителей уже не попадут
составные числа. Объясните почему?
53

Программа
Program Problem3; { Разлож. числа на прост. множит.. 1- й спос. }
uses WinCrt;
var
n, i : integer;
begin
write('Введите натуральное число '); readln(n);
write('Простые делители числа ', n, ' следующие; ');
i := 2;
while i <= n do
if n mod i =0 then
begin
write(i, ' ');
n := n div i
end
else i := i + 1
end.
Конечно, эта программа далека от совершенства и не может иметь претензии на оригинальность.
Она заставляет компьютер выполнять много лишних проверок на деление.
Вот более совершенный алгоритм.
Он основывается на следующих соображениях.
Вначале находим все делители, равные 2. Для этого последовательно делим число
360 на 2:
360:2  180,
180:2  90,
90:2  45.
После этого, полученный результат делим на нечетные числа. Причем на каждое нечетное число делим не один раз, а до тех пор, пока такое деление будет возможным.
Делим на 3: 45:3 = 15, 15:3 = 5.
Делим на 5: 5:5 = 1.
Делим на 7, не делится, пробуем делить на следующее нечетное число.
Делим на 9, не делится, переходим к следующему нечетному числу.
Делим на 11, не делится, и так далее.
До тех пор будем пробовать деление на нечетные числа, пока они будут меньше или
равны получаемому частному от деления числа на соответствующий делитель.
На основании этих соображений составляем программу.
Program Problem3a;
uses WinCrt;
var
i, n : integer;
begin
write('Введите целое число '); readln(n); writeln;
writeln('Простые делители целого числа ', n);
{----------------------------------------------------------------------------------------}
while n mod 2 = 0 do { Цикл для вывода делителей, равных 2 }
begin
54 
write(2, ' ');
n := n div 2
end;
{----------------------------------------------------------------------------------------}
i := 3;
while i <= n do
{ Цикл для нечетных делителей }
if n mod i = 0
then
begin
write(i, ' ');
n := n div i
end
else i := i + 2;
writeln
end.
Можно расширить область вводимых чисел, используя уже известный тип
longint:
Еще один пример, где используются цикл и условие.
Пример 4. Написать программу, в результате выполнения которой выяснится, входит ли цифра 2 в запись данного целого числа n.
Идея составления программы проста. Надо организовать цикл, в котором выделять
цифры числа уже известным вам способом и каждую из них сравнивать с цифрой 2. Если
цифра числа оказывается равной двум, тогда надо счетчик, которым может быть некоторая числовая переменная, увеличивать на единицу, иначе, цикл надо продолжать.
Когда цикл будет выполнен полностью, т. е. все цифры числа проверены и каждая из
них будет сравнена с цифрой 2, надо снова использовать условный оператор и сравнить
значение переменной - счетчика с нулем. Если значение переменной равно нулю, то это
значит, что цифра 2 не входит в запись числа, иначе - входит.
АЛГОРИТМ
1. Начало. Переменные целого типа n, p, k: n - для вводимого числа; p - для цифр
этого числа; k - счетчик, подсчитывающий количество цифр в числе, равных 2.
2. Ввод целого числа.
Счетчику k устанавливается первоначальное значение 0.
3. Цикл, пока n <> 0. В цикле, переменной p присваивать значение цифры числа.
Если p = 2, тогда увеличивать k на единицу.
Вычесть из числа n последнюю цифру и разделить его на 10.
Продолжить и закончить цикл.
4. Если k = 0, тогда выдать сообщение: "Цифра 2 не входит в запись числа", иначе,
выдать сообщение: "Цифра 2 входит в запись числа".
5. Конец.
Программа
Program Problem4; { Входит ли цифра 2 в запись числа }
uses WinCrt;
var
n, p, k : integer;
begin
55

write('Введите целое число '); readln(n);
k := 0;
while n <> 0 do
begin
p := n mod 10;
if p = 2 then k := k + 1;
n := n div 10
end;
if k = 0 then writeln('Цифра 2 не входит в запись этого числа')
else writeln('Цифра 2 входит в запись этого числа')
end.
Если вы внимательно разобрались в работе программы, то могли заметить, что во
многих случаях в программе будет проделываться бесполезная работа.
Например, если нами введено число 31572. В программе сделано так, что отделяется
по одной цифре справа и так продолжается до первой цифры слева.
Первой цифрой справа является 2. Казалось бы, раз в числе сразу первой цифрой
найдена двойка, то можно выдать сообщение, что число содержит цифру 2 и на этом работу закончить. Однако в программе сделано не так. Цикл будет продолжаться до последней
цифры числа и большая работа будет проделываться бесполезно.
Возникает необходимость в досрочном прерывании цикла. Как это сделать мы рассмотрим ниже.
3. Досрочное прерывание цикла. Метка. Оператор безусловного
перехода goto
Итак, если в числе появляется цифра 2, надо прервать цикл, т. е. нарушить естественный ход выполнения программы, выдать соответствующее сообщение и закончить
программу. Такой безоговорочный переход может выполнить оператор goto, который и
называется оператором безусловного перехода.
Оператор перехода указывает, что дальше программа должна выполняться,
начиная с оператора, помеченного меткой, которая записана в этом операторе перехода.
Оператор перехода имеет вид: goto <метка>. Здесь goto - зарезервированное слово (перейти на ... [метку]).
Метка в Турбо Паскале - это произвольный идентификатор, позволяющий именовать (помечать) некоторый оператор программы и таким образом ссылаться на него. Допускается в качестве меток (в том числе) использовать целые числа без знака (это сделано
с целью совместимости Турбо Паскаля со стандартным языком Паскаль).
Например:
goto 2341, goto 23, goto 1, goto bl1, goto mnk3, goto n56.
Любая метка должна быть описана в разделе описания меток, который обычно располагается в программе до начала раздела операторов:
label <список меток>.
Например: label 2341; label 1, 2; label bl1, 18, mnk.
В программе метка записывается перед оператором, на который осуществляется переход. Метка отделяется от оператора двоеточием. Между меткой и оператором можно
включать один или несколько пробелов, например:
1: writeln('Число не содержит цифру 2');
56 
Оператор можно помечать несколькими метками, которые в этом случае отделяются
друг от друга двоеточием.
1: 25: a := b div 10;
Теперь составим программу решения предыдущей задачи с использованием меток и
оператора перехода.
Ниже приведена эта программа.
Program Problem4a; { Входит ли цифра 2 в запись числа }
uses WinCrt;
label 1, 2;
var
n, p : integer;
begin
write('Введите целое число '); readln(n);
while n <> 0 do
begin
p := n mod 10;
if p = 2 then goto 1 else n := n div 10
end;
writeln('Цифра 2 не входит в запись этого числа');
goto 2;
1: writeln('Цифра 2 входит в запись этого числа');
2: end.
Внимательно разберитесь в ее работе. Постарайтесь ответить на следующие вопросы.
1) Зачем в программе две метки? Для чего служит каждая из них?
2) Почему в программу введен второй оператор перехода goto 2?
3) Как будет выполняться программа, если этот оператор исключить из нее?
Замечания
1. Оператор goto вносит фактическое безумие в составление программы. Посудите
сами, какой человек может идти, идти, а затем без всякой причины повернуться и пойти
обратно! У нормального человека всегда должна быть причина, условие такого поступка.
Оператор goto может заставить даже без всякой причины, условия нарушить естественный ход выполнения программы и перевести работу на помеченную строку.
Итак, оператор перехода изменяет последовательность выполнения операторов - они
выполняются не в том порядке, как написаны в тексте программы. Операторы перехода
нарушают связь между структурой выполнения (динамической) и текстовой (статистической) структурой программы.
Из-за этого программа становится менее понятной и труднее определяется ее правильность. Часто это становится гордиевым узлом, о котором программисты могут сказать: "Но все-таки программа работает". Почему и как работает программа, однако, остается секретом из-за оператора goto.
2. Частое использование операторов перехода указывает, что программист еще не
научился программировать "структурно", т. е. использовать последовательные, разветвляющиеся и циклические структуры управления.

57
Оператор перехода рекомендуется использовать только в исключительных случаях.
Такой случай может быть, когда цикл прерывается при удовлетворении определенного
условия. Именно такой случай есть в нашей программе.
3. Переход внутрь сложного оператора не определен. Ошибок такого рода транслятор может и не обнаружить.
1) if p then goto 3;
.....................
if q then 3: s;
2) while i<= 10 do
begin
s1;
3: s2;
end;
.............
goto 3;
4. Метка в Турбо Паскале - это произвольный идентификатор (может быть обозначен и буквами), позволяющий именовать некоторый оператор программы и таким образом
ссылаться на него.
В целях совместимости со стандартным языком Паскаль, в Турбо Паскале допускается в качестве меток использование целых чисел без знака.
Само собой возникает вопрос, можно ли программу примера 4 составить без оператора перехода goto?
Оказывается это возможно, о чем вы узнаете в следующих занятиях.
Задание 3
1. Введите и выполните две предыдущие программы. Измените их так, чтобы они
выполнялись для целых чисел больших 32767.
2. Найти все трехзначные числа, сумма цифр которых равна данному натуральному
числу. (Программа с циклом и условием.)
3. Найти двузначное число, обладающее тем свойством, что если сложить его с суммой кубов его цифр, то получится число, записанное теми же цифрами, но в обратном порядке. (Составьте программу с досрочным прерыванием цикла.)
4. Циклы в циклах
Рассмотрим еще один пример, где уже приходиться использовать два цикла, один
внутри другого.
Пример 5. Составить программу вывода всех натуральных чисел, меньших n, квадрат суммы цифр которых равен заданному числу m.
Сущность задачи такова. Вводится натуральное число, до которого надо выводить
все натуральные числа, удовлетворяющие заданному условию. Пусть, например, пользователь введет число - 21.
Второе число, которое надо ввести пользователю - это число, которому равен квадрат суммы цифр натуральных чисел.
Понятно, что это число должно быть точным квадратом, оно может быть: 4, 9, 16, 25,
36 и т.д.
58 
Допустим, что пользователь ввел число 4.
Надо найти все натуральные числа от 1 до 21, квадрат суммы цифр которых равна 4.
Начинаем из чисел: 1, 2, 3, 4, 5, ..., 21, выбирать те, которые удовлетворяют заданному
условию.
Первое из них - 2, так как 22 = 4, второе - 11, так как (1 + 1)2 = 22 = 4, третье - 20, так
как (2 + 0)2 = 22 = 4.
Других натуральных чисел до 21, удовлетворяющих такому условию нет.
Все отобранные числа надо вывести на экран, т. е. 2, 11 и 20.
Алгоритм
1. Раздел описаний.
Переменные: n, m, k, a, p, s. Тип целый.
n - для границы значений натуральных чисел, m - для числа, с которым сравнивается
квадрат суммы цифр (точный квадрат), k - для натуральных чисел от 1 до n, a - для запоминания натурального числа, перед тем, как будет определяться сумма его цифр, p - для
цифр числа, s - для суммы цифр.
2. Раздел операторов.
Ввод значений n и m. Установить первоначальное значение для k (эта переменная
"перебирает" все натуральные числа от 1 до n, k := 1).
Цикл, пока k <= n.
В цикле: установить первоначальные значения для суммы s (s:=0); запомнить число
в переменную a (a := k).
Цикл для подсчета суммы цифр, пока k <> 0.
В цикле: выделять по одной цифре числа, известным способом; прибавлять по одной
цифре к сумме; уменьшать число на последнюю цифру и на порядок.
Закончить цикл для подсчета суммы цифр.
Проверка выполнения условия.
Если квадрат суммы цифр равен заданному числу,
тогда вывести это натуральное число на экран.
Перейти к проверке следующего числа.
Закончить основной цикл проверки чисел.
3. Закончить программу.
По этому алгоритму составим программу.
Program Problem5;
uses WinCrt;
var
n, m, k, a, p, s : integer;
begin
write('Введите натуральное число, до которого ');
write('выводить искомые числа '); readln(n);
writeln('Введите число, с которым сравниваете квадрат');
write('его суммы цифр. Оно должно быть точн. квадрат. '); readln(m);
write('Искомые числа: ');
k := 1;
while k <= n do
begin
s := 0; a := k;
while k <> 0 do
begin
59

p := k mod 10;
s := s + p;
k := k div 10
end;
if sqr(s) = m then write(a, ' ');
k := a + 1
end
end.
В программе два цикла. Один - внешний, для натуральных чисел, второй - внутренний, для подсчета суммы цифр числа.
Задание 4
Составить программу нахождения всех натуральных чисел n  100000, сумма цифр
которых равна заданному натуральному числу.
Упражнения
10. Найти все трехзначные числа, при делении каждого из которых на 11 получается
частное, равное сумме квадратов значений отдельных цифр данного числа.
11. Трехзначное десятичное число оканчивается цифрой 3. Если эту цифру переместить через два знака влево, т. е. с этой цифры будет начинаться запись нового числа, то
это новое число будет на единицу больше утроенного исходного числа. Найдите это число.
12. Найдите все трехзначные числа, которые равны сумме кубов своих цифр.
13. Шестизначное десятичное число начинается слева цифрой 1. Если эту цифру перенести с первого места слева на последнее место справа, то значение образованного числа будет втрое больше исходного. Найдите исходное число.
14. Дано целое число n 10. Написать программу получения m последних цифр десятичной записи числа n.
15. Найти четырехзначное число, равное квадрату числа, выраженного двумя последними цифрами этого четырехзначного числа.
16. Натуральное число называется совершенным, если оно равно сумме всех своих
делителей, за исключением самого себя.
Число 6 является совершенным, так как 6 = 1 + 2 + 3, число 8 не является совершенным, так как 8 не равно 1 + 2 + 4. Написать программу вывода всех совершенных чисел,
меньших заданного числа n.
17. Найти четырехзначные числа, каждое из которых делится на 11 и сумма цифр
каждого равна 11.
18. Найти четырехзначные числа, которые, будучи приписаны справа к числу 400,
дают полный квадрат.
60 
Ответы
К заданию 2
Задача 2
1-й способ
Program Task2_2;
uses WinCrt;
var
n, p, n1 : longint;
begin
write('Введите натуральное число n '); readln(n);
n1 := 0;
while n > 0 do
begin
p := n mod 10;
n1 := n1*10 + p;
n := n div 10
end;
writeln('Число, после перестановки цифр ', n1 + n)
end.
2-й способ
Program Task2_2a;
uses WinCrt;
var
n, p, n1 : longint;
begin
write('Введите натуральное число '); readln(n);
n1 := 0;
while n > 0 do
begin
n1 := n1*10 + n mod 10;
n := n div 10
end;
writeln('Число, после перестановки цифр равно ', n1)
end.
К заданию 3
Задача 2
Program Task3_2;
uses WinCrt;
var
n, a, p, b, s : integer;
begin
write('Введите натуральное число меньшее 28 '); readln(a);
b := 100;
writeln('Трехзначные числа, сумма цифр которых');
write('равна числу ', a, ' следующие: ');
while b < 1000 do
begin
s := 0; n := b;
while n <> 0 do
begin
p := n mod 10;
61

s := s + p;
n := n div 10
end;
if s = a then write(b, ', ');
b := b + 1
end; writeln
end.
Задача 3
Program Task3_3;
uses WinCrt;
var
n, d, e : integer;
begin
n := 10;
write('Искомое двузначное число ');
while n <= 99 do
begin
d := n div 10; e := n mod 10;
if n + d*d*d + e*e*e = e*10 + d then writeln(n);
n := n + 1
end
end.
К заданию 4
Program Task4;
uses WinCrt;
var
n, a, p, b, s : integer;
begin
write('Введите натуральное число '); readln(a);
b := 1;
writeln('Натуральные числа, сумма цифр ');
write('которых равна числу ', a, ' следующие: ');
while b < 32767 do
begin
s := 0; n := b;
while n <> 0 do
begin
p := n mod 10; s := s + p; n := n div 10
end;
if s = a then write(b, ', ');
b := b + 1
end; writeln
end.
62 
Глава 5. Цикл с последующим условием. Оператор
repeat...until...
1. Оператор цикла с последующим условием (постусловием) похож на оператор
цикла с предусловием, но условие вычисляется и проверяется после выполнения операторов, составляющих тело цикла.
Общий вид оператора цикла с постусловием такой:
repeat
s1; s2; s3; ..
until <условие>,
где s1, s2, s3, ... - операторы тела цикла; <условие> - логическое выражение.
Переводится: repeat - повторять, until - до тех пор пока.
Как видите, такой цикл начинается с выполнения операторов внутри цикла, а уже затем вычисляется выражение, записанное в условии.
Если значение этого выражения истинно, тогда осуществляется выход из цикла, если
значение ложно, то цикл продолжается и снова выполняются операторы
s1, s2, s3, ... .
Надо сразу заметить, что в отличии от цикла while ... do, в цикле repeat ... until ...
операторные скобки begin ... end могут не использоваться, хотя и использование их вреда
не принесет. Можно сказать другими словами, что оператор цикла repeat ... until. ... не
требует операторных скобок begin ... end.
Рассмотрим работу этого оператора на примере.
Пример 1. Найти наименьшее натуральное число, дающее при делении на 2, 3, 4, 5, 6
соответственно остатки 1, 2, 3, 4, 5.
Задачу будем решать так: берется наименьшее натуральное число - единица и находятся остатки от деления его на 2, 3, 4, 5 и 6; если остатки будут равны 1, 2, 3, 4 и 5, тогда
это число является искомым, его надо выдать на экран и закончить программу, в противном случае, надо брать следующее натуральное число - 2 и проверять его, и так далее.
Программа, составленная по этой идее, очень проста:
Program Problem1;
uses WinCrt;
var
n : integer;
begin
n := 0;
repeat
n := n + 1;
until (n mod 2 = 1) and (n mod 3 = 2) and (n mod 4 = 3) and
(n mod 5 = 4) and (n mod 6 = 5);
writeln('Искомое целое число ', n)
end.
Еще один пример, который демонстрирует работу цикла с постусловием.

63
Пример 2. Числа, одинаково читающиеся и слева направо, и справа налево, называются палиндромами. Например, числа 42324 или 1331 - палиндромы. Составьте программу, которая будет находить числа - палиндромы из заданного промежутка.
Логика составления программы такова.
Переставить цифры в числе и сравнить полученное число с заданным.
Раньше уже составлялась программа перестановки цифр числа, которая была выполнена с помощью цикла с предусловием
while ... do ...
Как будет построена часть программы о перестановки цифр с помощью цикла
repeat ... until ...
Пусть заданное число a, тогда введем еще одну переменную b, которой будет присвоено значение переменной a (для чего это делается вы узнаете позже): b := a;
Заведем еще одну переменную a1 для нового числа, в котором цифры уже будут переставлены.
Первоначальное значение этой переменной - ноль: a1 := 0;
Почему значение этой переменной равно нулю станет ясно из программы.
Далее организуем цикл repeat, в котором будет происходить перестановка цифр
числа b:
repeat
a1 := a1*10 + b mod 10;
b := b div 10
until b = 0;
Итак, в цикле, также как и в цикле while ... do ..., отделяется последняя цифра:
b mod 10; (например, 343 mod 10 = 3); переменной a1 присваивается значение:
a1 := a1*10 + b mod 10; 0 * 10 + 3 =3;
"отбрасывается" последняя цифра заданного числа с помощью операции целочисленного деления:
b := b div 10; 343 div 10 = 34;
проверяется условие: b = 0, 34 = 0, условие не выполняется, значит цикл продолжается.
Отделяется последняя цифра уже нового числа:
b mod 10 = 34 mod 10;
новое число a1, уже равное 3, умножается на 10 и к результату прибавляется следующая цифра - 4:
a1 := a1*10 + b mod 10;
"отбрасывается" последняя цифра числа b:
b := b div 10 ; 34 div 10 = 3;
проверяется условие: b = 0, 3 = 0; условие не выполняется, значит цикл продолжается.
Отделяется последняя цифра числа:
b mod 10 ; 3 mod 10 = 3;
формируется новое число:
a1 := a1*10 + b mod 10 ; 34 * 10 + 3 = 343;
"отбрасывается" последняя цифра числа и получается новое число:
b := b div 10 ; 3 div 10 = 0;
проверяется условие: b = 0, 0 = 0; условие выполняется, значит цикл заканчивается.
Теперь становится ясно, почему введена другая переменная b для заданного числа,
ее значение в цикле меняется от начального до нуля и, чтобы сохранить заданное число в
переменной a, и вводится, так сказать, "рабочая" переменная - b.
64 
После окончания цикла перестановки цифр числа, сравнивается первоначальное
число, которое "сохранилось" в переменной a и число, которое получилось после перестановки цифр и "накопилось" в переменной a1.
Если a = a1, тогда значение a выдается на экран, так как это число является палиндромом.
Далее, значение a увеличивается на 1, т. е. берется для рассмотрения следующее по
порядку натуральное число и снова продолжается внешний цикл. Цифры числа переставляются, полученное новое число после перестановки цифр - a1, сравнивается с первоначальным a и так далее.
Внешний цикл заканчивается, когда значение a становится равным правой границе
интервала - n.
Составим программу
Program Problem2;
uses WinCrt;
var
m, n, a, b, a1 : longint;
begin
write('Введите левую границу промежутка '); readln(m);
write('Введите правую границу промежутка '); readln(n);
a := m;
writeln('Числа палиндромы из [', m, ';', n, ']');
repeat
b := a; a1 := 0;
repeat
a1 := a1*10 + b mod 10;
b := b div 10
until b=0;
if a1 = a then write(a, ' ');
a := a + 1
until a > n;
end.
Программы, составленные с циклом с предусловием (while ... do...), легко можно переделать с циклом с постусловием (repeat ... until ...) и они будут такими:
Программа, подсчитывающая сумму цифр числа:
Program Sum; { Сумма цифр числа }
uses WinCrt;
var
n, s, a : integer;
begin
write('Введите целое число '); readln(n);
a := n; s := 0;
repeat
s := s + n mod 10; n := n div 10
until n = 0;
writeln('Сумма цифр числа ', a, ' равна ', s)
end.
65

Программа перестановки первой и последней цифр в числе:
Program Transpose;
uses WinCrt;
var
n, n1, p, a, i : longint;
begin
write('Введите натуральное число n '); readln(n);
a := n; i := 1;
p := n mod 10; {последняя цифра введенного числа}
repeat
i := i*10; n := n div 10
until n<10;
n1 := a - n*i - p + n + p*i;
writeln('Число после перестановки цифр ', n1)
end.
Схематически цикл repeat можно изобразить так (см. рис. 21):
s1; s2; ..., sn
нет
Условие
да
Рис. 21
2. Различия между циклом - while и циклом - repeat
1. Оператор, находящийся в цикле while, повторяется до тех пор, пока условие удовлетворено (т.е. истинно). Последовательность операторов, находящихся в цикле repeat,
повторяется до тех пор, пока условие не удовлетворено (т. е. ложно).
Следовательно, в цикле while используется условие продолжения цикла, а в цикле
repeat - условие окончания цикла.
2. В цикле while повторяется один оператор (несколько операторов надо объединять
в составной оператор с помощью операторных скобок begin ... end), а в цикле repeat
можно повторять несколько операторов без операторных скобок.
3. В цикле while сначала проверяется условие, а после этого в зависимости от значения условия выполняется или не выполняется оператор или группа операторов после
слова do.
В цикле repeat последовательность операторов выполняется один раз, а после этого
проверяется условие, т. е. эта последовательность всегда выполняется хотя бы один раз, а
в цикле while операторы, составляющие тело цикла могут вообще не выполняться ни одного раза.
66 
Задание 1
Найти наименьшее натуральное число, кратное 131 с четным количеством цифр. Составить программу.
3. Программы с совместным использованием циклов repeat и
while ... do ...
Пример 3. Если мы сложим все цифры какого-либо числа, затем - все цифры
найденной суммы и будем повторять это много раз, мы наконец получим однозначное
число (цифру), называемое цифровым корнем данного числа. Например, цифровой корень
числа 561 равен 3 (5 + 6 + 1 = 12; 1 + 2 = 3).
Составьте программу для нахождения числового корня числа.
Соображения по составлению программы
Ясно, что в программе должен быть цикл, который определяет сумму цифр числа. В
свою очередь, этот цикл должен также выполняться до тех пор, пока значение суммы
цифр не станет равным одной цифре, т.е. станет меньше 10, но остается больше 0. Для
этого надо организовать еще один цикл, который будет являться внешним по отношению к
циклу, подсчитывающему сумму цифр.
Одна тонкая особенность! Каждый раз после выполнения внутреннего цикла подсчета суммы цифр, значение этой суммы надо присваивать переменной, в которой содержится первоначальное число, т. е. заменять число на его сумму, проверять условие (не является ли сумма меньше десяти) и продолжать цикл уже с новым числом - суммой, если
условие не выполняется. А ту переменную, в которой накапливалась сумма надо каждый
раз не забывать обнулять.
Итак, если введенное число было присвоено переменной n, а сумма его цифр переменной s, то после подсчета суммы цифр, переменная должна получить значение s (n:= s),
проверить условие (n < 10), если оно еще не выполняется, тогда обнулить переменную s
(s:= 0) и продолжить цикл подсчета суммы цифр.
Внешний цикл по проверке значения суммы организуем с помощью операторов
repeat ... until n < 10, а внутренний по подсчету суммы цифр с помощью операторов while
... do.
Программа
Program Problem3; { Цифровой корень числа }
uses WinCrt;
var
n, a, s : integer;
begin
write('Введите натуральное число '); readln(n);
a := n;
repeat
s := 0;
while n <> 0 do
begin
s := s + n mod 10; n := n div 10
end;
n := s
until n < 10;
67

writeln('Цифровой корень числа ', a, ' равен ', n)
end.
Задание 2
1. Выполните эту программу. Измените ее так, чтобы она находила цифровые корни
каждого из чисел от 10 до 100.
2. Найти трехзначное число, являющееся точным квадратом натурального числа k, и
такое, что произведение его цифр равно k - 1.
4. Разные задачи
Пример 1. Составить программу определения всех делителей числа n.
Когда ставится такая задача, то очень часто учащиеся предлагают такой способ решения.
Надо испробовать все натуральные числа, начиная от 1 до n и, если какое-то из них
будет являться делителем числа n, тогда выдавать его на экран. Например, для числа 36,
берем для проверки числа 1, 2, 3, ..., 36 и выбираем из них делители 36. Делители будут
следующими: 1, 2, 3, 4, 6, 9, 12, 18 и 36.
Такой способ возможен. Но, если вы внимательно посмотрите на делители числа 36,
то обнаружите, что все они находятся в интервале от 1 до 18, т.е. до половины числа 36 и
лишь последний делитель - это само число.
Да и простая логика рассуждений убеждает нас, что делители будут располагаться
n
именно в этом интервале: от 1 до .
2
Если допустить мысль, что есть делитель больше половины числа, тогда умножив
его только лишь на 2, мы получим число большее заданного.
Итак, становится ясным, что все делители числа, кроме самого, находятся в промеn
жутке от 1 до , а значит надо проверять числа на возможные делители именно из этого
2
промежутка.
n
Отсюда возникает такой план составления программы: организовать цикл от 1 до ;
2
если число n делится на число из этого промежутка, тогда вывести этот делитель на
экран; продолжить цикл; выдать на экран само число.
Программа
Program Problem1; { Простой алгоритм. 1 - способ }
uses WinCrt;
var
n, d : integer;
begin
write('Введите целое число '); readln(n);
d := 1;
writeln('Делители числа ', n);
repeat
if n mod d = 0 then write(d, ' ');
d := d + 1
68 
until d > n div 2;
write(n)
end.
Но и при решении этой задачи машине можно помочь и облегчить ее работу. Здесь
на помощь снова приходит математика.
Оказывается, для того чтобы найти делители числа n, достаточно обнаружить делители не превышающие n .
Все остальные делители получаются в результате деления числа n на найденные делители.
Например, если n = 30, то достаточно найти делители 1, 2, 3, 5 (натуральный квадратный корень из 30 равен 5), а все прочие делители получаются делением на найденные:
30 div 1 = 30;
30 div 2 = 15;
30 div 3 = 10;
30 div 5 = 6.
При составлении программы возникает проблема - нет встроенной функции извлечения квадратного корня в множестве целых чисел. Это препятствие легко обойти, если
организовать цикл для выбора делителей d от 1 до тех пор пока d*d<n (что является тем
же, что и d < n), а если корень квадратный извлекается нацело, тогда этот случай надо
рассмотреть отдельно после завершения основного цикла.
Почему надо сделать именно так. Это становится понятным на примере для числа
36. 36 = 6, цикл - пока d  d < 6;
d = 1, d  d = 1  1 = 1 < 36 (истина),
цикл продолжается;
находится остаток от деления 36 mod 1 = 0; выдается 1 и частное от деления 36 на 1,
36 div 1 =36;
d = 2, d  d = 2  2 = 4 < 36 (истина),
цикл продолжается;
36 mod 2 = 0;
выдается 2 и частное от деления 36 на 2, 36 div 2 = 18;
d = 3, d  d = 3  3 = 9 < 36 (истина),
цикл продолжается;
36 mod 3 = 0;
выдается 3 и частное от деления 36 на 3, 36 div 3 = 12;
d = 4, d  d = 4  4 = 16 < 36 (истина),
цикл продолжается;
36 mod 4 =0;
выдается 4 и 36 div 4 = 9;
d = 5, d  d = 5  5 = 25 < 36 (истина),
цикл продолжается;
36 mod 5 <>0, ничего не выдается на экран,
цикл продолжается;
d = 6, d  d = 6  6 = 36 < 36 (ложь), цикл заканчивается.
Проверяется d = 6 (d  d = n), 6  6 = 36 (истина), выдается 6.
Если бы цикл продолжался, пока d  d <= n, тогда при d = 6 на экран выдавалось бы
- 6 и 36 div 6 = 6, т. е. две шестерки, что было бы ошибкой.
69

Программа
Program Problem1a; { Делители числа. 2 - способ }
uses WinCrt;
var
n, d : integer;
begin
write('Введите целое число '); readln(n);
writeln('Делители числа ', n);
d := 1;
while d*d < n do
begin
if n mod d=0 then write(d, ' ', n div d, ' ');
d := d + 1
end;
if d*d = n then write(d); writeln
end.
Задание 3
Составьте программу, которая будет находить число делителей и их сумму для данного натурального числа.
Пример 2. Найти наибольший общий делитель (НОД) двух чисел a и b.
Вопрос определения наибольшего общего делителя двух чисел настолько детально и
тщательно изложен во всех учебных пособиях, что сообщить что-нибудь новое в составлении алгоритмов нахождения НОД очень трудно.
Однако, я заметил, что в большинстве пособий излагается определение НОД с помощью алгоритма Евклида, причем не самым лучшим способом.
Мы изберем другой подход к этому вопросу, как мне кажется, более естественный.
Итак, допустим, что мы не знаем алгоритма Евклида и пробуем исходя из элементарных знаний математики и простой логики рассуждений найти наибольший общий делитель чисел, а затем и составить программу.
Прежде четко определим для себя, что такое НОД двух чисел. Так, для чисел 36 и 45
существуют три общих делителя: 1, 3, 9. Наибольший среди них 9. Он и является НОД чисел 36 и 45.
Для 30 и 45 немного больше общих делителей: 1, 3, 5 и 15. Наибольшим является 15,
значит НОД(30, 45) = 15.
Наибольшим общим делителем чисел a и b называется наибольшее число среди всех
общих делителей чисел a и b.
Тогда, по логике вещей, возникает естественная идея найти НОД следующим образом.
Во-первых, надо проверить не делится ли одно из чисел на другое, если делится, тогда то на которое разделилось и является наибольшим общим делителем. Например, для
чисел 45 и 15 НОД будет число 15. Если ни одно из них не делится на другое, тогда будем брать поочередно все натуральные числа от 1 до меньшего из чисел a или b и проверять на какие из них делятся оба числа, последний из этих общих делителей и будет
наибольшим.
Такой процесс для чисел 36 и 45 будет выглядеть так:
70 
проверяем деление a на b и b на a;
находим остаток от деления на 1, 36 mod 1= 0, 45 mod 1 = 0, значит 1 - общий делитель;
на 2, 36 mod 2 = 0, 45 mod 2 <>0, 2 не является общим делителем;
на 3, 36 mod 3 = 0, 45 mod 3 = 0, 3 - общий делитель;
на 4, .................................................. и так далее до 36.
Последний из этих общих делителей будет 9, он и является НОД.
Нетрудно составить и программу по такому простому алгоритму.
Program Problem2;
uses WinCrt;
var
a, b, n, k, i : integer;
begin
write('Введите первое число '); readln(a);
write('Введите второе число '); readln(b);
if a mod b = 0
then n := b
else
if b mod a = 0
then n := a
else
begin
if a > b then i := b else i := a;
k := 1;
while k < i do
begin
if (a mod k = 0) and (b mod k = 0) then n := k;
k := k + 1
end
end;
writeln('НОД числе ', a,' и ', b, ' равен ', n)
end.
Но подумайте, сколько бесполезной работы проделывает компьютер, работая по
этой программе!
Так, для чисел 36 и 45 всего цикл будет выполняться 36 раз. Из них "чисто" бесполезных или "пустых" будет 27, так как наибольший общий делитель равен 9 и от 9 до 36 бесполезная работа.
Естественно возникает вопрос, а нельзя ли выбрать другой путь для определения
НОД? А что, если попробовать "с другого конца", т.е. выбрать меньшее число и уменьшать его на единицу, каждый раз проверяя, не является ли полученное число делителем.
Как только такой делитель найден, цикл прекращается, а этот делитель и будет
наибольшим, таким образом, число бесполезных циклов уменьшится.
Например, для тех же чисел 36 и 45 цикл уже будет выполняться не 36 раз, а 27: 36,
35, 34, 33, 32, 31, ..., 9.
71

Алгоритм
Выбираем меньшее из введенных чисел; начинается цикл, который выполняется с
уменьшением меньшего из чисел на единицу и последующей проверкой условия, является
ли оно общим делителем чисел; как только делитель найден, цикл заканчивается; на экран
выводится найденный делитель, который является НОД.
По алгоритму составим программу:
Program Problem2a;
uses WinCrt;
var
a, b, n, k : integer;
begin
write('Введите первое число '); readln(a);
write('Введите второе число '); readln(b);
if a > b then k := b else k := a;
n := k + 1;
repeat
n := n - 1
until (a mod n = 0) and (b mod n = 0) ;
writeln('НОД чисел ', a, ' и ', b, ' равен ', n)
end.
При такой конструкции программы уже не надо проверять деление одного числа на
другое (подумайте почему?).
Конечно, эти программы можно усовершенствовать, сделать менее трудоемкими для
компьютера (попробуйте это сделать сами), и все-таки нам придется обратиться к алгоритмам Евклида, которые до сих пор являются совершенством в математике.
Они отличаются не только математической оригинальностью, но и простотой. Все
гениальное просто!
Итак, первый из алгоритмов Евклида нахождения НОД состоит в следующем.
Например, надо найти НОД чисел 36 и 45.
Вычитаем из большего числа меньшее: 45 - 36 = 9,
заменяем большее из данных чисел на разность, получаем два других числа:
9 и 36;
снова, из большего вычитаем меньшее: 36 - 9 = 27,
заменяем большее на разность, получаем 9 и 27; из большего вычитаем меньшее:
27 - 9 = 18,
заменяем большее на разность, получаем 9 и 18; из большего вычитаем меньшее:
18 - 9 = 9,
заменяем большее на разность, получаем 9 и 9.
Получены два равных числа, значит НОД чисел 45 и 36 равно 9.
Итак, сущность алгоритма заключается в том, чтобы из большего числа вычитать
меньшее, а потом заменять большее на разность и так продолжать до тех пор, пока числа
неравны, как только они станут равными, процесс прекращается и выдается НОД.
Этот алгоритм Евклида имеет строгое математическое обоснование и не может вызывать никаких сомнений.
72 
Программа
Program Problem2b;
uses WinCrt;
var
a, b, c, a1, b1 : integer;
begin
write('Введите первое число '); readln(a);
write('Введите второе число '); readln(b);
a1 := a; b1 := b;
while a <> b do
begin
if a > b then a := a - b else b := b - a
end;
writeln('НОД чисел ', a1, ' и ', b1, ' равен ', a)
end.
В этой программе использован цикл "пока", а не цикл "до". Как вы думаете почему?
Для ответа на этот вопрос, замените цикл " пока" на цикл " до ...", т. е. операторы while ...
do на repeat ... until ... Цикл станет таким:
repeat
if a > b then a := a - b else b := b - a
until a = b;
Как вам уже известно, цикл repeat обязательно выполняется хотя бы один раз. Если
вы введете два равных числа, то программа "зациклится". В самом деле, условие a > b не
выполняется, значит будет выполнен оператор b := b - a. b получит значение 0, цикл повторится, условие a > b выполняется, тогда a получит значение: a := a - 0, т.е. значение a не
изменится, равенство a=b никогда не выполнится и цикл будет продолжаться "бесконечно", как говорят, "программа зациклится".
Если же применяется цикл while a <> b do ..., то даже при вводе равных чисел a и b
(a = b), цикл не выполнится ни одного раза и НОД получит значение одного из равных чисел - a.
Существует и второй алгоритм Евклида для нахождения НОД..
Пусть a и b - натуральные числа, b <> 0 и r - остаток от деления a на b. Тогда НОД(a,
b) = НОД(r, b).
Для доказательства используется очевидное свойство наибольшего общего делителя:
натуральное число d тогда и только тогда является наибольшим общим делителем a и b,
когда это число:
1) делит a и b, т.е. является общим делителем a и b;
2) делится на любой общий делитель a и b.
Пусть a  b  0 и a > 0. Тогда применение алгоритма Евклида происходит так: если
b = 0, то НОД(a, b) = a. Иначе вычисляем r, равное остатку от деления a на b, и сводим задачу отыскания НОД(a, b) к задаче отыскания НОД(r, b). При r>0 этот процесс можно
продолжить. Имеем: b > r > r1 > r2 > r3 >, ..., но так как b, r, r1, r2, r3 - неотрицательные целые
числа, то найдется n такое, что rn = 0. В соответствии с высказанным утверждением
НОД(a, b) = НОД(b, r) = НОД(r1, r) = ... = НОД(rn-1, 0) = rn-1.
Практически это выглядит так. Надо найти НОД чисел 888 и 351.
Большим из них является 888, a = 888, b = 351.
Находим остаток от деления a на b: 888 mod 351 = 186, r = 186;
заменим a на b и b на остаток r, получим: a = 351, b = 186;
снова находим остаток от деления a на b: 351 mod 186 = 165, r = 165;
73

заменим a на b и b на остаток r, получим: a = 186, b = 165;
находим остаток от деления a на b: 186 mod 165 = 21, r = 21;
заменим a на b и b на остаток r, получим: a = 165, b = 21;
находим остаток от деления a на b; 165 mod 21 = 18, r = 18;
заменим a на b и b на остаток r, получим: a = 21, b = 18;
находим остаток от деления a на b; 21 mod 18 = 3, r = 3;
заменим a на b и b на остаток r, получим: a = 18, b = 3;
находим остаток от деления a на b: 18 mod 3 = 0, r = 0;
заменим a на b и b на остаток r, получим: a = 3, b = 0.
Как только b стало равным нулю, цикл заканчивается, выдается значение a, которое
и является наибольшим общим делителем, НОД(888, 351) = a = 3.
Этот процесс можно записать в виде следующей цепочки, которая в общем виде была записана выше:
НОД(888, 351) = НОД(351, 186) = НОД(186, 165) =
= НОД(165, 21) = НОД(21, 18) = НОД(18, 3) = НОД(3, 0) = 3.
Замечание. Совсем не обязательно выбирать большее из двух чисел. Если число a
окажется меньшим, тогда при первом шаге цикла произойдет перестановка чисел a и b.
Например, a = 351, b = 888. Находится остаток от деления a на b:
351 mod 888  351, r = 351; заменим a на b и b на остаток r, получим: a  888, b  351,
все стало на свои места и процесс пойдет прежним порядком.
Понятно даже без глубокого анализа, что этот алгоритм значительно быстрее приводит нас к результату и выполняется без ненужных операций, т. е. не вынуждает компьютер работать впустую.
Программа
Program Problem2c; { 2 - способ. Алгоритм Евклида }
uses WinCrt;
var
a, b, r, a1, b1 : integer;
begin
write('Введите первое число '); readln(a);
write('Введите второе, не равное нулю, число ');
readln(b);
a1 := a; b1 := b;
repeat
r := a mod b;
a := b; b := r
until b = 0;
writeln('НОД чисел ', a1, ' и ', b1, ' равен ', a)
end.
Задание 4
Составьте программу определения наименьшего общего кратного (НОК) двух чисел
по меньшей мере двумя способами.
74 
Напоминание
Наименьшим общим кратным двух чисел a и b, НОК(a, b) называется наименьшее
число, которое делится и на a и на b.
Например, для чисел 18 и 27 наименьшим общим кратным является число 54. Оно
делится без остатка и на 18 и на 27. Хотя общих кратных для этих чисел существует бесконечно много: 54, 108, 162, 216, ..., однако, 54 является меньшим среди них.
Подсказка
1. Идея составления первой программы или, иначе говоря, идея первого алгоритма
состоит в следующем.
Выбираем большее из чисел, если оно делится на меньшее, тогда оно и будет являться наименьшим общим кратным, иначе, большее число увеличивается вдвое, т.е. к нему
прибавляется само это число и снова происходит проверка, делится ли новое число на
меньшее, если делится, тогда оно является НОК, если не делится, тогда снова увеличивается на такое же число, т.е. первоначальное большее из двух уже увеличивается втрое и
так далее.
Например, для чисел 10 и 36 этот процесс будет выглядеть так: 36 большее из чисел,
36 mod 10 <>0, т.е. 36 не делится на 10; увеличим 36 на 36, получим: 36  36  72; проверяем: 72 mod 10 <> 0; увеличим 72 еще на 36, получим: 72  36  108; проверяем: 108 mod
10 <> 0; увеличиваем на 36, получим: 108  36  144; проверяем: 144 mod 10 <> 0; увеличиваем: 144  36  180; проверяем: 180 mod 10=0, 180 делится на 10, значит 180 и является
наименьшим общим кратным чисел 10 и 36, НОК(10, 36) = 180.
2. Идея второго алгоритма основывается на следующем математическом утверждении: a  b = НОК(a, b)  НОД(a, b).
Пример 3. Составить программу, которая определяет является ли данное число n
простым.
Простым называется натуральное число, которое имеет только два делителя - 1 и
само себя. Надо заметить, что число 1 не подходит под это определение, так как имеет
только один делитель - само себя, а значит не является простым числом.
Натуральные числа, отличные от 1 и не являющиеся простыми называются составными.
Таким образом, число 1 не относится ни к простым ни к составным.
Но это лишь между прочим для того, чтобы вспомнить арифметику и расширить
наш математический кругозор.
Зная все это, возникает такой план составления программы. Найти количество делителей числа, исключая 1 и само число. Если таких делителей будет нуль, т.е. вообще не
будет, тогда число является простым, иначе, оно является составным.
Для подсчета числа делителей в программе надо завести счетчик, а по окончанию
цикла, выяснять его значение.
Ниже приводится программа, составленная по этому плану.
Program Problem3;
uses WinCrt;
var
n, i, k : integer;
begin
write('Введите натуральное число большее 2 ');
75

readln(n);
i := 2; k := 0;
repeat
if n mod i=0 then k := k + 1;
i := i + 1
until i>n div 2;
if k = 0 then writeln('Число ', n, ' является простым')
else writeln('Число ', n, ' составное')
end.
Ее можно усовершенствовать. В самом деле, зачем продолжать цикл, если найден
хотя бы один делитель? Цикл надо прервать и выдать сообщение, что число составное, а
n
затем закончить программу, иначе, продолжать цикл до конца, т. е. до
и после цикла
2
выдать сообщение - число простое.
Программа с досрочным прерыванием цикла получится такой:
Program Problem3a;
uses WinCrt;
var
n, i, k : integer;
label 1, 2, 3;
begin
write('Введите натуральное число, большее 1 '); readln(n);
if n = 2 then goto 1;
i := 2; k := 0;
repeat
if n mod i = 0 then goto 2;
i := i + 1
until i > n div 2;
1: writeln('Число ',n, ' - простое'); goto 3;
2: writeln('Число ',n, ' - составное');
3: end.
В обоих из приведенных вариантов компьютер проделывает много ненужной работы.
Существуют и другие способы определения, является ли число простым или составным.
Вот один из них, который вытекает из естественных соображений.
Во-первых, если число является четным, то ясно, что оно будет составным, но перед
этим надо исключить из рассмотрения число 2 (оно является простым числом), т.е. проверить, если данное число равно 2, то оно является простым.
Во-вторых, надо проверять деление только на нечетные числа до n/2. И в этом случае можно использовать досрочное прерывание цикла, если делитель найден.
Программа достаточно проста и вам надо составить ее
самостоятельно.
76 
Задание 5
Пользуясь выше приведенными соображениями составить программу, которая определяет является ли данное число простым вторым способом.
Пример 4. Составить программу нахождения всех простых чисел из заданного промежутка [n, m].
Алгоритм
Первые соображения такие: проверять каждое из чисел заданного промежутка [n, m],
начиная с m и проверять является ли оно простым числом, если является, тогда выводить
его на экран.
Затем увеличить проверенное число на единицу и снова проверить и так далее до
конца промежутка.
Для того, чтобы проверить каждое из чисел можно организовать цикл
repeat ... until ...
Первоначальное значение переменной цикла установить равной значению левого
конца промежутка (p := n), а в качестве условия окончания цикла, равенство значения p
правой границе промежутка - m (until p = m).
Тогда внешний цикл будет таким:
p := n;
repeat
....
p := p + 1
until p = m;
"Внутри" этого цикла записываются уже известные вам операторы проверки числа,
является ли оно простым. Если является, тогда выдавать его на экран.
Этот процесс проверки выполним с помощью операторов, которые вы должны были
составить при выполнении предыдущего задания:
if p = 2 then write(p:4 , ' ')
else if p = 3
then write(p:4, ' ')
else if p mod 2 <> 0
then
begin
i := 3; k := 0;
repeat
if p mod i = 0 then k := k + 1;
i := i + 2
until i > p div 2;
if k = 0 then write(p:4, ' ')
end;
Если число p равно 2 или p равно 3, тогда оно является простым и его надо выдать
на экран: if p = 2 then write(p:4, ' ')
иначе, надо проверять только нечетные числа, ибо ясно, что любое четное число составное:
else if p mod 2 <> 0,
также надо выдавать на экран число 3: else if p = 3
then write(p:4, ' ')
77

далее, надо проверять деление числа p на нечетные числа, а значит в качестве первоначального значения делителя i берется 3, а в цикле оно увеличивается на 2. Счетчик k,
как и в предыдущей программе подсчитывает число делителей. После завершения цикла
подсчета числа делителей, его значение проверяется, если оно равно нулю, значит ни одного делителя у числа нет - оно является простым и выдается на экран.
Полностью программа приведена ниже:
Program Problem4; { Простые числа из промежутка [n; m] }
uses WinCrt;
var
n, m, p, i, k : integer;
begin
write('Введите левую границу промежутка '); readln(n);
write('Введите правую границу промежутка '); readln(m);
writeln('Простые числа из промежутка [', n, ' ', m, ']');
p := n; if p = 1 then p := p + 1;
repeat
if p = 2 then write(p:4, ' ')
else if p = 3
then write(p:4, ' ')
else
if p mod 2 <> 0
then
begin
i := 3; k := 0;
repeat
if p mod i = 0 then k := k + 1;
i := i + 2
until i > p div 2;
if k = 0 then write(p:4, ' ')
end;
p := p + 1
until p = m;
writeln
end.
Задание 6
Найти простые числа p из промежутка [1; 1000], такие, что p + 10 и p + 14 тоже являются простыми числами.
Упражнения
19. Найти наименьшее целое число, делящееся на 7, которое при делении на 2, 3, 4,
5, 6 дает в остатке 1.
20. Какие числа, заключенные между числами 2320 и 2350 простые, а какие составные?
21. Составьте программу для нахождения наименьшего нечетного неравного 1 натурального делителя любого заданного натурального числа, большего 1.
78 
22. Найти двузначное число, которое на 6 меньше квадрата суммы своих цифр.
23. Дана сократимая дробь, ее числитель и знаменатель - натуральные числа m и n.
m1 m
Найти такие натуральные числа m1 и n1, не имеющие общих делителей, что
 , т. е.
n1 n,
m
сократить дробь .
n
24. Напишите программу, которая для каждого из целых чисел от 1 до n напечатает
все его делители. Например, для числа 35 - делители: 1, 5, 7, 35. Аналогичный список делителей должен быть выдан для каждого из чисел от 1 до заданного числа n.
25. Найти наименьшее натуральное число n, обладающее следующими свойствами:
а) его запись в десятичной системе счисления оканчивается цифрой 6;
б) если переставить цифру 6 из конца числа в его начало, то полученное число будет в 4 раза больше данного.
26. Написать программу вывода всех натуральных чисел, меньших n, квадрат суммы
цифр которых равен m.
27. Можно ли данное целое p представить в виде суммы двух квадратов целых чисел? Написать программу решения этой задачи.
28. Найти все четырехзначные числа a1a2 a3a4 , удовлетворяющие условию: a1a2 a3a4
2
2
= ( a1 a2 + a 3 a4 ).
29. Найти числа, оканчивающиеся на цифру a (a = 2, 3, 4, 5, 6, 7, 8, 9) и обладающее
тем свойством, что если последнюю цифру переставить в начало числа, то число увеличится во столько раз, сколько единиц в переставляемом числе.
30. Найти целые числа n, делящиеся на все простые числа, не большие n .
31. Составьте программу для проверки, можно ли заданное натуральное число представить в виде:
а) произведения двух простых чисел; б) произведения трех простых чисел;
в) квадрата какого-либо простого числа; г) куба какого-либо простого числа. Следует напечатать ответ ДА или НЕТ.
32. Разрезание прямоугольника на квадраты.
Дан прямоугольник, длины сторон которого a и b представляют собой натуральные
числа. Составить программу, которая будет находить, на сколько квадратов, стороны которых выражены натуральными числами, можно разрезать данный прямоугольник, если
от него каждый раз отрезается квадрат максимально большой площади.
33. Составить программу для нахождения всех прямоугольников указанной площади
(площадь - исходное данное выраженное натуральным числом), стороны которых - натуральные числа. Например, если площадь равна 12, то получим три разных прямоугольника:
1  12
2  6
3  4
Будем считать одинаковыми прямоугольники, получающиеся один из другого, если
поменять ребра местами.
34. Составить программы, которые устанавливают, являются ли два числа взаимно
простыми, три числа взаимно простыми.
35. Найти все натуральные числа n, меньшие заданного числа k, для которых n2  1
делится на n 1.
36.* Найти наименьшее натуральное число n, для которого n4  (n  1) 4 есть составное число. (Задача Серпинского.)
79

Ответы
К заданию 1
Program Task1;
uses WinCrt;
var
n, a, k : integer;
begin
n := 131;
repeat
n := n + 131;
a := n; k := 0;
repeat
k := k + 1;
a := a div 10
until a = 0;
until k mod 2 = 0;
writeln('Наименьшее натуральное число, кратное 131');
writeln('с четным количеством цифр равно ', n)
end.
К заданию 2
Program Task2_2;
uses WinCrt;
var
a, n, p, s : integer;
begin
a := 100;
writeln('Трехзначные числа, при делении которых на 11');
write('частное равно сумме квадратов их цифр следующие ');
repeat
n := a; s := 0;
repeat
p := n mod 10;
s := s + p*p;
n := n div 10
until n = 0;
if (a mod 11 = 0) and (s = a div 11) then write(a, '; ');
a := a + 1
until a = 1000;
end.
К заданию 4
Program Task4; { НОК двух чисел. 1 - способ }
uses WinCrt;
var
a, b, m, n, p : integer;
begin
80 
write('Введите первое число '); readln(a);
write('Введите второе число '); readln(b);
p := 0;
repeat
if a>b then
begin
m := a; n := b
end
else
begin
m := b; n := a
end;
p := p + m
until p mod n =0;
writeln('НОК чисел ', a, ' и ', b, ' равен ', p)
end.
К заданию 5
Program Task5; { Является ли число простым? 2- способ }
uses WinCrt;
label 1, 2;
var
n, i : integer;
begin
write('Введите целое число '); readln(n);
i := 3;
if n = 2 then writeln('Число ', n, ' - простое')
else if n = 3
then writeln('Число ', n, ' - простое')
else
if n mod 2 = 0 then writeln('Число ',n,' составное')
else
repeat
if n mod i = 0 then goto 1;
i := i + 2
until i > n div 2;
writeln('Число ', n, ' простое'); goto 2;
1: writeln('Число ', n, ' составное');
2: end.
81

Глава 6. Циклы с параметрами. Операторы for...to...do... и
for...downto...do...
1. Иногда заранее известно, сколько раз должен выполняться цикл. Для задач такого
типа в языке Паскаль имеются операторы циклов с параметрами.
Формат записи таких операторов следующий:
for <пар.цикла> := <нач.знач> to <кон.знач.> do <оператор>.
Здесь for, to, do - зарезервированные слова (для, до, выполнить);
<пар. цикла> - параметр цикла - переменная типа integer (точнее, любого порядкового типа);
<нач. знач.> - начальное значение - число или выражение того же типа;
<кон. знач.> - конечное значение - число или выражение того же типа;
<оператор> - произвольный оператор Паскаля.
Если операторов несколько, тогда, как и в операторе while ... do ..., используются
операторные скобки: begin ... end.
Например, возможны такие записи оператора цикла:
for i := a to b do s1;
for j := a to b do begin s1; s2; ..., sn end; или
for k := p to m do
begin
s1;
s2;
...
sn
end;
Здесь s1, s2, s3, ... sn - операторы цикла.
При выполнении оператора for вначале вычисляется выражение <нач .знач.> и осуществляется присваивание его значения переменной цикла
<пар .цикла> := <нач. знач.>.
После этого циклически повторяются:
1) проверка условия <пар .цикла>  <кон. знач.>; если условие не выполнено, оператор for завершает работу;
2) выполнение оператора <оператор> или операторов s1; s2; s3; ... sn;
3) переменная цикла <пар. цикла> увеличивается на единицу.
Надо сразу заметить, что задать шаг цикла, отличный от 1 в этом операторе,
нельзя.
Для иллюстрации работы оператора for рассмотрим пример уже ставший традиционным при изучении работы этого оператора.
Пример 1. Составить программу вычисления факториала числа n, т. е. n!.
Вспомним из математики, что факториал числа n равен произведению чисел от 1 до
n.
Например:
82 
1!

1,
2!

1  2,
3!

1  2  3,
4!

1  2  3  4,
... ...
n!

...
1  2  3  4. . . n.
Замечание. В математике принято: 0! = 1.
Программа
Program Problem1; { Вычисление факториала числа n! }
uses WinCrt;
var
n, f, i : longint;
begin
write('Введите натуральное число '); readln(n);
f := 1;
if n <> 0 then for i := 1 to n do f := f*i;
writeln('Факториал числа ', n, ' равен ', f)
end.
Переменная n - для вводимого пользователем числа, факториал которого надо найти;
f - переменная, в которой будет "накапливаться" значение факториала числа n; i - переменная цикла.
Устанавливается первоначальное значение переменной f := 1.
Далее начинается цикл. Переменной i присваивается начальное значение 1; оно
сравнивается с конечным - n (1 <= n), если условие истинно, тогда выполняется оператор
(в этой программе он один): f := f*i, 1*1=1; значение переменной цикла увеличивается на
1, т. е. станет равным: i := i + 1, 1 + 1 = 2 и цикл повторяется.
Когда значение i станет равным n, тогда цикл выполнится последний раз, потому
что следующее значение i будет n + 1, что больше конечного значения n, условие i <= n ложно, цикл не выполняется.
2. Оператор цикла for...downto...do...
Существует другая форма оператора цикла for:
for <пар .цик.> := <нач. зн.> downto <кон. зн.> do <оператор>.
Замена зарезервированного слова to на downto означает, что шаг параметра цикла
равен (-1).
Изменение значения параметра идет от большего значения к меньшему, т. е. <нач.
знач.>  <кон. знач.>.
Программу вычисления факториала числа можно составить, используя этот оператор
цикла.
Программа
Program Problem1a;
uses WinCrt;
var
n, i, f : longint;
83

begin
write('Введите натуральное число '); readln(n);
f := 1;
if n <> 0 then for i := n downto 1 do f := f*i;
writeln('Факториал числа ', n, ' равен ', f)
end.
Графическое изображение циклов for будет таким (см. рис. 22):
i := n, k
s1; s2; ..., sn
Рис. 22
Здесь: p - переменная цикла; n - ее начальное значение; k - ее конечное значение. Тело цикла составляет оператор или несколько операторов: s1; s2; ... sn;, которые нарисованы в прямоугольнике.
Задание 1
1. Выполните программу примера 1 на компьютерах.
2. Измените и дополните ее так, чтобы она вычисляла следующую сумму:
1! + 2! + 3! + ... + n!.
Разберем другие, на мой взгляд, более интересные примеры с использованием циклов for ... to ... do ..., а также вложенных друг в друга циклов (циклов в циклах), совмещение циклов с параметром с другими циклами.
Пример 2. Квадрат любого натурального числа n равен сумме n первых нечетных
чисел:
12 = 1
22 = 1 + 3
32 = 1 + 3 + 5
42 = 1 + 3 + 5 + 7
52 = 1 + 3 + 5 + 7 + 9
...................
Основываясь на этом свойстве, составить программу, позволяющую напечатать
квадраты натуральных чисел от 1 до n.
Ясно, что цикл в программе надо организовать от 1 до n, в котором выполнять всего
три оператора: находить сумму нечетных чисел (а их как раз столько, сколько раз будет
84 
выполняться цикл); выдавать полученную сумму на экран; "получать" следующее нечетное число.
Программа
Program Problem2;
uses WinCrt;
var
i, n, s, k: integer;
begin
writeln('Введите натуральное число, до которого надо');
write('выводить квадраты чисел '); readln(n);
writeln('Квадраты чисел следующие:');
s := 0; k := 1;
for i := 1 to n do
begin
s := s + k;
writeln('Квадрат числа ', i, ' равен ', s);
k := k + 2
end
end.
Задание 2
1. Измените программу так, чтобы она выдавала на экран не таблицу квадратов чисел от 1 до n, а квадрат только одного числа n, введенного пользователем.
2. Измените и дополните программу так, чтобы она выдавала значение квадрата числа и те нечетные числа, сумме которых он равен.
3. Продолжая тему возведения натуральных чисел в степень, без операций
умножения, рассмотрим еще два интересных примера. В первом из них нам придется
совмещать, "вкладывать" друг в друга два цикла for, а во втором, циклы for и repeat.
Пример 3. Куб любого натурального числа n равен сумме n нечетных чисел, следующих по порядку за числами, сумма которых составляла куб предыдущего числа n - 1:
13 = 1
23 = 3 + 5
33 = 7 + 9 + 11
43 = 13 + 15 + 17 + 19
......................
Основываясь на этом свойстве, создайте программу, позволяющую напечатать таблицу кубов натуральных чисел.
Вот здесь уже нужны два цикла. Один - внешний, по количеству нечетных чисел,
которое равно возводимому в куб числу, например, для 43 этот цикл должен выполняться
4 раза. В этом же цикле надо будет после подсчета суммы выводить ее значение на экран
вместе с числом, которое возводится в куб.
Второй - внутренний, который будет суммировать нечетные числа и "вырабатывать" нужные нечетные числа для суммирования.
85

Программа
Program Problem3; { Кубы натуральных чисел от 1 до n }
uses WinCrt;
var
i, j, n, s, k : longint;
begin
writeln('Введите натуральное число, до которого надо');
write('выводить кубы чисел '); readln(n);
writeln('Кубы чисел следующие:');
k := 1;
for i := 1 to n do
begin
s := 0;
for j := 1 to i do
begin
s := s + k; k := k + 2
end;
writeln('Куб числа ', i, ' равен ', s)
end
end.
Разберем работу этой программы
Переменные i и j нужны в качестве переменных первого - внешнего и второго внутреннего циклов. Переменная k для нечетных чисел, а s для суммы чисел. Тип этих переменных установлен целый, но longint, так как могут быть достаточно большие целые
числа, большие 32767.
Программа начинается с запроса для пользователя с помощью операторов writeln и
write о вводе натурального числа, до которого надо выдавать таблицу кубов чисел. Затем с
помощью оператора readln это значение вводится в память компьютера и присваивается
переменной n.
Выводится надпись "Кубы чисел следующие". Она дана перед началом циклов по
понятным причинам. В циклах ее дать нельзя, - она будет повторяться несколько раз. По
окончании циклов тоже, тогда она будет написана внизу, после вывода самих чисел. Переменной k присваивается первое нечетное значение 1.
Начинается внешний цикл по количеству чисел, от 1 до n. В цикле несколько операторов, поэтому "открываются" операторные скобки: - begin ...
Перед началом внутреннего цикла обнуляется переменная s - сумма. Причем такое
обнуление будет происходить каждый раз, когда повторяется внешний цикл, перед началом выполнения внутреннего цикла.
Внутренний цикл выполняется от 1 до i. Почему? В цикле вычисляется сумма и увеличивается нечетное k на 2, т. е. "вырабатывается" следующее нечетное число.
Заметьте! Переменной k не присваивается перед началом каждого внутреннего
цикла 1. Почему?
Следующим оператором writeln внутри внешнего цикла выдается информация на
экран. Почему он размещен во внешнем цикле?
Пример 4. Из математики известно, что всякая натуральная степень числа n есть
сумма n последовательных нечетных натуральных чисел. Составьте программу, которая
для любой степени натурального числа n находила бы последовательность нечетных чисел, сумме которых равна эта степень.
Например, для 53 она выдавала бы последовательность чисел: 21, 23, 25, 27, 29.
86 
План составления программы
1. Определим цель составления программы: надо показать, что действительно любую натуральную степень натурального числа можно представить в виде суммы последовательных нечетных чисел.
А если это так, тогда нам совершенно необходимо знать значение степени числа n с
показателем k.
Это можно сделать с помощью простого цикла:
s := 1;
for i := 1 to k do s := s*n;
Значение степени будут накапливаться в переменной s, для этого ей устанавливается
первоначальное значение 1.
В цикле, значение переменной s последовательно, k раз умножается на основание
степени n. После выполнения цикла переменная s получит значение степени числа n с показателем k.
2. Вся острота вопроса состоит в том, что неизвестно первое нечетное число, от которого надо начинать суммирование последовательных нечетных чисел.
Для этого надо пробовать складывать нечетные числа вначале от 1 и далее (известно их количество - n);
1 + 3 + 5 + 7 + 9 ...,
а затем проверять полученный результат, сравнивая со значением степени s. Если
равенство выполняется, тогда закончить цикл и вывести на экран полученные нечетные
числа, если равенство не выполняется, тогда надо начинать суммирование со следующего
нечетного числа - 3: 3 + 5 + 7 + 9 ... и т.д.
Этот процесс легче организовать с помощью цикла repeat. Переменной j, которая
будет задавать начальные нечетные числа надо установить перед началом цикла первоначальное значение 1.
Общий вид такого цикла:
j := 1;
repeat
......
j := j + 2
until ...= s;
3. Осталось продумать, как подсчитывать суммы последовательных нечетных чисел.
Мы уже сталкивались с этим вопросом и знаем, что для этого надо создать цикл от 1 до n,
в котором в одну из переменных, скажем m, накапливать эту сумму, а вторая переменная
должна "вырабатывать" следующее нечетное число.
Этот цикл можно записать так:
p := j; m := 0;
for i := 1 to n do
begin
m := m + p; p := p + 2
end;
Обратите внимание! Переменная p, каждый цикл repeat, (внешний по отношению
к данному), будет получать новое начальное значение нечетного числа, а переменная m для суммы должна обнуляться перед каждым новым суммированием для другой последовательности нечетных чисел.
4. Наконец, когда последовательность нечетных чисел найдена, ее надо вывести на
экран. Для этого надо устроить еще один цикл от 1 до n, в котором выдавать значения
этих нечетных чисел. За первое нечетное число из последовательности надо взять значение j, но так как оно уже увеличилось на 2, то из j следует вычесть 2. Этот цикл будет:
87

j := j - 2;
for i := 1 to n do
begin
write(j, ' ');
j := j + 2
end
Программа
Program Problem4;
uses WinCrt;
var
n, i, k, j, m, s, p : longint;
begin
write('Введите натуральное число - основание степени '); readln(n);
write('Введите натуральное число - показатель степени '); readln(k);
s := 1; j := 1;
for i := 1 to k do s := s*n;
repeat
p := j; m := 0;
for i := 1 to n do
begin
m := m + p;
p := p + 2
end;
j := j + 2
until m=s;
write('Степень с основанием ', n);
writeln(' и показателем ', k, ' т. е. ', s);
writeln('равна сумме следующих нечетных чисел');
j := j - 2;
for i:=1 to n do
begin
write(j, ' ');
j := j + 2
end
end.
Чтобы лучше понять ее работу, возьмите степень 25 и проверьте как будут последовательно выполняться операторы программы.
Задание 3
1. Выполните эту программу на компьютерах.
2. Составьте программу, которая выясняет, может ли произведение а) трех; б) четырех последовательных натуральных чисел равняться некоторой степени некоторого натурального числа (квадрату, кубу, и т. д.)?
88 
4. Разные задачи
Пример 5. Напечатать все четырехзначные числа, в десятичной записи которых нет
двух одинаковых цифр.
Сразу возникает мысль составить программу по следующей схеме:
организовать цикл по числу тысяч, t от 1 до 9,
а затем внутренние циклы: по числу сотен, s от 0 до 9;
по числу десятков, d от 0 до 9;
по числу единиц, e от 0 до 9;
проверка условия:
если цифры различны, тогда составленное из них четырехзначное число
t  1000  s  100  d  10  e выдавать на экран.
Программа
Program Problem5; { 1 - й способ }
uses WinCrt;
var
t, s, d, e : integer;
begin
writeln('Все четырехзначные числа из разных цифр');
for t := 1 to 9 do
for s := 0 to 9 do
for d := 0 to 9 do
for e := 0 to 9 do
if (t <> s) and (t <> d) and (t <> e) and (s <> d) and
(s <> e) and (d <> e)
then write(t*1000 + s*100 + d*10 + e, ' ')
end.
Понятно, что эта программа выполнена нерационально. В ней все циклы выполняются полностью.
Программу можно усовершенствовать таким путем. Когда выполняется цикл сотен,
тогда следующий цикл десятков надо начинать выполнять, если цифра сотен s не равна
цифре тысяч t, в противном случае, иначе, цикл сотен надо продолжить, т. е. взять следующую цифру сотен.
Для цифры десятков, также установить условие, что следующий цикл единиц будет
выполняться, если цифра десятков d не равна цифре сотен и тысяч, в противном случае,
иначе, надо переходить к следующей цифре десятков.
И тогда, "внутри" цикла единиц достаточно записать условие, если цифры единиц e
не равны цифре десятков d, сотен s и тысяч t, тогда четырехзначное число является искомым и оно выводится на экран.
Программа
Program Problem5a; { 2 - й способ }
uses WinCrt;
var
t, s, d, e : integer;
begin
writeln('Все четырехзначные числа из разных цифр');
89

for t := 1 to 9 do
for s := 0 to 9 do if s <> t then
for d := 0 to 9 do if (d <> s) and (d <> t) then
for e := 0 to 9 do
if (e <> d) and (e <> s) and (e <> t)
then write((((t*10 + s)*10 + d)*10) + e, ' ')
end.
Задание 4
1. Дополните и измените эту программу так, чтобы она выдавала на экран не только
различные четырехзначные числа, но и их количество.
2. При умножении четырехзначного числа, состоящего из разных цифр, на 9 получилось в произведении число, которое отличалось от множимого только тем, что между
цифрами тысяч и сотен оказался нуль. Найти множимое.
Пример 6. Тройки натуральных чисел a, b, c, удовлетворяющих равенству:
a  b2  c2 , - называются Пифагоровыми числами.
Например, 3, 4 и 5 являются Пифагоровыми числами, поскольку 32  4 2  52 .
Составить программу для нахождения и печати всех Пифагоровых чисел, не превышающих 20.
2
Математика этого вопроса проста. Для чисел a, b и c возможные значения - это натуральные числа от 1 до 20.
Первоначальное значение a - единица, a = 1. Будем просматривать всевозможные
значения b от 1 до 20, а также значения c от 1 до 20 и проверять выполнение равенства
a  a + b  b = c  c. Как только равенство будет выполняться, тогда выводить на экран значения a, b и c.
Далее надо брать значение a = 2 и проверять значения b уже от 2 до 20. Почему не от
1, а от 2? Да потому, что набор двух чисел из 1 и 2 уже был рассмотрен при значениях a =
1 и b = 2, чтобы не повторять значения a и b, т.е. избежать появления двух одинаковых пар
чисел, значения b следует начинать просматривать или до значения a или от a до 20.
В связи с этим, возможны несколько способов организации циклов для переменных
a и b.
1-й способ:
for a := 1 to 20 do
for b := a to 20 do
2-й способ:
for a := 20 downto 1 do
for b := 1 to a do
3-й способ:
for a := 1 to 20 do
for b := 1 to a do
90 
Нетрудно видеть, что при каждом из этих способов не будут повторяться пары чисел. Проверьте это самостоятельно.
Для значений c мы обязаны проверять все натуральные числа от 1 до 20 для каждой
пары чисел a и b. Поэтому цикл для c должен быть таким: for c := 1 to 20 do
Программа
Program Problem6;
uses WinCrt;
var
a, b, c : integer;
begin
writeln('Тройки Пифагоровых чисел из промежутка [1; 20]');
for a := 1 to 20 do
for b := 1 to a do
for c := 1 to 20 do
if a*a + b*b = c*c then writeln(a, ' ', b, ' ', c)
end.
Задание 5
1. Составьте программу, которая находит все решения уравнения x 2  y 2  n, где n заданное число, из промежутка [2; 100].
2. Найти все натуральные x из промежутка [1; 1000], для которых выражение
22x  5 является квадратом натурального числа.
Пример 7. Сколькими способами заданное натуральное число n можно представить
в виде суммы двух кубов натуральных чисел:
n  i3  j 3 ?
Перестановка слагаемых нового способа не дает. Операцией возведения в степень
1/3 пользоваться нельзя.
Сразу возникает следующая простая идея составления программы.
Организовать два цикла, один - внешний цикл с переменной i от 1 до n, а второй внутренний цикл по j, также от 1 до n.
Сущность работы программы будет заключаться в следующем:
первое значение i равно 1, оно умножается трижды само на себя (этим заменяется
возведение в 3-ю степень);
затем "перебираются" все значения j от 1 до n, каждое из которых также умножается
трижды на себя и складывается со значением i  i  i, т. е. i в кубе;
далее, эта сумма проверяется, равна ли она значению n, если равенство выполняется,
тогда счетчик, заведомо определенный в программе увеличивается на 1, а значения i и j
можно вывести на экран;
цикл по i продолжается, i принимает второе значение - 2 и снова начинает выполняться внутренний цикл по j от 1 до n и так далее.
Если мы составим программу по этому плану, то она будет иметь два существенных
недостатка:
1) проделывается много бесполезной работы - оба цикла организованы от 1 до n и
среди них много лишних (достаточно брать значения от 1 до корня кубического из n);
91

2) программа будет выдавать значения, которые получаются при перестановки слагаемых, например: 2  2  2 + 3  3  3 = 35 и 3  3  3 + 2  2  2 = 35, что является недопустимым по условию задачи. Как устранить эти недостатки?
Первый недостаток устраним, если предварительно выясним, сколько значений для
каждого из чисел надо рассматривать, чтобы выполнялось неравенство i  i  i  1  n.
Для этого можно организовать цикл с предусловием, цикл "пока", в который включить счетчик - k, который бы подсчитывал, сколько раз такой цикл будет выполняться.
Это можно сделать так:
k := 0; i := 1;
while i*i*i + 1 <= n do
begin
k := k + 1; i := i + 1
end;
Теперь можно значительно уменьшить число циклов для "испытуемых" чисел и организовать их от 1 до k, ибо при значениях i больше k, даже при самом маленьком значении j (j := 2) неравенство i  i  i + 1 <=n не выполняется.
Чтобы устранить второй недостаток, т. е., чтобы не выдавать варианты с перестановкой слагаемых можно поступить так:
внешний цикл по i первого числа устроить от k до 1, а внутренний цикл для второго
числа по j делать от 1 до i.
Получится такая часть программы:
p := 0;
for i := k downto 1 do
for j := 1 to i do if i*i*i + j*j*j = n
then
begin
p := p + 1;
writeln(i, '*', i, '*', i, '+', j, '*', j, '*', j, '=', n)
end;
Внимательно разберитесь с этой частью программы и подумайте, почему в этом случае мы избегаем повторения вариантов и исключаем случаи перестановки слагаемых?
Осталось красиво закончить программу. Ведь очень часто будут встречаться случаи,
когда число вообще нельзя представить в виде суммы кубов двух чисел. Надо учесть и это
обстоятельство.
Для этого, после выполнения всех циклов введем условный оператор, в котором, в
зависимости от значений счетчика p будут выдаться соответствующие сообщения.
Если p = 0, тогда выдать сообщение, что число нельзя представить в виде суммы
кубов двух чисел, а иначе, выдать сообщение о количестве способов.
Эта часть программы может быть выполнена так:
if p = 0 then
begin
write('Число ', n, ' нельзя представить в виде ');
writeln('суммы кубов двух чисел')
end
else writeln('Число способов равно ', p)
92 
Полностью программа, составленная по описанному плану, будет следующей:
Program Problem7;
uses WinCrt;
var
i, j, n, k, p : longint;
begin
write('Введите натуральное число '); readln(n);
k := 0; i := 1;
while i*i*i + 1 <= n do
begin
k := k + 1; i := i + 1
end;
p := 0;
for i := k downto 1 do
for j := 1 to i do
if i*i*i + j*j*j=n then
begin
p := p + 1;
writeln(i, '*', i, '*', i, '+', j, '*', j, '*', j, '=', n)
end;
if p = 0
then
begin
write('Число ', n, ' нельзя представить в виде ');
writeln('суммы кубов двух чисел')
end
else writeln('Число способов равно ', p)
end.
Еще одно решение этой задачи
Program Problem7b;
uses WinCrt;
label 1, 2;
var
i, j, m, k, n : longint;
begin
write('Введите натуральное число '); readln(n);
m := 0; i := 1; j := 1;
while j*j*j + 1 < n do j := j + 1;
repeat
k := i*i*i + j*j*j;
if k = n then m := m + 1;
if k <= n then i := i + 1;
if k >= n then j := j - 1;
until i > j;
if m = 0 then goto 1;
write('Число ',n,' можно представить в виде суммы');
writeln(' кубов двух чисел ',m,' способами'); goto 2;
1: write('Это число не представимо в виде');
writeln(' суммы кубов двух чисел');
2: end.

93
Задание 6
Дано натуральное n. Можно ли n представить в виде суммы трех квадратов натуральных чисел? Если можно, то указать все тройки x, y, z таких натуральных чисел, что
x 2  y 2  z 2  n.
Перестановка слагаемых нового способа не дает. Составить программу.
5. Преобразование типов
Пример 8. Двузначное десятичное число в сумме с числом, записанным теми же
цифрами, но в обратном порядке, дает полный квадрат. Найти все такие числа.
Пусть искомое двузначное число ab = a  10 + b, тогда число, записанное теми же
цифрами, но в обратном порядке будет ba = b  10 + a, например, 12 и 21, 13 и 31 и т. п.
Сумма этих чисел должна давать полный квадрат, т.е. точный квадрат целых чисел.
Как это проверить?
Проверку можно было бы выполнить так: извлечь квадратный корень из полученной
суммы; затем округлить результат до целого числа, а потом умножить полученный результат на себя, если снова получится сумма этих чисел, то значит она является точным
или полным квадратом.
Например, 12 + 21=33, извлекаем квадратный корень из 33, он равен 5.74...; округляем, будет 6; умножаем 6 само на себя и получаем 36.
Мы не получили исходного результата, значит сумма 33 не является точным квадратом.
Еще один пример, чтобы вам была понятна идея решения. Пусть двузначное число
29, тогда число, записанное теми же цифрами, но в обратном порядке - 92, в сумме они
дают 121. Извлекаем квадратный корень из 121 и получаем 11. Умножив 11 само на себя,
снова получим 121. Делаем вывод, что получен точный квадрат, а значит двузначное число 29 является искомым.
Чтобы составить программу по этому принципу, придется извлекать квадратный корень из суммы, что можно сделать с помощью стандартной функции sqrt(x). Результат
функции sqrt(x) является вещественным числом, его надо округлить или отбросить дробную часть, а нам неизвестно, как это сделать.
Но, даже более существенным, является то, что если квадратный корень в множестве
целых чисел извлекается нацело, как для 121 (он равен 11), то на множестве вещественных чисел мы не получим строго число 11, а результат будет очень близок к 11 и после
умножения на себя всё равно не получится 121, т.е. возникает необходимость преобразовать вещественное значение в целое.
Итак перед нами две задачи: 1) выяснить как округлять числа и; 2) установить, как
преобразовывать вещественный тип в целый.
Для этого в Паскале есть стандартные функции round(x) и trunc(x)
Стандартные функции round и trunc предназначены для замены значений вещественного типа значениями целого типа.
Функция round(x) округляет вещественное число x до целого - ее значение есть
ближайшее целое число:
round(4.2) = 4, round(4.7) = 5, round(4.5)=5,
round(-4.2) = -4, round(-4.7) = -5, round(-4.5) = -5.
94 
Функция trunc(x) отбрасывает (без округления) дробную часть вещественного числа
x:
trunc(1.2) = 1, trunc(5.8) = 5, trunc(-1.2) = -1,
trunc(-5.8) = -5, trunc(-6.7) = -6, trunc(8,9) = 8
Функции округления связаны так:
trunc(x + 0.5) = round(x), если x  0,
trunc(x - 0.5) = round(x), если x < 0.
Итак, в программе можно воспользоваться одной из этих функций. Какой? Подумайте сами и попробуйте применить в программе вначале функцию trunc, а потом замените ее
на round и сравните полученные результаты.
Программа
Program Problem8;
uses WinCrt;
var
d, e, k : integer;
begin
writeln('Искомые двузначные числа');
for d := 1 to 9 do
for e := 1 to 9 do
begin
k := round(sqrt(d*10 + e + e*10 + d));
if k*k = d*10 + e + e*10 + d
then write(d*10 + e, ' ')
end
end.
Задание 7
Найти целые числа из заданного промежутка [m; n], которые являются точными
квадратами и остаются таковыми после приписывания к ним справа единицы (в десятичной системе записи).
Упражнения
37. Составьте программу, которая находит 4 последовательных натуральных числа,
произведение которых равно 1680.
38. Показать, что четырехзначное число, у которого цифры тысяч и десятков одинаковы и цифры сотен и единиц тоже одинаковы, не может быть точным квадратом.
39. Произведение шести последовательных натуральных чисел может быть равно
произведению трех последовательных натуральных чисел. Например, 1  2  3  4  5  6 =
8  9  10 = 720. Есть ли еще такие числа?
40. Доказать, что произведение четырех последовательных целых чисел в сумме с
единицей дает полный квадрат.
41. Найдите 11 последовательных натуральных чисел, сумма квадратов которых есть
квадрат целого числа.
42. Существуют ли такие целые числа, которые уменьшаются в 57 раз при зачеркивании их первой (слева) цифры?
95

43. Найти четырехзначное число, зная, что оно является квадратом натурального
числа и что цифры его распадаются на две пары, состоящие из одинаковых цифр.
44. Найдите все семизначные числа, которые делятся на 15 и записываются только
цифрами 0 и 1.
45. Шестизначное число начинается с цифры 1. Если эту цифру переставить в конец
числа, то новое число будет в три раза больше первоначального. Найдите число.
46. Сколько точных квадратов можно составить из цифр 3, 4, 5, 6?
47. Даны 20 различных натуральных чисел, не больших 50. Найдите два из них, разность которых равна 4, 5 или 9.
48. Во сколько раз увеличится двузначное число, если справа к нему приписать такое
же двузначное число?
49. Определить наибольшее значение отношения трехзначного числа к числу, равному сумме цифр этого числа.
50. Найти трёхзначное число, кратное 45, если разность между этим числом и числом, записанным теми же цифрами, но в обратном порядке равна 297.
51. Найти четырёхзначное число abcd , кратное 11, при условии: b + c = a и bc есть
полный квадрат.
52. Найти трёхзначное число, равное сумме цифры десятков, квадрата цифры сотен и
куба цифры единиц.
53. Найти два числа, произведение которых есть трёхзначное число, являющееся кубом некоторого числа, а частное является квадратом этого числа.
54. Разность между числом и произведением его цифр равна сумме цифр этого числа. Найти это число.
55. Найти все значения числа m, для которых сумма 1! + 2! + ,,, + m! является полным квадратом.
56. Найти положительное четырёхзначное число, кратное 7 и представляющее собою
сумму куба и квадрата некоторого числа.
57. Некоторое число при делении на 7 дает в остатке 3; его квадрат при делении на
2
7 дает остаток 44; его куб при делении на 73 даёт остаток 111. Найти это число.
58. При каком натуральном значении a число a2 + a + 1589 будет точным квадратом?
59. Найти совершенное число вида 16p.
60. Найти два числа, если сумма их квадратов равна 468, а сумма их общего
наибольшего делителя и наименьшего кратного равна 42.
Ответы
К заданию 1
Program Task1;
uses WinCrt;
var
n, f, i, s : longint;
begin
write('Введите натуральное число '); readln(n);
s := 0; f := 1;
for i := 1 to n do
begin
f := f*i; s := s + f
end;
writeln('Сумма факториалов чисел от 1 до ', n, ' равна ', s)
end.
96 
К заданию 4
Program Task4;
uses WinCrt;
var
t, s, d, e : integer;
begin
writeln('Искомое четырехзначное число');
for t := 1 to 9 do
for s := 0 to 9 do if s <> t then
for d := 0 to 9 do if (d <> s) and (d <> t) then
for e := 0 to 9 do
if (e <> d) and (e <> s) and (e <> t) then
if (t*1000 + s*100 + d*10 + e)*9 = t*10000 + s*100 + d*10 + e
then writeln(t*1000 + s*100 + d*10 + e)
end.
К заданию 6
Program Task6;
uses WinCrt;
var
x, y, z, n, k, p : longint;
begin
write('Введите натуральное число '); readln(n);
k := 0; x := 1;
while x*x + 2<=n do
begin
k := k + 1; x := x + 1
end;
p := 0;
for x := 1 to k do
for y := 1 to x do
for z := 1 to y do
if x*x + y*y + z*z=n
then
begin
p := p + 1;
writeln(x, '*', x, '+', y, '*', y, '+', z, '*', z, '=', n)
end;
if p=0
then
begin
write('Число ', n, ' нельзя представить в виде ');
writeln('суммы квадратов трех чисел')
end
else writeln('Число способов равно ', p)
end.
97

К заданию 7
Program Task7;
uses WinCrt;
var
m, n, i, k, k1 : longint;
begin
write('Введите начало промежутка '); readln(m);
write('Введите конец промежутка '); readln(n);
write('Искомые числа ');
for i := m to n do
begin
k := round(sqrt(i));
k1 := round(sqrt(i*10 + 1));
if (k*k = i) and (k1*k1 = i*10 + 1) then write(i, ' ')
end
end.
98 
Глава 7. Подпрограммы на паскале. Процедуры и функции. Рекурсия
1. Дедуктивный метод программирования
Отвлечемся на некоторое время от составления программ и поговорим о творческом
процессе вообще, не только программиста или математика, а, например, художника или
архитектора.
Допустим, что художник собирается нарисовать картину: портрет человека или чтото другое. Прежде, в глубине его сознания созревает общий образ будущего произведения, затем начинается ее реальное воплощение на холсте, бумаге, дереве или на чем-то
другом. И вот здесь начинается тяжелейшая работа. Художник выполняет эскизы, рисунки отдельных фрагментов картины, а потом создает единое произведение, воплощающее в
красках, цвете и тени, выношенный им образ.
Архитектор задолго до создания проекта своей новой конструкции также видит его
целиком, а затем воплощает по отдельным частям единый проект здания или сооружения.
Подобно им и программист должен видеть в целом программу, которая решает какую-то задачу, а потом разбивает ее на отдельные части, составляет на выбранном языке
программирования эти части программы, объединяет их в единое целое и получает программу.
Итак, весь творческий процесс можно разбить (разумеется, чисто условно) на следующие этапы:
1) основная идея решения задачи;
2) общая конструкция программы;
3) выделение отдельных, элементарных частей программы;
4) практическая реализация на языке программирования этих частей программы;
5) объединение их в единую программу.
Такой процесс программирования называют структурным или нисходящим. Более
подробно с этим процессом мы познакомимся позже, когда изучим хотя бы основы языка
программирования, но об отдельных частях, "кирпичиках", составляющих программу
узнаем на этом занятии.
Подпрограммой называется группа операторов, к которой обращаются из основной
программы несколько раз. Иногда это может быть 2, 3 раза, а очень часто, каждый раз из
выполняемого цикла основной программы.
Вполне понятно, что писать несколько раз одинаковые группы операторов трудно,
проделывается много "технической" работы, а в некоторых случаях просто невозможно
(если обращаться приходиться каждый раз при выполнении цикла).
Для облегчения такой работы и созданы подпрограммы.
Использование подпрограмм позволяет:
1) сделать основную программу более наглядной и компактной;
2) уменьшить объем используемой памяти ЭВМ;
3) сократить время отладки программы.
На языке Паскаль подпрограммы бывают двух видов, - это процедуры и функции.
2. Процедуры
Рассмотрим следующий простой пример, с помощью которого попробуем разобраться в конструкции процедур на Паскале.
99

Пример 1. Составить программу, которая бы проверяла, являются ли три числа взаимно простыми.
Мы знаем, что числа называются взаимно простыми, если их наибольший общий делитель (НОД) равен 1. Значит, для решения этой задачи нам придется дважды находить
НОД чисел. Если заданы три числа: a, b, c, то найти НОД(a, b), а затем найти НОД(НОД(a,
b), c).
Дважды писать операторы для нахождения НОД нам не хочется, поэтому оформим
операторы для НОД в виде процедуры.
Посмотрите, как это будет выглядеть в программе:
Program Problem1;
uses WinCrt;
var
a, b, c, k : integer;
{----------------------------------------------------------------------------------------}
Procedure nod(a, b : integer; var n : integer);
var
r : integer;
begin
repeat
r := a mod b;
a := b; b := r
until b = 0;
n := a
end;
{---------------------------------------------------------------------------------------}
begin
write('Введите три натуральных числа '); readln(a, b, c);
nod(a, b, k);
a := k; b := c;
nod(a, b, k);
if k = 1 then writeln('Числа взаимно простые')
else writeln('Числа не взаимно простые')
end.
В разделе описаний, после описания переменных, записывается заголовок процедуры: Procedure
Это слово является служебным и зарезервировано в Паскале. В одной строке с ним,
через пробел, записывается имя процедуры, которое должно удовлетворять всем требованиям, предъявляемым к именам, основными из которых являются: начинаться с буквы и
не иметь пробелов, т. е., требования такие же, как и к имени программы (имя нашей процедуры - nod):
Procedure nod(a, b : integer; var n : integer);
Далее, в скобках, записываются имена переменных и их типы, значения которых будут вводиться в процедуру из основной программы, в нашем случае, их две (a, b) и они
имеют тип integer.
Сразу надо заметить, что имена этих переменных могут не совпадать с именами переменных в основной программе, скажем мы могли их обозначить m, n или любыми другими именами.
100 
После точки с запятой и зарезервированного слова var, записываются переменные и
их типы, значения которых будет являться результатом работы процедуры и выводятся
из нее в основную программу. Такая переменная в нашем примере одна - n. Она выведет
значение НОД чисел a и b. Ее имя также может иметь одноименное в основной программе
и это нисколько не отразится на работе процедуры.
Обратите внимание, что перед переменными, значения которых вводятся из основной программы, не ставится слово var, а перед переменной, значение которой выводится в основную программу, это слово записано. Это очень важное обстоятельство!
Так, если поставить var перед a и b, то компилятор будет воспринимать эти переменные как выходные и вводимые для них значения воспринимать не будет, и, наоборот,
если var не будет записано перед выходной переменной, то компилятор воспримет ее как
входную и выводить ее значение в основную программу не будет.
Дальнейшее построение процедуры строится также, как и основная программа на
Паскале.
Описываются переменные, которые будут участвовать в ее работе, но их имена не
должны повторять имена уже описанных входных и выходных параметров в заголовке
программы. Далее описываются необходимые для работы операторы.
В нашем примере процедура nod будет такой:
Procedure nod(a, b : integer; var n : integer);
var
r : integer;
begin
repeat
r := a mod b;
a := b; b := r
until b = 0;
n := a
end;
Основная программа строится обычным образом, но там, где необходимо найти
НОД чисел, обращается к процедуре. Как?
Для этого обращаются к ней по имени, а в скобках записывают фактические значения входных переменных (в нашем случае для переменных a и b), а также имена выходных переменных (в нашем случае k).
Из приведенного ниже участка программы видно, что при первом обращении к процедуре nod определяется НОД чисел a и b (nod(a, b, k) и результат запоминается в переменную k, далее, изменяются значения переменных a и b (a :  k ; b :  c) и снова вызывается процедура nod, которая уже находит НОД чисел k и c и результат присваивает
переменной k.
Вы можете видеть основную часть программы:
begin
write('Введите три натуральных числа '); readln(a, b, c);
nod(a, b, k);
a := k; b := c;
nod(a, b, k);
if k = 1 then writeln('Числа взаимно простые')
else writeln('Числа не взаимно простые')
end.
101

Сделаем общие выводы для построения и работы процедур
Процедуры помещаются в разделе описаний и начинается зарезервированным (служебным) словом
Procedure
Процедуре обязательно дается имя, которое должно удовлетворять тем же требованиям, что и имена переменных, т.е. это может быть одна или несколько букв, комбинация
букв и целых чисел, но без пробелов, начинаться с буквы и т.д.
После имени, в скобках записываются переменные - параметры и их тип: входные,
значения которых используются для вычисления в качестве аргументов.
Выходные параметры - это те переменные, в которых получается результат выполнения процедуры.
Входные и выходные параметры процедуры называются формальными параметрами.
Фактические, конкретные, значения формальные параметры должны получить в основной программе после обращения к ней (а пока в процедуре они являются не чем иным,
как "пустышками").
После формальных параметров, описываются переменные, которые необходимы
непосредственно для работы процедуры.
Это параметры процедуры. Они нужны в ней, как и в любой другой программе и
описываются также. Их имена должны отличаться от имен входных и выходных параметров.
Надо заметить, что процедура может быть такой, что в ней не будет вообще параметров, достаточно тех, которые будут введены из программы.
Описание процедуры имеет вид:
Procedure <имя> (<входные параметры> : <их тип>;
var
<выходные параметры> : <их тип>);
(раздел описаний)
begin
(раздел операторов)
end;
Она помещается в основной программе в разделе описаний.
По входным и выходным параметрам процедуры могут быть следующих типов:
1) иметь и входные и выходные параметры:
Procedure <имя>(<входные параметры> : <их тип>;
var <выходные параметры> : <их тип>);
Мы только познакомились с программой такого типа.
2) иметь входные параметры, но не иметь выходных:
Procedure <имя>(<входные параметры> : <их тип>);
3) иметь выходные параметры, но не иметь входных:
Procedure <имя>(var <выходные параметры> : <их тип>);
4) не иметь ни входных, ни выходных параметров:
Procedure <имя>;
102 
В зависимости от этого различаются процедуры по своей конструкции и выполняемым функциям.
Далее следует раздел операторов, который составляется по тем же правилам, как и в
других программах.
Процедура описана и после этого начинается основная программа.
Вызов процедуры из программы
Как происходит вызов подпрограммы - процедуры?
Обязательно указывается имя процедуры. В скобках задаются фактические значения входных параметров и те переменные, в которые будут "запоминаться" выходные
значения.
Рассмотрим пример, где может быть использована процедура второго типа: имеет
входные параметры, но не имеет выходных.
Пример 2. Составить программу, которая устанавливает, какие числа из заданного
промежутка [a; b] можно представить в виде суммы двух квадратов целых чисел?
В этой программе, нам придется проверять каждое из чисел промежутка [a; b] можно
ли его представить в виде суммы квадратов двух чисел, поэтому было бы разумно разработать процедуру, которая бы проверяла одно число и затем обращаться к ней из основной программы для проверки каждого числа из промежутка.
Процедуру составим по следующему способу. Пусть задано число n. Нам необходимо найти такие два числа a и b, чтобы сумма их квадратов была равна n, т.е. решить в целых числах уравнение: a2  b2  n.
Возникает естественное желание испытывать натуральные числа от 1 и до ...? А вот
до какого значения неизвестно. Если их брать до числа n, то это будет слишком много
лишней и бесполезной работы.
Чтобы выяснить этот вопрос, можно организовать цикл, в котором проверять сколько чисел a надо, чтобы выполнялось неравенство: a  a  1  n. Здесь, в качестве b взято
наименьшее натуральное число 1. Организовав такой цикл, и подсчитав, сколько чисел a
потребуется, мы узнаем сколько чисел надо просматривать, чтобы найти решение уравнения.
Этот цикл может быть таким:
a := 1; k := 1;
while a*a + 1<=n do
begin
k := k + 1;
a := a + 1
end;
Теперь ясно, что для испытания чисел, следует устроить цикл от 1 до k:
for a := 1 to k do
Второй цикл должен быть для значений b. Но если его организовать тоже от 1 до k,
тогда могут повторяться дважды одинаковые значения, только на разных местах, например, для числа 20 могут быть выданы следующие значения:
22 + 42 = 20 и 42 + 22 = 20.
Чтобы избежать повторения чисел, цикл для чисел b можно организовать либо от 1
до a, либо от k до а.
Нами выбран первый вариант.
103

Процедура
Procedure to_square(n : integer);
label 1;
var
a, b, k : integer;
begin
a := 1; k := 1;
while a*a + 1<=n do
begin
k := k + 1;
a := a + 1
end;
for a := 1 to k do
for b := 1 to a do
if a*a + b*b = n
then
begin
writeln(n, '=', a, '*', a,' +', b, '*', b); goto 1
end;
1: end;
Процедура выполнена с досрочным прерыванием цикла, так как нет необходимости
выяснять всевозможные значения пар чисел, удовлетворяющих этому уравнению, а достаточно просто выяснить возможность такого представления.
Выполнив такую процедуру, не составляет труда решить полностью задачу. Для этого в основной программе выполнить цикл для всех чисел из промежутка, и каждое из которых, с помощью процедуры проверять. Кстати говоря, эта процедура имеет только один
формальный параметр - входной, - значение проверяемого числа из промежутка и не
имеет выходных параметров.
Программа
Program Problem2;
uses WinCrt;
var
a, b, i : integer;
{---------------------------------------------------------------------------------------}
Procedure to_square(n : integer);
label 1;
var
a, b, k : integer;
begin
a := 1; k := 1;
while a*a + 1 <= n do
begin
k := k + 1;
a := a + 1
end;
for a := 1 to k do
for b := 1 to a do
if a*a + b*b = n
104 
then
begin
writeln(n, '=', a, '*', a, '+', b,'*', b); goto 1
end;
1: end;
{----------------------------------------------------------------------------------------}
begin
write('Введите начало промежутка '); readln(a);
write('Введите конец промежутка '); readln(b);
write('Числа, которые можно представить в виде суммы ');
writeln('квадратов следующих чисел');
for i := a to b do to_square(i);
end.
Задание 1
1. Покажите, что квадрат числа, являющегося суммой двух точных квадратов, также
можно представить в виде суммы двух точных квадратов.
2. Покажите, что произведение двух целых чисел, из которых каждое есть сумма
квадратов двух целых чисел, можно представить в виде суммы двух точных квадратов.
Пример 3. Составить программу нахождения и вывода на экран всех простых чисел
из заданного промежутка [n; m]. (Массивы не использовать.)
Следует сразу заметить, что эта задача решается иначе с помощью программы "Решето Эратосфена", но ее мы будем разбирать при изучении работы с массивами чисел и
множествами.
А сейчас приведем другой вариант решения этой задачи. Ясно, что для ее решения
нам потребуется процедура, которая устанавливает, является ли число простым. На
предыдущих занятиях мы уже составляли такую программу. Сейчас вспомним ее работу и
возможно внесем некоторые изменения.
Алгоритм составления процедуры такой.
Во-первых, вспомним, какие числа называются простыми.
Натуральные числа, которые имеют только два делителя 1 и само себя называются
простыми. Остальные называются составными.
Из их числа исключается число 1, которое не относится ни к простым, ни к составным.
Первое простое число - это 2. Если оно есть, тогда его сразу надо выводить на
экран:
if p = 2 then write(p,' ')
Ясно, что все остальные четные числа являются составными, а значит их нет смысла
проверять. Для исключения из рассмотренных четных чисел введем для проверки условный оператор:
else if p mod 2 <> 0 then
Если число нечетное, тогда его надо проверять. Сущность проверки будет заключаться в определении числа делителей. Но нам уже известен математический факт, что все
делители некоторого натурального числа p находятся в промежутке от 1 до корня квадратного из этого числа (исключая само число). Значит, если имеются делители, в данном
случае, от 3 до trunc(sqrt(p)), то оно является составным, а если таких делителей нет (чет-
105

ные числа мы уже исключили, а единицу и само число p не рассматриваем), тогда число
будет простым.
Для проверки этого факта устроен следующий цикл:
begin
i := 3; k := 0;
while i <= trunc(sqrt(p)) do
begin
if p mod i = 0 then k := k + 1;
i := i + 2
end;
if k = 0 then write(p, ' ')
end
Полностью процедура, устанавливающая является ли число простым будет следующей (probleme number -простое число):
Procedure Probleme_number(p : integer);
var
i, k : integer;
begin
if p=2 then write(p, ' ') else if p mod 2<>0
then
begin
i := 3; k := 0;
while i<=trunc(sqrt(p)) do
begin
if p mod i = 0
then k := k + 1;
i := i + 2
end;
if k = 0 then write(p, ' ')
end
end;
Снова, эта процедура имеет только входной формальный параметр и не имеет
выходных.
Программу составить нетрудно. В ней достаточно организовать цикл для проверки
чисел из заданного промежутка и каждое из них проверять с помощью процедуры.
Program Problem3; { Простые числа из промежутка [n; m] }
uses WinCrt;
var
n, m, i : integer;
{----------------------------------------------------------------------------------------}
Procedure probleme_number(p : integer);
var
i, k : integer;
begin
if p=2 then write(p, ' ')
else if p mod 2 <> 0
106 
then
begin
i := 3; k := 0;
while i <= trunc(sqrt(p)) do
begin
if p mod i = 0 then k := k + 1;
i := i + 2
end;
if k = 0 then write(p, ' ')
end
end;
{----------------------------------------------------------------------------------------}
begin
write('Введите левую границу промежутка > 1 '); readln(n);
write('Введите правую границу промежутка '); readln(m);
writeln('Простые числа из промежутка [', n, ' ', m, ']');
for i := n to m do probleme_number(i);
writeln
end.
Пример 4. Французский физик М. Мерсен (1588 - 1648) заметил, что многие простые
числа имеют вид
2p - 1,
где p также простое число. Все числа такого вида называются числами Мерсена. Составить программу, которая находит числа Мерсена на заданном промежутке.
Алгоритм
Самый простейший алгоритм для составления программы, будет такой:
во-первых, необходима процедура для определения простых чисел, с которой мы уже
знакомы;
во-вторых, нужна процедура, которая вычисляет степень натурального числа с натуральным показателем (эту процедуру вы уже должны были составлять при выполнении
задания).
Процедура определения простого числа:
Procedure Probleme_number(p : longint; var v : longint);
var
i, k : longint;
begin
if p = 2 then v := p
else if p mod 2 <> 0
then
begin
i := 3; k := 0;
while i <= trunc(sqrt(p)) do
begin
if p mod i = 0 then k := k + 1;
i := i + 2
end;
if k = 0 then v := p
end
end;
107

Процедура вычисления степени натурального числа с натуральным показателем
(extent - степень):
Procedure extent(a, n : integer; var s : longint);
var
i : integer;
begin
s := 1;
for i := 1 to n do s := s*a
end;
В основной программе надо пробовать каждое число из промежутка, является ли оно
простым, а для этого необходимо обращение к процедуре probleme_number(i, p).
Если получено простое число, тогда следует 2 возвести в эту степень, а для этого
следует обратиться к процедуре extent(2, p, m).
Наконец, полученный результат также надо проверить, является ли он простым числом. Если является, тогда мы получаем число Мерсена.
Казалось бы все хорошо, но нас поджидают многие неприятности.
Неприятность первая! Выбрано число 3, процедурой probleme_number(i, p) установлено, что оно простое число и его значение присвоено переменной p. Следующим числом
из выбранного промежутка является 4, процедура probleme_number(i, p) установила, что
оно не является простым и его значение не присваивается переменной p. Тогда возникает
вопрос, а чему равно значение переменной p? Оказывается оно осталось прежним, т. е.
равным 3 - предыдущему простому числу.
Если продолжать дальше процесс в программе, тогда значения будут повторяться.
Аналогичное повторение будет и при проверке предполагаемого числа Мерсена, является
ли оно простым?
Чтобы избежать этих неприятностей, после каждой проверки, начиная с первой,
необходимо запоминать полученные значения простых чисел в новые переменные,
например: p1 := p; m1 := m; n1 := n, а затем перед повторным обращением к процедурам
вычисления степени и проверке простых чисел, проверять, а не являются ли эти значения
повторениями предыдущих.
Эта часть основной программы такая:
for i := 2 to b do
begin
probleme_number(i, p);
if p <> p1 then extent(2, p, m);
if m <> m1 then probleme_number(m-1, n);
if n <> n1 then write(n, ' ');
n1 := n; p1 := p; m1 := m
end;
Программа
Program Problem4; { Числа Мерсена }
uses WinCrt;
var
b, p, p1, m, m1, n, n1, i : longint;
{----------------------------------------------------------------------------------------}
Procedure Probleme_number(p : longint; var v : longint);
var
108 
i, k : longint;
begin
if p = 2 then v := p
else if p mod 2 <> 0
then
begin
i := 3; k := 0;
while i <= trunc(sqrt(p)) do
begin
if p mod i = 0 then k := k + 1;
i := i + 2
end;
if k = 0 then v := p
end
end;
{----------------------------------------------------------------------------------------}
Procedure extent(a, n : integer; var s : longint);
var
i : integer;
begin
s := 1;
for i := 1 to n do s := s*a
end;
{---------------------------------------------------------------------------------------}
begin
write('Введите правую гран. знач. показ. степ. '); readln(b);
write('Числа Мерсена: ');
for i := 2 to b do
begin
probleme_number(i, p);
if p <> p1 then extent(2, p, m);
if m <> m1 then probleme_number(m - 1, n);
if n <> n1 then write(n,'; ');
n1 := n; p1 := p; m1 := m
end;
writeln
end.
Замечание. В дальнейшем, при работе с массивами чисел, мы найдем более простой
способ нахождения чисел Мерсена с использованием "Решета Эратосфена".
Задание 2
Найти наименьшее натуральное число n, такое, что 2 n  2 не делится на n, но 3 n  3
делится на n.
(Составьте и используйте процедуру вычисления степени натурального числа с
натуральным показателем.)
109

Пример 5. Число, состоящее из n (n > 1) цифр, называется числом Армстронга, если
сумма его цифр, возведенных в n-ю степень равна самому этому числу.
Например, числами Армстронга являются 153 и 1634, так как
153 = 13 + 53 + 33, 1634 = 14 + 64 + 34 + 44.
Составить программу, которая будет находить все n-значные числа Армстронга (n входное данное, причем n < 10).
Математический анализ задачи
Пользователем задается, образно говоря, n - значность числа, т.е. количество цифр,
которое должно быть в числе. Например, он может задать, что числа 5-ти значные. Программа должна из всех пятизначных чисел найти числа Армстронга, если, конечно, такие
есть.
Для этого, в программе надо определять наименьшее n-значное число, что сделать
просто, организовав цикл от 1 до n - 1 и умножая, заведомо установленную переменную
(первоначальное значение которой равно 1) на 10. Чтобы установить наибольшее nзначное число, достаточно наименьшее n-значное умножить на 10 и вычесть 1. Например,
для 5-значных чисел, наименьшим будет 10000, а наибольшее 100000  1  99999.
Для определения наименьшего и наибольшего n-значного числа создадим такую
процедуру:
Procedure minmax(n : longint; var min, max : longint);
var
i : longint;
begin
min := 1;
for i := 1 to n - 1 do min := min*10;
max := min*10 - 1
end;
Каждую цифру числа придется возводить в n-ю степень, для этого снова потребуется
процедура возведения в степень. Она уже нам знакома:
Procedure extent(a, n : longint; var s : longint);
var
i : longint;
begin
s := 1;
for i := 1 to n do s := s*a
end;
В основной программе придется отделять по одной цифре, мы опять-таки знакомы с
этим процессом (находить остаток от деления на 10 - это последняя цифра, уменьшать
число в 10 раз, отбрасывая последнюю цифру целочисленным делением на 10).
Каждая цифра возводится в степень и результат суммируется, затем происходит
сравнение с исследуемым числом, если равенство выполняется, то исследуемое число число Армстронга.
for x := min to max do
begin
p := x; s := 0;
for i := 1 to n do
110 
begin
extent(p mod 10, n, k);
s := s + k;
p := p div 10
end;
if s = x then write(x, ' ')
end;
Программа
Program Problem5; { Числа Армстронга }
uses WinCrt;
var
n, min, max, x, p, s, i, k : longint;
{----------------------------------------------------------------------------------------}
Procedure extent(a, n : longint; var s : longint);
var
i : longint;
begin
s := 1;
for i := 1 to n do s := s*a
end;
{----------------------------------------------------------------------------------------}
Procedure minmax(n : longint; var min, max : longint);
var
i : longint;
begin
min := 1;
for i := 1 to n - 1 do min := min*10;
max := min*10 - 1
end;
{---------------------------------------------------------------------------------------}
begin
write('Введите количество цифр числа '); readln(n);
writeln(n, '-х значные числа Армстронга');
minmax(n, min, max);
for x := min to max do
begin
p := x; s := 0;
for i := 1 to n do
begin
extent(p mod 10, n, k);
s := s + k;
p := p div 10
end;
if s = x then write(x, ' ')
end;
writeln
end.
(И эту программу, впоследствии, мы будем выполнять с использованием массивов.)
111

Пример 6. Напишите программу, которая для каждого из целых чисел от 1 до n
напечатает все его делители. Например, 1 5 7 35 являются делителями числа 35. Аналогичный список делителей должен быть напечатан для каждого из чисел от 1 до заданного
числа n.
Алгоритм
Программа составляется очень просто. Для этого, надо создать процедуру определения делителей числа (программу мы разбирали на предыдущих занятиях) и для каждого
числа из данного промежутка обращаться к ней.
Получится следующая простая программа. Единственное замечание. При определении числа делителей в процедуре, проверяются делители числа до его целой половины (n
div 2), хотя мы знаем, что делители числа находятся до корня квадратного из него и находили их до trunc(sqrt(n)). Такое сделано только из соображений наглядности - в первом
случае делители выдаются на экран в порядке возрастания и это выглядит приятнее.
Program Problem6;
uses WinCrt;
var
i, n : integer;
{----------------------------------------------------------------------------------------}
Procedure math_divisor(n : integer);
var
d : integer;
begin
for d := 1 to n div 2 do
if n mod d=0 then write(d, ' ');
writeln(n)
end;
{----------------------------------------------------------------------------------------}
begin
write('Введите правую границу промежутка '); readln(n);
for i := 1 to n do
begin
write('Делители числа ', i, ' следующие: ');
math_divisor(i)
end
end.
Задание 3
1. Напишите процедуру, которая будет вычислять сумму правильных делителей числа n. Правильными делителями числа n являются все делители этого числа, за исключением его самого. Например, если n равно 12, то сумма правильных делителей есть 1 + 2 + 3 +
4 + 6 = 16. Для проверки правильности работы этой процедуры напишите главную программу, которая бы считывала различные значения n из заданного промежутка [a; b] и для
каждого вычисляла сумму его правильных делителей.
2. Натуральное число n является точным квадратом тогда и только тогда, когда оно
имеет нечетное число делителей. Доказать.
112 
Вызов процедуры из процедуры
Пример 7. Нумерация книжных страниц. В книге n страниц. Составим программу,
которая будет находить, сколько цифр понадобится для того, чтобы занумеровать все
страницы книги.
Решение
Математическое решение рассмотрим на частном примере, а потом сделаем общий
вывод.
Пусть нам требуется определить число цифр для нумерации 357 страниц.
Естественными рассуждения будут такими: однозначных цифр 9, значит они пронумеруют 9 страниц; двузначных чисел 90 - они нумеруют 90 страниц и используют 90 . 2 =
180 цифр; трехзначных чисел 900 - они пронумеруют 900 страниц и используют 2700
цифр. Следовательно, для нумерации данных 357 страниц потребуются все однозначные и
двузначные числа и часть трехзначных. Чтобы узнать, сколько трехзначных чисел потребуется для нумерации, надо из заданного числа вычесть "использованные" однозначные и
двузначные числа: 357 - (9 + 90) = 258.
Итак, всего потребуется цифр:
9 1  9
90  2  180
258  3  774
...........
Итого: 9 + 180 + 774 = 963 цифры.
Теперь обобщим наши соображения. Пусть задано число страниц n, которое имеет c
цифр. Тогда для нумерации потребуются цифры:
1 - значные; потребуется: 9  1 = 9 цифр;
2 - значные;
90  2 = 180 цифр;
х
3 - значные;
900  3 = 2700 цифр;
...................................
c-1 -значные;
9....0 . (c-1) . . . цифр,
а c-значных полностью не хватит, также, как не хватило полностью трехзначных для нумерации 357 страниц.
Чтобы узнать сколько потребуется c-значных цифр, надо из данного числа вычесть
все число одно, -дву, -трех,- и т. д., c-1 значные, которые уже использованы:
n  (9  90  900  9...0), а затем полученный результат умножить на c - значность числа.
c1
Сложив израсходованные цифры, мы получим окончательный результат.
Попробуем на основе этих рассуждений составить программу.
Прежде, составим процедуру, которая определяет число цифр во введенном числе
страниц. С такой программой мы уже раньше имели дело:
Procedure number(n : integer; var k : integer);
begin
k := 0;
repeat
k := k + 1;
n := n div 10
until n = 0
end;
113

В следующей процедуре будет находиться искомое число цифр. В ней, переменная
m будет служить для указания числа цифр в одно, - двух, - трех, ... c-значных числах (9,
90, 900, ..., 9...0).
Переменная c покажет число цифр в числе - номере страницы, в переменной z будет
накапливаться искомый результат, а сумма s даст нам сколько всего n-значных чисел было использовано для подсчета.
Первоначальные значения: m := 9; z := 0; s := 0, а число цифр числа будет получено
из процедуры number(n, c) и задаст значение переменной c:
m := 9; number(n, c); z := 0; s := 0;
Теперь организуем цикл по количеству цифр введенного числа страниц, от 1 до c - 1.
Переменная цикла i.
for i := 1 to c - 1 do
begin
z := z + m*i; {Сумма цифр}
s := s + m;
m := m*10
end;
В цикле подсчитывается сумма цифр (z := z + m*i), сумма использованных однозначных, двузначных и т.д. цифр.
После завершения цикла, к сумме z добавляются оставшиеся c-значные цифры:
z := z + (n - s)  c {n - s оставшиеся страницы c-значными}
{цифрами}
Процедура
Procedure Page(n : integer; var z : integer);
var
i, m, c, s : integer;
begin
m := 9;
number(n, c); z := 0; s := 0;
for i := 1 to c - 1 do
begin
z := z + m*i; {Сумма цифр}
s := s + m;
m := m*10
end;
z := z + (n - s)*c
end;
И, наконец, полностью программа
Program Problem7; { Число цифр для нумерации страниц }
uses WinCrt;
var
n, c : integer;
{----------------------------------------------------------------------------------------}
Procedure number(n : integer; var k : integer);
begin
k := 0;
114 
repeat
k := k + 1; n := n div 10
until n = 0
end;
{----------------------------------------------------------------------------------------}
Procedure Page(n : integer; var z : integer);
var
i, m, c, s : integer;
begin
m := 9; number(n, c); z := 0; s := 0;
for i := 1 to c - 1 do
begin
z := z + m*i; {Сумма цифр}
s := s + m; m := m*10
end;
z := z + (n - s)*c {n - s оставшиеся страницы c-значными цифрами}
end;
{----------------------------------------------------------------------------------------}
begin
write('Введите число страниц '); readln(n);
page(n, c);
writeln('Число цифр, необходимых для нумерации ', c)
end.
Задание 4
Составьте программу для решения обратной задачи: для нумерации страниц книги
потребовалось k цифр (k - входное данное). Сколько страниц в книге? Если указанное
число цифр не может служить для нумерации какого-либо количества страниц, то результат программы считайте равным 0.
Пример 8. Одна машинистка напечатала подряд без интервалов натуральные числа:
12345678910111213141516... .
Если подобным образом напечатать 1000 цифр, то какая цифра будет последней?
Решение
Решение будем выполнять по простой идее. Просматривать подряд числа, так как
они пишутся машинисткой, подсчитывать сумму цифр каждого из чисел, находить общую
сумму цифр и, когда она станет равна 1000, тогда прекратить процесс и выдать последнюю цифру на экран.
Но в этом алгоритме нас подстерегают некоторые неожиданности. Давайте проанализируем порядок записи машинисткой чисел.
Вначале пишутся однозначные числа - и здесь все в порядке, с помощью процедуру
подсчитывается сумму цифр каждого однозначного числа (она равна 1), с помощью сумматора - 9 раз по 1 суммируется общее количество цифр.
Затем пишутся двузначные числа, процедура подсчета цифр будет выдавать сумму
цифр 2 для каждого двузначного числа, а сумматор увеличиваться каждый раз уже сразу
на 2 (90 раз), затем для трехзначных чисел - к сумматору будет прибавляться по 3 единицы. Возникает вопрос, где гарантия, что общая сумма цифр будет в точности равна 1000.
115

Ведь очень даже может случиться, что после прибавления очередной двойки, тройки или
четверки, общее число цифр "перепрыгнет" эту 1000-ю границу.
Как быть в таком случае? Это вызывает необходимость организовать цикл repeat ...
until ... до тех пор, когда сумматор s станет больше заданной суммы цифр n (s  n). Такое
положение дел будет означать, что в последнем проверяемом числе (p) имеются "лишние"
и ненужные нам цифры:
write('Введите число цифр '); readln(n);
p := 1; s := 0;
repeat
number(p, v);
s := s + v; p := p + 1
until s >= n;
Выясняем сколько этих "лишних" цифр (m := s - n). Чтобы отбросить их, надо разделить последнее число p (а оно в силу инертности работы цикла увеличится еще на 1, поэтому действительное последнее число, сумма цифр которого подсчитывалась равно: p :=
p - 1) на 10, 100, 1000 и т. п., короче, на единицу с нулями, у которого столько нулей,
сколько лишних цифр нами обнаружено, т. е. m.
С этой целью организуется цикл от 1 до м, в котором это число и строится:
m := s - n; p := p - 1; q := 1;
for i := 1 to m do q := q*10;
Теперь оно стало равно q. Далее следует разделить число p на q и "отбросить" ненужные цифры (c := p div q), а вот чтобы найти искомую цифру, надо еще найти остаток
от деления c на 10 (а вдруг в оставшемся после деления на q числе еще остались не одна, а
2, 3 или более цифры, например, 2345 div 100  23, 23 mod 10  3 ).
Это выполняется последней группой операторов:
c := p div q; c := c mod 10;
Вам остается подумать, будет ли работать программа, когда сумма цифр s и число
заданных цифр n окажутся равными?
Программа
Program Problem8; { Определение цифр в записи 1234567... }
uses WinCrt;
var
n, p, s, c, v, q, i, m : integer;
{----------------------------------------------------------------------------------------}
Procedure number(n : integer; var k : integer); {Число цифр}
begin
k := 0;
repeat
k := k + 1;
n := n div 10
until n = 0
end;
{----------------------------------------------------------------------------------------}
116 
begin
write('Введите число цифр '); readln(n);
p := 1; s := 0;
repeat
number(p,v);
s := s + v; p := p + 1
until s >= n;
m := s - n; p := p - 1; q := 1;
for i := 1 to m do q := q*10;
c := p div q; c := c mod 10;
writeln('Последняя цифра в записи этих цифр будет: ', c);
writeln('Она находится в числе ', p)
end.
Задание 5
Изучив две предыдущие программы, вы можете выбрать некоторый свой способ для
решения такого типа задач. Попробуйте предложить свой способ для решения задачи аналогичной примеру 5. Выписать подряд все четные числа: 24681012... . Какая цифра стоит
на 1971-м месте?
Пример 9. Счастливые автобусные билеты.
Номера автобусных билетов представляют собой шестизначные числа. Счастливым
считается тот билет, у которого сумма первых трех цифр равна сумме последних трех
цифр. Например, билет 356428 считается счастливым, так как:
3 + 5 + 6 = 4 + 2 + 8 =14.
Будем считать, что номера билетов принадлежат промежутку
[100000; 999999].
Составить программу определения счастливого билета.
Алгоритм
Для программы составим две процедуры: одна - определяющая сумму цифр введенного числа, уже известную нам (sum number - сумма цифр):
Procedure sum_number(p : longint; var s : longint);
begin
s := 0;
while p <> 0 do
begin
s := s + p mod 10;
p := p div 10
end
end;
вторую - отделяющую первые и последние три цифры, а затем, с помощью вызова
процедуры sum_number, устанавливает равны ли эти суммы (happiness - счастье):
Procedure happiness(x : longint);
var
l, r : longint;
117

begin
sum_number(x mod 1000, l);
sum_number(x div 1000, r);
if l = r then write(x,' ')
end;
x mod 1000 - отделяет последнее трехзначное число, а x div 1000 - первое трехзначное
число.
Программа
Program Problem9; { Счастливые автобусные билеты }
uses WinCrt;
var
i : longint;
{----------------------------------------------------------------------------------------}
Procedure sum_number(p : longint; var s : longint);
begin
s := 0;
while p <> 0 do
begin
s := s + p mod 10;
p := p div 10
end
end;
{----------------------------------------------------------------------------------------}
Procedure happiness(x : longint);
var
l, r : longint;
begin
sum_number(x mod 1000, l);
sum_number(x div 1000, r);
if l = r then write(x, ' ')
end;
{---------------------------------------------------------------------------------------}
begin
writeln('Счастливые автобусные билеты');
for i := 100000 to 999999 do happiness(i);
writeln
end.
Этот алгоритм можно изменить, учитывая следующее. Если мы имеем некоторый
"счастливый" номер, последняя цифра которого отлична от нуля, а предпоследняя - от девяти, то следующий "счастливый" номер может быть получен одновременным уменьшением последней цифры и увеличением предпоследней на единицу (эта операция эквивалентна прибавлению 9). Отсюда следует, что нет смысла перебирать все числа из указанного промежутка и для каждого из них решать, представляет ли оно "счастливый" номер.
Попробуйте составить программу, используя эти соображения.
118 
Задание 6
Составить программу, печатающие все номера счастливых билетов, которые равны:
а) квадрату какого-либо натурального числа;
б) кубу какого-либо натурального числа;
в) квадрату какого-либо натурального числа и одновременно кубу какого-либо другого натурального числа.
Упражнения
61. Найти наибольший общий делитель всех чисел из заданного промежутка [n; m ].
a
62. Сократить дробь. Даны натуральные числа a и b. Сократить дробь .
b
63. Найдите пять троек натуральных чисел (x; y; z), удовлетворяющих условию
x ! y !  z !
64. Б. Кордемский указывает одно интересное число 145, которое равно сумме факториалов своих цифр: 145 = 1! + 4! + 5!. Он пишет, что неизвестно, есть ли еще такие числа, удовлетворяющие названному условию. Выясните, существуют ли еще такие числа?
65. Найти трехзначное число, являющееся точным квадратом числа a, и такое, чтобы
произведение его цифр было равно a - 1.
66. Найти все натуральные решения уравнения в интервале [1; 20]
i3  j 3  k 3  z 3.
67. Найдите какие-нибудь три последовательных натуральных числа, каждое из которых делится на квадрат целого числа, большего единицы.
68. Нетрудно указать тройку квадратов целых чисел, образующих арифметическую
прогрессию: 1, 25, 49. Найдите еще три такие тройки (из квадратов чисел, не имеющих
общего делителя, т. е. взаимно простых).
69. Найти три таких простых числа, чтобы их сумма была в 5 раз меньше их произведения.
70. Попробуйте найти решения задачи Ферма x n  y n  z n на некотором промежутке
[a, b] для показателей из промежутка [1, 30].
71. Попытайтесь найти пять идущих подряд целых чисел, таких, чтобы сумма квадратов двух наибольших из них равнялась сумме квадратов трех остальных?
72. Некоторое четное число является суммой двух точных квадратов. Докажите, что
его половина является суммой двух точных квадратов.
73. 32  9; 52  25; 72  49; 92  81. Каждое из чисел 9, 25, 49, 81 при делении на 8
дает остаток 1. Что это: случайность или же этому закону подчинены квадраты всех нечетных чисел?
74. Пусть у целых чисел A и B последние k цифр одинаковы. Докажите, что у чисел
A n и B n (n - любое натуральное) также k последних цифр одинаковы (ограничиться случаями n = 2, 3, 4).
119

3. Рекурсия
Такой процесс, когда в процедуре происходит обращение к самой себе, называется
рекурсией (рекурсия - возврат). (Происходит от латинского recurreus - возвращающийся).
Теперь нам предстоит более подробно поговорить о рекурсиях.
Рекурсия - это такой способ организации подпрограммы, при котором в ходе выполнения она обращается сама к себе.
Приведем примеры, которые уже стали классическими, использования рекурсий в
подпрограммах:
Пример 10. Вычисление факториала числа.
Ниже приведена программа вычисления факториала числа, в которой используется
рекурсивная процедура fac:
Procedure fac(n : integer; var f : real);
begin
if (n = 0) or (n = 1) then f := 1
else
begin
fac(n - 1, f);
f := f*n
end
end;
Разберемся детально в работе этой процедуры. Для этого снова обратимся к математике.
Для вычисления факториала числа n, т.е. n! надо умножить последовательно n натуральных чисел от 1 до n: n !  1  2  3...n.
Так, 4! будет равно:
4 !  1  2  3  4  24.
Это прямой путь вычисления или итеративный.
Возможен и другой путь вычисления: 4 !  1  2  3  4  24. Этот путь можно назвать
возвратным или рекурсивным.
Именно на этом принципе основана работа приведенной процедуры.
Пусть введено в программу значение 4 для вычисления факториала 4! Как будет работать процедура?
После начала ее работы, будет выполнена проверка:
if (n = 0) or (n = 1) then f := 1
Понятно, что 4 не равно 0 и не равно 1, значит будет выполняться оператор после
else, т. е. fac(n - 1, f), а это означает, что снова будет вызвана также процедура, но значение n уменьшится на единицу и станет равным 3; затем снова будет выполнена проверка
условия:
if (n = 0) or (n = 1) then f := 1 и переход к вызову процедуры fac(n - 1, f).
Значение n уменьшится на 1 и станет равным 2 и т. д. до тех пор, пока n не станет
равным 1, а значение f получит значение 1 (надо заметить, что при всех предыдущих операциях значение f оставалось равным 0, а точнее говоря, неопределенным).
После этого, начнется обратный процесс, в котором будет выполняться команда: f :=
f*n. Он будет происходить так:
f := 1*4; f := 4*3; f := 12*2; f := 24*1.
120 
Образно говоря, при первоначальном процессе, значения n от 4 до 1 "запоминаются"
в стековую память "Паскаль-машины", а при следующем процессе, значения n "считываются" из стековой памяти “Паскаль-машины” и умножаются на значения f.
Условно-схематически это можно изобразить так: значения n запоминаются в стекпамять "Паскаль-машины":
4
3
2
1
4
3
2
4
3
4
а затем начинают считываться в обратном порядке, начиная с единицы.
Обязательным элементом в описании всякого рекурсивного процесса является некоторое утверждение, определяющее условие завершения рекурсии; иногда его называют
опорным условием рекурсии (или "якорем"). В нашем случае это условие:
if (n = 0) or (n = 1) then f := 1.
В опорном условии может быть задано какое-то фиксированное значение, заведомо
достигаемое в ходе рекурсивного вычисления и позволяющего организовать своевременную остановку процесса; применительно к вычислению факториала им будет равенство 1!
= 1. Таким образом, любое рекурсивное определение всегда содержит два элемента: условие завершения и способ выражения одного шага решения посредством другого, более
простого шага.
Для четкого понимания происходящих при этом процессов необходимо иметь в виду, что:
а) при каждом вызове процедуры создается новый экземпляр f;
б) все экземпляры f накапливаются во внутреннем стеке “Паскаль-машины” и
в) в любой момент обработке доступен только один, хронологически последний экземпляр переменной f, который
г) по завершению очередного рекурсивного вызова автоматически уничтожается).
Вывод
При каждом входе в рекурсивную подпрограмму ее локальные переменные размещаются в особым образом организованной области памяти, называемой программным
стеком.
Программа
Program Problem10;
uses WinCrt;
var
n : integer;
f : real;
{---------------------------------------------------------------------------------------}
Procedure fac(n : integer; var f : real);
begin
if (n=0) or (n=1) then f := 1
else
121

begin
fac(n - 1, f);
f := f*n
end
end;
{---------------------------------------------------------------------------------------}
begin
write('Введите натуральное значение n '); readln(n);
fac(n, f);
writeln('Факториал числа ', n, ' равен ', f:12:0)
end.
Турбо-Паскаль 7 или 6 дает очень удобную возможность пошаговой трассировки
программы и процедуру. Для этого достаточно последовательно нажимать клавишу F7 и
вы сможете полностью убедиться в правильности наших соображений.
Рекурсивная форма организации подпрограммы обычно выглядит изящнее итерационной (последовательной) и дает более компактный текст программы, но при выполнении, как правило, медленнее и может вызвать переполнение стека.
Как избавиться от этой неприятности вы узнаете позже. Но стоит знать, что при зацикливании программы следует выйти из нее нажатием <Ctrl>+<Z>+<Enter> (<Ввод>)
(для Турбо-Паскаля 7 или 6).
Еще примеры с использованием рекурсивных процедур.
Пример 11. Над цепью озер летела стая белых гусей. На каждом озере садилось половина гусей и еще полгуся, а остальные летели дальше. Все гуси сели на семи озерах.
Сколько гусей было в стае?
Решение
Математически задача решается устно очень остроумным способом.
Пусть вместе со стаей белых гусей все время летит еще один, Серый гусь. Если к некоторому озеру подлетит m белых гусей и Серый, то на этом озере садится
m / 2  1 / 2  (m  1) / 2 - ровно половина всех гусей вместе с серым. Поэтому после каждого озера число летящих гусей уменьшается ровно вдвое. После семи озер оно уменьшится в 27 = 128 раз, а остается летящим один Серый гусь. Значит, вначале было 128 гусей, из них 127 - белых.
А теперь выполним, образно говоря, прямые рассуждения для решения задачи.
Обозначим через xk количество летящих белых гусей, когда впереди еще k озер. Тогда условие задачи записывается так:
xk 1
x k  x k 1 
 .
2 2
Отсюда получаем для последовательности (xk) рекуррентное соотношение
x k  2  x k 1  1.
Зная его, легко составить рекурсивную процедуру:
Procedure goose(x, k : integer);
begin
if k = 1 then writeln(x) else goose(2*x + 1, k - 1)
end;
122 
В процедуру вводятся всего две переменные: x - искомое число гусей; k - число озер.
Процедура устроена с расчетом, что гуси уже пролетели все 7 озер, значит надо вводить
значение для x - один (1), а для k - семь (7). В процедуре устроено, что число k уменьшается на 1 и тогда опорным условием ("якорем") завершения процедуры является условие
равенства 1 значений k и после этого на экран надо выдать значение числа гусей:
if k = 1 then writeln(x)
Опорное условие может быть и другим, если первоначальным значением k будет 1,
тогда при повторном обращении к процедуре значение k надо не уменьшать, а увеличивать на 1 (k + 1), опорным условием, в этом случае, будет k = 7.
Ниже приводится законченная программа решения этой задачи:
Program Problem11;
uses WinCrt;
var
k : integer;
{----------------------------------------------------------------------------------------}
Procedure goose(x, k : integer);
begin
if k = 1 then write(x) else goose(2*x + 1, k - 1)
end;
{----------------------------------------------------------------------------------------}
begin
write('Введите число озер '); readln(k);
write('В стае было ');
goose(1, k);
writeln(' гусей')
end.
Придерживаясь подобных соображений, решите следующую задачу.
Задание 7
Поток студентов пять раз сдавал один и тот же зачет (не сумевшие сдать зачет приходили на следующий день). Каждый день успешно сдавала зачет треть всех пришедших
студентов и еще треть студента. Каково наименьшее возможное число студентов, так и не
сдавших зачет за пять раз?
Легко составлять рекурсивные процедуры, если задачи связаны с арифметическими
или геометрическими прогрессиями, вообще последовательностями (к ним мы вернемся
позже), заданными как формулами n-го члена, так и рекуррентными соотношениями.
Вот еще несколько простых программ с рекурсивными процедурами.
Пример 12. Мой богатый дядюшка подарил мне один доллар в мой первый день
рождения. В каждый следующий день рождения он удваивал свой подарок и прибавлял к
нему столько долларов, сколько лет мне исполнилось. Написать программу, подсчитывающую общую сумму денег, подаренных к N-му дню рождения и указывающую, к какому
дню рождения сумма подарка превысит 100$.
123

Вначале напишем программу, сколько денег получит племянник к n-му дню рождения.
Снова попробуем составить рекурсивную процедуру, хотя возможен и другой путь
решения.
Введем обозначения: k - число лет племянника, p - количество денег, которые дает
дядя на каждом дне рождения, s - общая сумма денег, полученных племянником за все годы, n - счетчик числа дней рождения, который считает в обратном порядке от n (введенного пользователем) до 1.
Процедура
Procedure uncle(k, p, s, n : longint); {uncle - дядя}
begin
if n = 1 then write(s)
else
begin
k := k + 1;
p := 2*p + k;
uncle(k, p, s + p, n - 1)
end
end;
Задаются первоначальные значения формальным параметрам процедуры:
k : 1; p : 1, s : 1, n - вводится пользователем из основной программы (вы обратили внимание, что в этой, как и в предыдущей процедуре нет выходных параметров и нет
переменных в самой процедуре, хотя возможны и другие варианты).
Увеличивается число лет: k := k + 1; вычисляется подарок к k-тому дню рождения: p
:= 2*p + k; вызывается процедура, в которой увеличивается на p общая сумма полученных
денег s и уменьшается на 1 число дней рождения:
uncle(k, p, s + p, n - 1)
Далее весь процесс повторяется, до тех пор, пока n не станет равным 1.
Программа
Program Rich_man1; { rich man - богатый }
uses WinCrt;
var
n : integer;
{---------------------------------------------------------------------------------------}
Procedure uncle(k, p, s, n : longint); {uncle - дядя}
begin
if n = 1 then write(s)
else
begin
k := k + 1;
p := 2*p + k;
uncle(k, p, s + p, n - 1)
end
end;
{---------------------------------------------------------------------------------------}
begin
write('Введите число лет племянника '); readln(n);
124 
write('Я получу к ', n, '-ому дню рождения ');
uncle(1, 1, 1, n);
writeln(' долларов')
end.
Во второй части условия требуется определить число лет, когда сумма полученных
денег будет равна или превысит 100 долларов. Для этого в процедуре меняется опорное
условие: if s >= 100 then write(n), а все остальное остается без изменений.
Program Rich_man2;
uses WinCrt;
var
n : integer;
{----------------------------------------------------------------------------------------}
Procedure uncle1(k, p, s, n : longint);
begin
if s >= 100 then write(n)
else
begin
k := k + 1;
p := 2*p + k;
uncle1(k, p, s + p, n + 1)
end
end;
{--------------------------------------------------------------------------------------}
begin
write('Сумма подарка превысит 100 долларов к ');
uncle1(1, 1, 1, 1);
writeln(' -ому дню рождения')
end.
Следующие задачи решаются аналогично и особого труда не представляют, поэтому
я предлагаю их для самостоятельной работы. Используйте рекурсивные процедуры.
Задание 8
1. Ежедневно Незнайка учит половину от суммы выученных за два предыдущих дня
иностранных слов и еще два слова. Знайка считает, что силы Незнайки иссякнут, когда
нужно будет выучить 50 слов в день. Написать программу, определяющую, через сколько
дней иссякнут силы у Незнайки, если в первые два дня он выучил по одному слову.
2. Татьяна Ларина, читая очередной французский роман, подсчитала сумму номеров
прочитанных страниц. Обозначим эту сумму Q. Написать программу, определяющую номер последней прочитанной страницы.
3. Царевна-лягушка съедает ежедневно на 20% комаров больше, чем в предыдущий
день, и еще два комара. Написать программу, определяющую через сколько дней количество съеденных комаров превысит 100, если в первый день было съедено 12 комаров.
4. На каждом следующем дне рождения Винни Пух съедает столько же пищи, что и
на двух предыдущих. На двух первых днях рождения у Пятачка и Кролика он съел по 100
г пищи. Написать программу, определяющую, сколько килограммов пищи съест Винни
Пух на пятнадцатом дне рождения.
125

5. Одноклеточная амеба каждые 3 часа делится на 2 клетки. Определить, сколько
клеток будет через 3, 6, 9, 12, ..., 24 часа.
6. Начав тренировки, спортсмен в первый день пробежал 10 км. Каждый день он
увеличивал дневную норму на 10% от нормы предыдущего дня. Какой суммарный путь
пробежит спортсмен за 7 дней?
Рассмотрим более сложную задачу, для составления программы которой используется рекурсивная процедура.
Пример 13. Перемножая большие числа, можно быстро получить переполнение. Поэтому, для того чтобы напечатать произведение, превышающее наибольшее допустимое
для данного целого типа (integer или longint) числа, надо применить искусственные средства.
Составим программу для печати произведения двух чисел, которое может превышать максимально допустимое целое число.
Решение
Процедура multiplication умножает число a на каждую цифру числа b, начиная с
цифры единиц. Последняя цифра полученного произведения, сложенная с последней цифрой имеющегося в памяти частичного произведения, печатается, а все прочие цифры запоминаются - передаются как параметры при рекурсивном обращении к процедуре
multiplication. В самом конце производится умножение на первую (левую) цифру числа b.
На этом умножение заканчивается. Тогда печатается начало результата - накопившееся
частичное произведение без последней цифры (s div 10), а после него при возвращении из
рекурсии - все остальные цифры произведения (s mod 10) в обратном порядке по сравнению с тем, как они вычислялись при входе в рекурсию.
Program Problem13; { Большое произведение }
uses WinCrt;
var
x, y : longint;
{----------------------------------------------------------------------------------------}
Procedure multiplication(a, b, s : longint);
begin
if b <> 0 then
begin
s := s+a*(b mod 10);
multiplication(a, b div 10, s div 10);
write(s mod 10:1)
end
else if s <> 0 then write(s)
end;
{----------------------------------------------------------------------------------------}
begin
write('Введите первый множитель '); readln(x);
write('Введите второй множитель '); readln(y);
write(x,'*',y:1,' = ');
if ((x < 0) and (y > 0)) or ((x > 0) and (y < 0)) then write('-');
multiplication(abs(x), abs(y), 0);
writeln
end.
126 
Задание 9
1. На какое наименьшее число нужно умножить 12345679, чтобы получить число,
состоящее из одних пятерок?
2. На какое наименьшее число нужно умножить 333667, чтобы получить число, состоящее из одних восьмерок?
Рекурсивный вызов может быть косвенным. В этом случае подпрограмма обращается к себе опосредованно, путем вызова другой подпрограммы, в которой содержится обращение к первой, например:
Procedure A(i: real);
begin
...
B(i);
...
end;
Procedure B(j: integer);
...
begin
...
A(j);
...
end;
Если строго следовать правилу, согласно которому каждый идентификатор перед
употреблением должен быть описан, то такую программную конструкцию использовать
нельзя. Для того, чтобы такого рода вызовы стали возможны, вводится опережающее
описание:
Procedure B(j: integer);
forward;
A(i: real);
Procedure
begin
...
B(i);
...
end;
Procedure B;
begin
...
A(j);
...
end;
Как видим, опережающее описание заключается в том, что объявляется лишь заголовок процедуры B, а ее тело заменяется стандартной директивой FORWARD. Теперь в
процедуре A можно использовать обращение к процедуре B - ведь она уже описана, точнее, известны ее формальные параметры и компилятор может правильным образом организовать ее вызов.
Обратите внимание: тело процедуры B начинается заголовком, в котором уже не
указываются описанные ранее формальные параметры.
127

4. Функции
Язык программирования Паскаль допускает введение в программу функции, определяемой пользователем. Она помещается в разделе описаний основной программы.
Запись функции начинается так:
Function <имя> (<список формальных параметр.>) : <тип рез.>
var
<описание переменных, участвующих в работе функции>
Дальнейшее построение такое же, как и во всех других программах на языке Паскаль.
begin
<операторы>
<имя> := <результат>
end;
Обязательной является команда присваивания имени функции результата, полученного в итоге ее работы. Функция может быть использована несколько раз в программе.
Для ее вызова достаточно указать имя функции и задать значение формальных параметров: <имя> (<значение параметров>).
Например: s(2, 3) или s(n, a). Параметры и переменные функции могут иметь те же
имена, что и переменные в основной программе.
Снова обратимся к наиболее типичным примерам, создаваемых функций. Как вы
смогли уже убедиться, их конструкция мало чем отличается от процедур, да и существует
возможность обратных преобразований функций в процедуру и процедур в функции.
Известный ряд чисел Фибоначчи имеет вид:
1, 1, 2, 3, 5, 8, 13, 21, 34, ...
Каждый член этой последовательности, начиная с третьего, равен сумме двух
предыдущих членов.
Если первый член последовательности обозначить f1, второй - f 2 , ...,
f n2 , f n1 , f n , ..., тогда можно составить такую зависимость:
f1  1, f 2  1, f n  f n1  f n2 .
Пользуясь такой зависимостью, можно получить все члены последовательности чисел Фибоначчи.
Формулу, выражающую любой член последовательности, начиная с некоторого, через предыдущие (один или несколько), называют рекуррентной (от латинского слова
recurro - возвращаться).
Зная зависимость между последующим и предыдущими членами, легко создать рекурсивную функцию, позволяющую найти n-е число ряда Фибоначчи:
Function fib(n : integer) : longint;
begin
if (n = 1) or (n = 2) then fib := 1
else fib := fib(n - 1) + fib(n - 2)
end;
Здесь, мы одновременно проследим и построение функции и рекурсии.
В заголовке указывается зарезервированное слово Function, далее пишется по фантазии пользователя ее имя, удовлетворяющее всем требованиям, предъявляемым к идентификаторам.
128 
В скобках описываются, как и в процедурах, входные параметры, заметьте, в функции есть только входные параметры, в качестве выходного значения используется сама
функция, поэтому обязательно указывается ее тип.
И вот теперь ее имя fib может быть использовано в программе, наряду со встроенными функциями, в различных операторах и арифметических вычислениях.
Построение самой функции начинается, как и построение любой другой программы,
но обязательно надо присваивать конечное значение самой функции: fib.
Function fib(n : integer) : longint;
var
f, f1, f2, i : integer;
begin
f1 := 1; f := 0;
for i := 1 to n do
begin
f2 := f1; f1 := f;
f := f1 + f2;
end;
fib := f
end;
Конечно, удобно составлять программу, когда все члены ряда вычисляются по одному правилу, но в ряде Фибоначчи выпадают из общего правила два первых члена. Если
мы хотим вычислить и их по тому же правилу, тогда следует в функции fib искусственно
продолжить ряд влево, пополнив его двумя фиктивными членами: f(-1) = 1 и f(0) = 0. Тогда ряд примет следующий вид:
10
1 1 2 3 5 ...
- фиктивные члены ряда
- подлинные члены ряда.
При наличии этих двух фиктивных членов все подлинные члены ряда вычисляются
по тем же правилам.
Работу этой функции понять несложно, поэтому мы не будем останавливаться на детальном разборе ее работы.
Можно составить функцию для вычисления чисел Фибоначчи используя рекурсию,
тогда она будет выглядеть более компактной:
Function fib(n : integer) : integer;
begin
if (n = 1) or (n = 2) then fib := 1
else fib := fib(n - 1) + fib(n - 2)
end;
Однако, несмотря на внешнюю изысканность, эта функция крайне неэффективна.
Давайте детально проследим за ходом ее работы.
Когда n = 1 или n = 2, получаем значение функции, выполнив функцию один (первый) раз.
Когда n = 3, выполняется вторая (else) ветвь условного оператора и значение функции находится из выражения fib(2) + fib(1).
Для того, чтобы вычислить значение выражения, следует еще два раза (рекурсивно)
обратиться к функции fib.
Когда n = 4, функция будет выполняться пять раз, а когда n = 5 - девять раз.
129

fib(4)
fib(3)
fib(2)
fib(5)
fib(2)
fib(1)
fib(2)
fib(4)
fib(3)
fib(2)
fib(3)
fib(2)
fib(1)
fib(1)
Таким образом, при возрастании значения параметра функции очень быстро возрастает и число обращений к функции, а тем самым увеличивается время вычисления. Это
происходит от того, что вторая рекурсивная ветвь условного оператора содержит сразу
два рекурсивных вызова. Поэтому эта рекурсивная функция служит примером очень часто
встречаемых неэффективных рекурсивных функций.
Часто, внешняя любезность рекурсии оборачивается большими неприятностями.
Приведем и другой способ вычисления членов ряда Фибоначчи с помощью с помощью функции, построенной итеративно. Для ее построения возможны два способа.
Пример 1
Первый способ
Function Fib(n: integer):longint;
var
f1, f2, f : longint;
i
: integer;
begin
f2 := 1; f := 1;
if (n = 1) or (n = 2) then f := 1
else
for i := 3 to n do
begin
f1 := f2; f2 := f
f := f1 + f2;
end;
fib := f
end;
Второй способ
Function fib(n : integer) : integer;
var
f, f1, f2, i : integer;
begin
f1 := 1; f := 0;
for i := 1 to n do
begin
f2 := f1; f1 := f;
f := f1+f2;
end;
fib := f
end;
130 
Полностью программа:
Program Problem1;
uses WinCrt;
var
i, n : integer;
{----------------------------------------------------------------------------------------}
Function fib(n : integer) : integer;
var
f, f1, f2, i : integer;
begin
f1 := 1; f := 0;
for i := 1 to n do
begin
f2 := f1; f1 := f;
f := f1 + f2;
end;
fib := f
end;
{----------------------------------------------------------------------------------------}
begin
write('Введите значение n '); readln(n);
writeln('Числа Фибоначчи');
for i := 1 to n do write(fib(i), ' ');
writeln
end.
Пример 2.
Последовательность (an) задается так: a1  7, an1 - сумма цифр квадрата числа an
плюс 1. Постройте эту последовательность и найдите a1000 .
Решение
При построение членов последовательности нам придется находить сумму цифр
числа. Поэтому есть смысл составить функцию, которая определяет сумму цифр числа.
Эта функция может быть построена так:
Function Sum(a : integer) : integer;
var
s : integer;
begin
s := 0;
repeat
s := s + a mod 10;
a := a div 10
until a = 0;
Sum := s
end;
131

Вторая функция - это функция, с помощью которой можно получить любой член последовательности:
Function Succ(n : integer) : integer;
var
a, i : integer;
begin
a := 7;
for i := 2 to n do a := Sum(a*a) + 1;
Succ := a
end;
Полностью программа может быть построена так:
Program Succession; { succession - последовательность }
uses WinCrt;
var
a, i, n : integer;
{----------------------------------------------------------------------------------------}
Function Sum(a: integer): integer;
var
s: integer;
begin
s:=0;
repeat
s := s + a mod 10;
a := a div 10
until a = 0;
Sum := s
end;
{----------------------------------------------------------------------------------------}
Function Succ(n : integer): integer;
var
a, i : integer;
begin
a := 7;
for i := 2 to n do a := Sum(a*a) + 1;
Succ := a
end;
{----------------------------------------------------------------------------------------}
begin
write('Введите число членов последовательности ');
readln(n);
for i := 1 to n do write(Succ(i), ' ');
writeln
end.
132 
Задание 1
1. Последовательность (an) задается так: a1 - некоторое натуральное число, an1 сумма квадратов цифр числа an , n  1.
а). Постройте эту последовательность. Будет ли она периодична?
б). Докажите, что в этой последовательности обязательно встретится одно из чисел 1
или 89 и указать номер места, на котором оно находится.
Применение ряда Фибоначчи
Пример 2. Определение минимума функции с помощью ряда Фибоначчи.
Ряд Фибоначчи много интересных применений в математике. О некоторых из них
мы поговорим позже, а на этом занятии разберем использование этого ряда для поиска
минимума функции на заданном промежутке (смотри также В.Ф. Очков, Ю.В. Пухначев,
"128 советов начинающему программисту", Москва, 1991 г.).
Для примера рассмотрим функцию y  x 4  14x 3  60x 2  70x на промежутке (0, 2).
График этой функции, а точнее, его часть на промежутка (0, 2) показан на рисунке 23.
Рис. 23
Итак, стоит задача найти минимум функции на этом промежутке, т.е. значение x,
при котором получается минимум и значение функции y в этой точке. Первая мысль, которая возникает - это делить отрезок (0, 2) пополам, затем выяснять, на каком из получившихся частей может находится минимум и делить эту часть пополам и так далее. Такой процесс возможен, но имеет два существенных недостатка.
Во-первых, "приближение" к точке минимума будет очень медленным, придется испробовать много вариантов, чтобы "подобраться" к искомой точке.
Во-вторых, при даже очень большом количестве делений точность приближения будет невелика.
Поэтому, возникает необходимость как-то иначе делить отрезок (если мы избрали
метод деления отрезка). Но как? Отделять от одного конца 4-ю или 3-ю части и постепенно сужать отрезок к лучшему результату не приведет, пожалуй еще и к худшему.
Улучшить процесс деления отрезка помогает ряд Фибоначчи. Может даже возникнуть впечатление, что он как будто специально создан для этой цели. Хотя ряд возник совершенно из других более естественных соображений, он показывает число появления
кроликов во 2-й, 3-й, 4-й и т. д. годы, если первоначально есть только одна самка и один
самец. Но многие закономерности природы прекрасно описываются математическими
средствами, вот и в нашем примере ряд Фибоначчи дает очень хорошие результаты.
Для деления отрезка можно задать число делений - n, а затем в зависимости от n
определить коэффициент деления, как отношение (n - 1)-го и n-го членов ряда. Если a -
133

левый конец промежутка, b - правый, тогда разделить отрезок можно так: x2 := a + (b a)*fib(n - 1)/fib(n); y2 := f(x2);
Для n = 10 отношение fib(9)/fib(10) = 34/55 = 0.6181818... . Тогда, правая граница
станет равна: x2 := 1.236364... . Для дальнейшего процесса поиска, надо "приблизить" левый конец промежутка на такое же расстояние к правому концу ( x1:  a  b  x 2 ), затем
найти соответствующее значения функции (y1 := f(x1) и определить, который из промежутков брать для дальнейшего рассмотрения.
В дальнейшем могут возникнуть несколько случаев.
Если x2 > x1 и y2 > y1, тогда в качестве правого конца промежутка принять x2 и зафиксировать его (b := x2), а x2 заменить на x1 (x2 := x1), y2 присвоить значение y1
(y2:=y1) и повторить процесс приближения левого конца к правому:
x1 := a + b - x2.
Если x2 <= x1 и y2 > y1, тогда a := x2; x2 := x1; y2 := y1 и повторить:
x1 := a + b - x2.
Если x2 > x1 и y2 < y1, тогда a := x1 и выполнить: x1 := a + b - x2.
Если x2 <= x1 и y2 <= y1, тогда b := x1 и выполнить: x1 := a + b - x2.
Если ни одно из этих условий не выполняется, тогда выполнятся оператор:
x1 := a + b - x2
и весь процесс повторяется.
Для составления программы потребуется функция, вычисляющая члены ряда Фибоначчи, уже знакомая нам:
{ Функция вычисления членов ряда Фибоначчи }
Function fib(n : integer) : real;
var
f, f1, f2 : real;
i : integer;
begin
f1 := 1; f := 0;
for i := 1 to n do
begin
f2 := f1; f1 := f;
f := f1 + f2
end;
fib := f
end;
Нужно будет вычислять значения заданной функции и для этого составим следующую функцию:
{ Заданная исследуемая функция }
Function func(x : real) : real;
begin
func := x*x*x*x - 14*x*x*x + 60*x*x - 70*x
end;
Полностью программа приводится ниже:
Program Minimumfib;
uses WinCrt;
label 1;
var
a, aa, bb, x, b, x1, x2, y1, y2 : real; i, n : integer;
{----------------------------------------------------------------------------------------}
{ Заданная исследуемая функция }
Function func(x : real) : real;
134 
begin
func := x*x*x*x - 14*x*x*x + 60*x*x - 70*x
end;
{----------------------------------------------------------------------------------------}
{ Функция вычисления членов ряда Фибоначчи }
Function fib(n : integer) : real;
var
f, f1, f2 : real; i: integer;
begin
f1 := 1; f := 0;
for i := 1 to n do
begin
f2 := f1;
f1 := f;
f := f1 + f2
end;
fib := f
end;
{----------------------------------------------------------------------------------------}
{ Основная программа }
begin
write('Введите нижнюю границу промежутка '); readln(a);
aa := a;
write('Введите правую границу промежутка '); readln(b);
bb := b;
write('Введите число приближений к минимуму '); readln(n);
x2 := a + (b - a)*fib(n-1)/fib(n); y2 := func(x2);
for i := 1 to n do
begin
x1 := a + b - x2; y1 := func(x1);
if (x2 > x1) and (y2 > y1)
then
begin
b := x2; x2 := x1; y2 := y1; goto 1
end;
if (x2 <= x1) and (y2 > y1)
then
begin
a := x2; x2 := x1; y2 := y1; goto 1
end;
if (x2 > x1) and (y2 < y1)
then
begin
a := x1; goto 1
end;
if (x2 <= x1) and (y2 <= y1)
then
begin
b := x1; goto 1
end;
1: end;
x := (a + b)/2;
135

write('Мин. значение функции на (');
writeln(aa:1:0, ',', bb:2:0, ')');
writeln('Значение функции равно ', func(x):6:12);
writeln('При значении аргумента ', x:6:12)
end.
В этой программе число приближений устанавливается пользователем. Программу
можно изменить, указав в условии цикла точность приближения значений аргумента x. Но
тогда придется каждый раз при повторении цикла изменять коэффициент деления, так неизвестно конечное число повторений цикла. Для этого можно добавить в программу процедуру вычисления границ промежутка:
{ Процедура вычисления знач. аргумента и функции }
{ approach - приближение }
Procedure approach(a, b : real; n : integer; var x2, y2 : real);
begin
x2 := a + (b - a)*fib(n - 1)/fib(n);
y2 := func(x2)
end;
И тогда, программа станет следующей:
{Поиск минимума функции методом Фибоначчи}
Program Minimumfib;
uses WinCrt;
label 1;
var
a, aa, bb, x, b, x1, x2, y1, y2, e : real;
n
: integer;
{----------------------------------------------------------------------------------------}
{ Заданная исследуемая функция }
Function func(x : real) : real;
begin
func := x*x*x*x - 14*x*x*x + 60*x*x - 70*x
end;
{----------------------------------------------------------------------------------------}
{ Функция вычисления членов ряда Фибоначчи
}
Function fib(n : integer) : real;
var
f, f1, f2 : real;
i
: integer;
begin
f1 := 1; f := 0;
for i := 1 to n do
begin
f2 := f1;
f1 := f;
f := f1+f2
end;
fib := f
end;
{----------------------------------------------------------------------------------------}
136 
{ Процедура вычисления знач. аргумента и функции }
{ approach - приближение }
Procedure approach(a, b : real; n : integer;
var x2, y2 : real);
begin
x2 := a + (b - a)*fib(n-1)/fib(n);
y2 := func(x2)
end;
{----------------------------------------------------------------------------------------}
{ Основная программа }
begin
write('Введите нижнюю границу промежутка '); readln(a);
aa := a;
write('Введите правую границу промежутка '); readln(b);
bb := b;
write('Введите точность приближения '); readln(e); n := 3;
approach(a, b, n, x2, y2);
while abs(b - a) > e do
begin
x1 := a + b - x2; y1 := func(x1);
if (x2 > x1) and (y2 > y1)
then
begin
n := n + 1;
approach(a, b, n, x2, y2);
b := x2; x2 := x1; y2 := y1; goto 1
end;
if (x2 <= x1) and (y2 > y1)
then
begin
n := n + 1;
approach(a, b, n, x2, y2);
a := x2; x2 := x1; y2 := y1; goto 1
end;
if (x2 > x1) and (y2 < y1)
then
begin
n := n + 1;
approach(a, b, n, x2, y2);
a := x1; goto 1
end;
if (x2 <= x1) and (y2 <= y1)
then
begin
n := n + 1;
approach(a, b, n, x2, y2);
b := x1; goto 1
end;
n := n + 1;
approach(a, b, n, x2, y2);
1: end;
x := (a + b)/2;
137

write('Мин. значение функции на промежутке (');
writeln(aa:1:0,',',bb:2:0,')');
writeln('Значение функции равно ', func(x):6:12);
writeln('При значении аргумента ', x:6:12)
end.
Очень часто, при поиске минимума функции для деления отрезка используют так
называемое "Золотое сечение".
"Золотое сечение" или "золотое сечение" - деление отрезка на две части так, что
большая из них есть средняя пропорциональная между меньшей частью и всем отрезком.
Если a - весь отрезок, x - большая из двух частей, тогда:
a : x = x : (a - x)
Решая это уравнение, получаем: x 2  ax  a2  0, получим:
x

  0.618
a 5 1
(с точностью до 0.001).
2
Зная это, можно составить программу поиска минимума функции, используя "золотое сечение", тогда:
x1 := 0.618*a + 0.382*b, x2 := 0.382*a + 0.618*b.
Для вычисления этих значений можно составить две процедуры, которые затем использовать в программе.
Procedure gold1(a, b : real; var x1, y1 : real);
begin
x1 := 0.618*a + 0.382*b; y1 := fx(x1)
end;
{------------------------------------------------------}
Procedure gold2(a, b : real; var x2, y2 : real);
begin
x2 := 0.382*a + 0.618*b; y2 := fx(x2)
end;
Задание 2
Составить программу поиска минимума функции, используя "золотое сечение". Для
организации цикла используйте условие проверки приближения аргумента с заданной
точностью, по аналогии со второй программой. применяющей ряд Фибоначчи.
Пример 4. От прямоугольника отрезают квадраты, стороны которых равны по длине
его меньшей стороне, до тех пор, пока это возможно, и т. д.
Задание состоит в том, чтобы для произвольного натурального n, найти какиенибудь два числа a и b, чтобы при таком разрезании прямоугольника a . b получились n
квадратов разных размеров.
Общее решение
Для произвольного натурального числа n можно найти такие числа a и b, чтобы при
разрезании получилось ровно n разных размеров квадратов.
В качестве таких чисел можно взять числа f2 и f1 последовательности Фибоначчи.
138 
Если положить a = f(n + 2) и b = f(n + 1), то каждый раз от прямоугольника
f (k )  f (k  1) будет отрезаться только один квадрат со стороной длины f(k - 1) и оставаться прямоугольник f ( k )  f ( k  2) .
Если взять в этой задаче f7 = 13 и f8 = 21; размеры квадратов получатся равными
первым шести различным числам Фибоначчи: 1, 2, 3, 5, 8, 13.
Построенный пример прямоугольника a  b имеет наименьшее возможное (при делении на n) размеры; другими словами, если числа a и b не больше f(n + 2), то алгоритм Евклида дает НОД(a, b) не больше, чем за n шагов.
Program Problem4; { Разрезание прямоугольников на квадраты }
uses WinCrt;
var
a, b, n, i : longint;
{----------------------------------------------------------------------------------------}
Function fib(n : longint) : longint;
var
f, f1, f2, i : longint;
begin
f1 := 1; f := 0;
for i:=1 to n do
begin
f2 := f1; f1 := f;
f := f1+f2
end;
fib := f
end;
{---------------------------------------------------------------------------------------}
begin
write('Введите натуральное число n '); readln(n);
a := fib(n + 2); b := fib(n + 1);
writeln('Прямоугольник, со сторонами ', a, ' и ', b);
writeln('Можно разделить на ',n,' квадратов со сторонами');
for i := n+1 downto 2 do write(fib(i), ' ');
writeln
end.
5. Задачи с применением НОД
Пример 5. Один мастер делает на длинной ленте пометки синим карандашом от ее
начала через каждые 36 см. Другой мастер делает пометки красным карандашом от начала
через каждые 25 см. Может ли синяя пометка оказаться на расстоянии 1 см от какойнибудь красной?
Решение
Ответ: может. Например, 9-я синяя пометка и 13-я красная находятся друг от друга
на расстоянии 1 см, так как 13  25 - 9  36 = 1.
В этой задаче нам фактически надо было найти какое-нибудь решение в целых числах одного из уравнений 25x - 36y = 1, 25x - 36y = - 1
или доказать, что таких решений нет. Существует стандартная процедура, с помощью которой всегда можно найти решение уравнения ax  by  1, если НОД (a, b)  1.
139

Продемонстрируем ее на нашей задаче. Выпишем все шаги алгоритма Евклида для
нахождения НОД(36; 25):
36 = 25  1 + 11; 25 = 11  2 + 3; 11 = 3  3 + 2; 3 = 2  1 + 1.
Перепишем эту цепочку равенств по остаткам:
11 = 36 - 25  1; 3 = 25 - 11  2; 2 = 11 - 3  3; 1 = 3 - 2  1.
Тогда получим:
1 = 3 - (11 - 3  3) = 3  4 - 11 = (25-11  2)  4 - 11 = 25  4 - 11  9 =
= 25  4 - 11  9 = 25  4 - (36 - 25)  9 = 25  13 - 36  9.
В результате получается равенство 25  13 - 36  9 = 1, дающее одно решение уравнения 25x - 36y = 1.
Определение. Неопределенные уравнения - уравнения, содержащие более одного
неизвестного.
Под одним решением неопределенного уравнения понимается совокупность значений неизвестных, которая обращает данное уравнение в верное равенство.
Уравнения вида ax + by = c, где a, b, c - целые числа, отличные от нуля
Теорема 1. Если НОД (a; b) = d, то существуют такие целые числа x и y, что
имеет место равенство a  x  b  y  d .
(Это равенство называется линейной комбинацией или линейным представлением
наибольшего общего делителя двух чисел через сами эти числа.)
Теорема 2. Если в уравнении ax + by = l (a, b) = 1, то уравнение имеет по крайней
мере одно целое решение.
Справедливость этой теоремы следует из теоремы 1. Таким образом, чтобы найти
одно целое решение уравнения ах + by = 1, если (а, b) = 1, достаточно представить число 1
в виде линейной комбинации чисел а и b.
Пример. Найти целое решение уравнения 15x + 37y = 1.
Решение
1) Применим алгоритм Евклида и найдем НОД(15, 37):
НОД(15, 37) = 1
2) Выразим 1 последовательно через неполные частные и остатки, используя полученные равенства, начиная с конца:
1  15  7  2  15  (37  15  2)  2  15  37  2  15  4  15  5  37  (2) , т. е.
x0 = 5, y0 = -2.
Теорема 3. Если в уравнении ах + by = с (а, b) = d > 1 и с не делится на d, то
уравнение целых решений не имеет.
Пример. Найти целое решение уравнения 16x - 34y = 7.
Решение
(16, 34) = 2, 7 не делится на 2, уравнение целых решений не имеет.
140 
Теорема 4. Если в уравнении ах + by = с (a, b) = d > 1 и c делится на d, то оно
равносильно уравнению а1х + b1у = c1, в котором (a1, b1) = 1.
Теорема 5. Если в уравнении ах + by = с (а, b) = 1, то все целые решения этого
уравнения заключены в формулах:
x  x 0  c  bt ,
y  y 0  c  at ,
где x0, y0 - целое решение уравнения ах + by = 1, t - любое целое число.
Приведенные теоремы позволяют установить следующее правило решения в
целых числах уравнения ах + by = с, где (а, b) = 1:
1) находится целое решение уравнения ах + by = 1 путем представления 1 как линейной комбинации чисел а и b (существуют и другие способы отыскания целых решений
этого уравнения, например при использовании цепных дробей);
2) составляется общая формула целых решений данного уравнения:
x  x 0  c  bt ,
y  y 0  c  at ,
где x0, y0 - целое решение уравнения ах + by = 1, t—любое целое число.
Придавая t определенные целые значения, можно получить частные решения данного уравнения: наименьшие по абсолютной величине, наименьшие положительные (если
можно) и т. д.
Пример 1. Найти целые решения уравнения 407х - 2816у = 33.
Решение
1) Упрощаем данное уравнение, приводя его к виду 37х - 256у = 3.
2) Решаем уравнение 37x - 256y = 1.
1  34  3  11  34  (37  34  1)  11  34  12  37  11  (256  37  6)  12  37  11 
 256 12  37  83  37  ( 83 )  256  ( 12 ) . x0  83, y 0  12 .
3) Найдем решения данного уравнения по формулам:
x  x 0  c  bt ,
x  83  3  256t , x  249  256t ,
y  y 0  c  at ,
y  12  3  37t , y  36  37t , t  Z .
x  249  256t ,
Ответ:
y  36  37t , t  Z .
Для составления программы решения неопределенных уравнений, нам предстоит
решить три задачи:
1) нахождение НОД, для последующего выяснения числа решений уравнения, - это
легко сделать с помощью известной процедуры;
2) нахождение одного решения уравнения вида ах + by = 1 и
3) последующий вывод обобщенных результатов решения с учётом знаков a и b, и с
x  x 0  c  bt ,
учетом формулы
где t - произвольное целое число.
y  y 0  c  at ,
141

Первую задачу можно решить с помощью рекурсивной функции:
Function nod(a, b : integer) : integer;
begin
if b = 0 then nod := abs(a)
else nod := nod(abs(b), abs(a) mod abs(b))
end;
Для решения второй задачи применять методику нахождения остатков от деления, а
затем выполнять процесс в обратном порядке для компьютера нерационально. Проще составить два цикла с параметром, перебирающие числа от наименьшего (который равен
наибольшему по модулю, но берётся с противоположным знаком) до наибольшего из коэффициентов (почему, будут существовать решения уравнения, меньшие или равные его
коэффициентов? Докажите сами).
if abs(a) > abs(b) then max := abs(a) else max := abs(b);
for x := -max to max do
for y := -max to max do
Для вывода результатов следует рассмотреть несколько случаев, в зависимости от
знаков коэффициентов a и b, а также, чтобы не получать несколько ответов, включить
оператор безусловного перехода, после завершения проверки каждого условия.
Procedure The_equation(a, b : integer); {Решение уравнения ax + by = 1}
label 1;
var
max, x, y, n : integer;
begin
if (nod(a, b) <> 1) then writeln('Уравнение не имеет решений');
if abs(a) > abs(b) then max := abs(a) else max := abs(b);
for x := -max to max do
for y := -max to x do
begin
if (a*x + b*y = 1) and (a > 0) and (b > 0)
then begin writeln('Решения уравнения x = ', x, '+', b,'*t, y = ', y, '-', a, '*t,');
writeln('где t - произвольное целое число'); goto 1 end;
if (a*x + b*y = 1) and (a < 0) and (b > 0)
then begin writeln('Решения уравнения x = ', x, '+', b,'*t, y = ', y, ' ', a, '*t,');
writeln('где t - произвольное целое число'); goto 1 end;
if (a*x + b*y = 1) and (a > 0) and (b < 0)
then begin writeln('Решения уравнения x = ', x, ' ', b,'*t, y = ', y, '-', a, '*t,');
writeln('где t - произвольное целое число'); goto 1 end;
if (a*x + b*y = 1) and (a < 0) and (b < 0)
then begin writeln('Решения уравнения x = ', x, ' ', b,'*t, y = ', y, ' ', a, '*t,');
writeln('где t - произвольное целое число'); goto 1 end
end;
1: end;
Полностью программа решения уравнений вида ах + by = 1 будет такой:
Program Problem5;
uses WinCrt;
var
a, b : integer;
142 
{---------------------------------------------------------------------------------------------------------}
Function nod(a, b : integer) : integer;
begin
if b = 0 then nod := abs(a)
else nod := nod(abs(b), abs(a) mod abs(b))
end;
{----------------------------------------------------------------------------------------------------------}
Procedure The_equation(a, b : integer); {Решение уравнения ax + by = 1}
label 1;
var
max, x, y, n : integer;
begin
if (nod(a, b) <> 1) then writeln('Уравнение не имеет решений');
if abs(a) > abs(b) then max := abs(a) else max := abs(b);
for x := -max to max do
for y := -max to x do
begin
if (a*x + b*y = 1) and (a > 0) and (b > 0)
then begin writeln('Решения уравнения x = ', x, '+', b,'*t, y = ', y, '-', a, '*t,');
writeln('где t - произвольное целое число'); goto 1 end;
if (a*x + b*y = 1) and (a < 0) and (b > 0)
then begin writeln('Решения уравнения x = ', x, '+', b,'*t, y = ', y, ' ', a, '*t,');
writeln('где t - произвольное целое число'); goto 1 end;
if (a*x + b*y = 1) and (a > 0) and (b < 0)
then begin writeln('Решения уравнения x = ', x, ' ', b,'*t, y = ', y, '-', a, '*t,');
writeln('где t - произвольное целое число'); goto 1 end;
if (a*x + b*y = 1) and (a < 0) and (b < 0)
then begin writeln('Решения уравнения x = ', x, ' ', b,'*t, y = ', y, ' ', a, '*t,');
writeln('где t - произвольное целое число'); goto 1 end
end;
1: end;
{-----------------------------------------------------------------------------------------------------------}
begin
write('Введите значение коэффициента при x, a '); readln(a);
write('Введите значение коэффициента при y, b '); readln(b);
The_equation(a, b);
end.
Задание 4
1. Наберите программу и выполните ее. Проверьте работу программы для решения
уравнений: 27x - 40y = 1; 54x + 37y = 1; 107x + 84 y = 1; 37x - 256y = 1/
Изменить программу решения уравнения ax + by = 1, для решения неопределенных
уравнений вида ax + by = c. Проверьте работу программы для решения уравнений: 13x 15y = 7; 81x + 52y = 5; 24x - 56y = 72; 42x + 34y = 5; 253x - 449y = 3.
2. Используя метод решения неопределенных уравнений, решить следующую задачу.
Было написано трехзначное число, затем из его цифр были составлены всевозможные двузначные числа (с неповторяющимися цифрами) и найдена их сумма. Оказалось,
что она вдвое больше исходного трехзначного числа. Какое же было трехзначное число?
143

6. Решение уравнений с одной переменной методом половинного деления
Здесь мы очень кратко рассмотрим один из простых методов решения нелинейных
уравнений - метод половинного деления, так как другие методы будут рассмотрены позже,
после изучения последовательностей, массивов и множеств.
Главная цель этого небольшого раздела - показать использование функций, создаваемых пользователем в программах.
Отделение корней
Первый этап численного решения уравнения f(x) = 0 состоит в отделении корней,
т.е. в установлении "тесных" промежутков, содержащих только один корень.
При отделении корней на некотором промежутке [a, b], мы потребуем, чтобы функция f(x) была непрерывна на этом промежутке и будем считать, что все интересующие нас
корни находятся на промежутке [a, b], в котором f(a)*f(b) < 0.
Будем вычислять значения функции f(x), начиная с точки x = a, двигаясь вправо с
некоторым шагом h. Как только обнаружится пара соседних значений f(x), имеющих разные знаки, и функция f(x) монотонна на этом отрезке, тогда значения аргумента x (предыдущее и последующее) можно считать концами отрезка, содержащего корень. Результатом решения этой задачи будет вывод значений концов промежутка.
Очевидно, что надежность рассмотренного подхода к отделению корней зависит как
от характера функции f(x), так и от выбранной величины шага h. Действительно, если при
достаточно малом значении h на концах текущего отрезка [x ; x  h] функция f(x) принимает значение одного знака, естественно ожидать, что уравнение f(x) = 0 корней на этом
отрезке не имеет. Однако, это не всегда так: при несоблюдении условия монотонности
функции f(x) на отрезке [x ; x  h] могут оказаться корни уравнения. Не один, а несколько
корней могут оказаться на отрезке [x ; x  h] и при соблюдении условия
f ( x )  f ( x  h)  0. Смотрите рисунки 24 и 25, иллюстрирующие эти случаи.
Рис. 24
Рис. 25
144 
Предвидя подобные ситуации, следует выбирать при отделении корней достаточно
малые значения h.
Давайте посмотрим как будет выглядеть программа отделения корней для функции
f (x )  cos x  01
. x на промежутке [-10; 10].
Ясно, что необходимо завести функцию, которая бы при необходимости обращения
к ней вычисляла ее значения. Эту функцию мы устроим уже известным нам способом и
назовем fx:
Function fx(x : real) : real;
begin
fx := cos(x) - 0.1*x
end;
В основной программе, естественно потребовать от пользователя ввода границ промежутка и шага. В качестве границ промежутка будут переменные a и b, а для шага - h (в
качестве значения шага, при выполнении программы возьмем 0.1).
Для подсчета числа промежутков будет служить счетчик k. Первоначальное значение левой границы: x1:=a; а первая правая граница будет равна сумме левой границы и
шага: x2:=x1+h; значение функции в левой границе первого промежутка: y1:=fx(x1).
Последовательно к левой границе добавляется шаг h и так должно продолжаться пока это значение не станет равно правой границе данного промежутка b. Значит, необходимо организовать цикл "пока": while x2 <= b do
В цикле, вычислять значение функции в точке x2, которая уже получилась от увеличения x1 на h: y2 := fx(x2).
Теперь следует проверить знак произведения значений функций на концах промежутка (fx(x1)*fx(x2)) и, если оно отрицательно, то на этом промежутке будет существовать корень, а значит надо выдать на экран координаты этого промежутка и его номер:
if y1*y2 < 0 then
begin
k := k + 1;
writeln(k,'-й корень на [',x1:6:4,'; ',x2:6:4,']')
end;
Далее следует продолжить движение к правой границе, а для этого выполнить следующие операторы:
x1 := x2; x2 := x1 + h; y1 := y2
Вот и вся несложная тактика этой программы. Полностью она приводится ниже:
Program Separation_root; { Программа отделения корней }
uses WinCrt;
var
a, b, h, x1, x2, y1, y2 : real;
k : integer;
{----------------------------------------------------------------------------------------}
Function fx(x : real) : real;
begin
fx := cos(x) - 0.1*x
end;
{----------------------------------------------------------------------------------------}
begin
145

write('Введите левую границу промежутка '); readln(a);
write('Введите правую границу промежутка '); readln(b);
write('Введите шаг '); readln(h);
k := 0;
x1 := a; x2 := x1 + h;
y1 := fx(x1);
while x2 <= b do
begin
y2 := fx(x2);
if y1*y2 < 0
then
begin
k := k+1;
writeln(k, '-й корень на [', x1:6:4, ';', x2:6:4, ']')
end;
x1 := x2; x2 := x1 + h;
y1 := y2
end
end.
Следующим, естественным этапом решения, является нахождение на промежутке
корень с заданной степенью точности (если, конечно, уже известно, что он существует на
нем).
Для этого нетрудно сочинить простую программу вычисления корня методом половинного деления, сущность которого заключается в следующем.
Известно, что на промежутке [a; b] есть корень. Зададим необходимую точность, с
которой нам необходимо его вычислить. Обозначим ее - e.
Разделим промежуток [a; b] пополам. Точкой деления будет точка (см. рис. 25)
c  (a  b) / 2:
Рис. 25
Установим, на котором из полученных двух промежутков находится корень. Для чего найдем знак разности fx(a)*fx(c). Если этот знак отрицательный, тогда корень находится на левом промежутке. Заменив c на b (b:=c), мы получим новый промежуток, обозначенный прежними буквами (см. рис. 26):
Рис. 26
А если разность fx(a)*fx(c) не будет отрицательной, тогда корень находится на правом промежутке. Заменив c на a (a := c), мы получим новый промежуток для поиска корня, обозначенный теми же буквами (см. рис. 27):
Рис. 27
146 
И такой процесс деления надо выполнять, пока разность между правой и левой границами по абсолютной величине будет больше заданной точности e
( (while abs(b  a)  e do).
Пользуясь этими соображениями, нетрудно составить программу, где сам процесс
половинного деления будет выполняться с помощью процедуры. В качестве функции берется функция: f(x) := sin(2*x) - ln(x) и рассматривается на промежутке [13
, ; 15
, ].
После завершения основного цикла, находится окончательное значение x,
x :  (a  b) / 2 и вычисляется погрешность d, d:  abs(b  a).
Program Division;
uses WinCrt;
var
a, b, c, e, x, d : real;
{----------------------------------------------------------------------------------------}
Function func(x : real) : real;
begin
func := sin(2*x) - ln(x)
end;
{----------------------------------------------------------------------------------------}
Procedure half(a, b, e : real; var x, d : real);
var
c : real;
begin
while abs(b - a) > e do
begin
c := (a + b)/2;
if func(a)*func(c) < 0 then b := c else a := c
end;
x := (a + b)/2;
d := abs(b - a)/2
end;
{----------------------------------------------------------------------------------------}
begin
write('Введите левую границу промежутка '); readln(a);
write('Введите правую границу промежутка '); readln(b);
write('Введите точность вычисления корня '); readln(e);
half(a, b, e, x, d);
writeln('Значение корня равно x = ', x:6:10);
writeln('С границей погрешности ', d:2:10)
end.
Можно объединить программы отделения корня и уточнения его методом половинного деления в одну и получить программу, которая отделяет промежутки и сразу вычисляет на каждом из них корни с заданной точностью.
Программа
Program Equation;
uses WinCrt;
var
a, b, h, x1, x2, y1, y2, e, x, d : real;
k
: integer;
147

{----------------------------------------------------------------------------------------}
Function fx(x : real) : real;
begin
fx := cos(x) - 0.1*x
end;
{----------------------------------------------------------------------------------------}
Procedure half(a, b, e : real; var x, d : real);
var
c : real;
begin
while abs(b - a) > e do
begin
c := (a + b)/2;
if fx(a)*fx(c) < 0 then b := c else a := c
end;
x := (a + b)/2;
d := abs(b - a)/2
end;
{----------------------------------------------------------------------------------------}
begin
write('Введите левую границу промежутка '); readln(a);
write('Введите правую границу промежутка '); readln(b);
write('Введите шаг '); readln(h);
write('Введите точность вычисления корня '); readln(e);
k := 0; x1 := a; x2 := x1 + h;
y1 := fx(x1);
while x2 <= b do
begin
y2 := fx(x2);
if y1*y2 < 0
then
begin
k := k + 1;
half(x1, x2, e, x, d);
write(k,'-й корень равен ', x:6:6);
writeln(' с погрешностью ', d:2:10)
end;
x1 := x2; x2 := x1 + h; y1 := y2
end
end.
Задание 4
Составьте программы вычисления корней уравнений:
1) (0.2x 3  cos x ;
2)
2  x  sin x ,
3) lg(x  5)  cos x ;
4) 12
. x  2x  241
.  13x  14.2x .
4
3
2
пр и x  10;
148 
7. Вычисление корней уравнения нахождением минимума функции на промежутке
Зная определение минимума функции на промежутке, легко применить этот метод к
нахождению корней уравнения.
Для этого достаточно рассматривать на заданном промежутке не саму функцию, а ее
модуль, тогда минимум функции будет находиться на оси OX , а значение аргумента в
этой точке даст нам значение корня уравнения на заданном промежутке. Разумеется,
функция должна удовлетворять всем вышеперечисленным требованиям.
Ниже приводятся рисунки, которые наглядно показывают механизм применения поиска минимума функции на промежутке к нахождению корней. На одном из рисунков
схематически показан график заданной функции, а на втором - график абсолютного значения этой функции применительно к нахождению корня с использованием поиска минимума для нахождения корня (см. рис. 28 и 29).
Рис. 28
Рис. 29
Программа нахождения корня уравнения с использованием поиска минимума функции методом “золотого сечения” приводится ниже.
{Решение уравнений с использованием определения минимума }
{ с помощью "золотого сечения" }
Program Equation_min_gold;
uses WinCrt;
var
a, a1, b, b1, e, x : real;
{----------------------------------------------------------------------------------------}
{ Поиск минимума функции методом золотого сечения }
Procedure mingold(a, b, e : real; var x : real);
var
x1, x2, y1, y2 : real;
{----------------------------------------------------------------------------------------}
Function func(x : real) : real;
begin
func := abs(sin(2*x) - ln(x))
end;
149

{----------------------------------------------------------------------------------------}
Function f1(a, b : real) : real;
begin
f1 := 0.618*a + 0.382*b
end;
{----------------------------------------------------------------------------------------}
Function f2(a, b : real) : real;
begin
f2 := 0.382*a + 0.618*b
end;
{----------------------------------------------------------------------------------------}
begin
x1 := f1(a, b); y1 := func(x1);
x2 := f2(a, b); y2 := func(x2);
while abs(b - a) > e do
if y1<y2 then
begin
b := x2; x2 := x1; y2 := y1;
x1 := f1(a, b); y1 := func(x1)
end
else
begin
a := x1; x1 := x2; y1 := y2;
x2 := f2(a, b); y2 := func(x2)
end;
x := (a + b)/2
end;
{----------------------------------------------------------------------------------------}
{ Основная программа }
begin
write('Введите нижнюю границу промежутка '); readln(a);
a1 := a;
write('Введите правую границу промежутка '); readln(b);
b1 := b;
write('Введите точность вычисления корня ');readln(e);
mingold(a, b, e, x);
write('Корень уравнения на промежутке (');
write(a1:1:0, '; ', b1:2:0, ')');
writeln(' равен x = ', x:6:6);
writeln('с точностью до ',e:2:6)
end.
Задание 5
Составьте программу нахождения корня уравнения, применяя поиск минимума
функции с помощью ряда Фибоначчи.
150 
Библиотека часто встречающихся процедур и функций
1. Процедуры, вычисляющая сумму цифр числа:
Procedure sum_number(n : integer; var s : integer);
begin
s := 0;
repeat
s := s + n mod 10;
n := n div 10
until n = 0
end;
Procedure sum_number(p : longint; var s : longint);
begin
s := 0;
while p <> 0 do
begin
s := s + p mod 10;
p := p div 10
end
end;
2. Процедура, вычисляющая количество цифр в числе:
Procedure quantity_number(n : integer; var k : integer);
begin
k := 0;
repeat
k := k + 1;
n := n div 10
until n = 0
end;
3. Процедура, записывающая заданное число в обратном порядке, например, 3467
записывает так: 7643.
Procedure backwards(n : integer; var a : integer);
begin
a := 0;
repeat
a := a*10 + n mod 10;
n := n div 10
until n = 0
end;
4. Процедура перестановки первой и последней цифр числа.
Procedure first_last_number(n : integer; var n1 : integer);
var
a, i, p : integer;
151

begin
a := n; i := 1;
p := n mod 10; {последняя цифра введенного числа}
while n >= 10 do
begin
i := i*10;
n := n div 10
end;
n1 := a - n*i - p + n + p*i
end;
5. Процедура, определяющая, является число числом - палиндромом.
Procedure palindrom(a : integer);
var
b, c, p : integer;
begin
b := a; c := 0;
repeat
p := b mod 10;
c := c*10 + p;
b := b div 10
until b = 0;
if c = a then writeln('Число ', a, ' является палиндромом')
else writeln('Число ', a, ' не явл. палиндромом')
end;
6. Процедура нахождения цифрового корня числа.
Цифровым корнем числа называется сумма цифр заданного числа, затем сумма цифр
полученной суммы и т.д. до тех пор, пока эта сумма не станет однозначным числом.
Procedure radical_number(n : integer; var k : integer);
var
p, s : integer;
begin
repeat
s := 0;
while n <> 0 do
begin
p := n mod 10; s := s+p; n := n div 10
end;
n := s
until n < 10;
k := n
end;
7. Процедуры нахождения наибольшего общего делителя:
1-й способ (по простому алгоритму)
Procedure nod1(a, b : integer; var n : integer);
begin
152 
if a > b then n := b else n := a;
n := n + 1;
repeat
n := n - 1
until (a mod n = 0) and (b mod n = 0)
end;
2-й способ (по 1-му алгоритму Евклида)
Procedure nod2(a, b : integer; var n : integer);
begin
while a <> b do
begin
if a > b then a := a - b else b := b - a
end;
n := a
end;
3-й способ (по 2-му алгоритму Евклида)
Procedure nod(a, b : integer; var n : integer);
var
r : integer;
begin
repeat
r := a mod b;
a := b; b := r
until b = 0;
n := a
end;
8. Рекурсивная процедура нахождения НОД.
Procedure nod(a, b : integer; var n : integer);
begin
if b = 0 then n := a else nod(b, a mod b, n)
end;
9. Процедуры нахождения наименьшего общего кратного двух целых чисел (НОК).
1-й способ
Procedure nok(a, b : integer; var k : integer);
var
m, n : integer;
begin
k := 0;
repeat
if a > b then
begin
m := a; n := b
end
153

else
begin
m := b; n := a
end;
k := p + m
until k mod n = 0
end;
2-й способ (с использованием НОД).
Procedure nok1(a, b : integer; var k : integer);
var
n : integer;
begin
n := a*b;
repeat
c := a mod b;
a := b; b := c
until b = 0;
k := n div a
end;
10. Процедура определения всех делителей заданного числа.
1-й способ
Procedure everyone_divisor(n : integer);
var
i : integer;
begin
writeln('Делители числа ', n);
for i := 1 to n div 2 do
if n mod i = 0 then write(i, ' ');
writeln(n)
end;
2-й способ
Procedure everyone_divisor(n : integer);
var
i : integer;
begin
writeln('Делители числа ', n);
for i := 1 to trunc(sqrt(n)) do
if n mod i = 0 then write(i, ' ', n div i, ' ')
end;
11. Процедура, определяющая число делителей натурального числа:
Procedure number_division(n : integer; var k : integer);
var
d : integer;
154 
begin
k := 0;
for d := 1 to n div 2 do
if n mod d = 0 then k := k + 1;
k := k + 1
end;
12. Процедура разложения числа на простые множители:
Procedure probleme_number(n : integer);
var
i : integer;
begin
while n mod 2 = 0 do
begin
write(2, ' ');
n := n div 2
end;
i := 3;
while i <= n do
if n mod i = 0 then
begin
write(i, ' ');
n := n div i
end
else
i := i + 2
end;
13. Процедура, определяющая, является ли число простым.
первый способ
Procedure probleme_number(p : integer);
var
i, k : integer;
begin
if p = 2 then write(p, ' ')
else
if p mod 2 <> 0
then
begin
i := 3; k := 0;
while i <= p div 2 do
begin
if p mod i = 0 then k := k + 1;
i := i + 2
end;
if k = 0 then write(p, ' ')
end
end;
155

второй способ
Procedure probleme_number(p : integer);
var
i, k : integer;
begin
if p = 2 then write(p, ' ')
else if p mod 2 <> 0
then
begin
i := 3; k := 0;
while i <= trunc(sqrt(p)) do
begin
if p mod i = 0 then k := k + 1;
i := i + 2
end;
if k = 0 then write(p, ' ')
end
end;
14. Процедура, определяющая, является ли число автоморфным? Автоморфным
называется такое число, которое равно последним цифрам своего квадрата. Например: 52
= 25; 252 = 625.
Procedura awtomorf(x : integer);
var
d, k : integer;
begin
d := 10;
while d <= x do d := d*10;
k := x mod 10;
if (k = 1) or (k = 5) or (k = 6)
then
if x*x mod d = x then writeln(x, ' ', x*x)
end;
15. Процедура, устанавливающая, равно ли заданное число сумме квадратов целых
чисел и каких именно, если таковые существуют:
Procedure square(n : integer);
label 1;
var
a, b, k : integer;
begin
a := 1; k := 1;
while a*a + 1 <= n do
begin
k := k + 1; a := a + 1
end;
for a := 1 to k do
for b := 1 to a do if a*a + b*b = n then
156 
begin
writeln(n, '=', a, '*', a, '+', b, '*', b); goto 1
end;
1: end;
16. Процедура определения Пифагоровых чисел из промежутка [n; m].
Procedure pifagor(n, m : integer);
var
a, b, c : integer;
begin
writeln('Пифагоровы числа из промежутка [',n, ';', m,']');
for a := n to m do
for b := n to a do
for c := n to m do
if a*a + b*b = c*c then writeln(a, ' ', b, ' ', c)
end;
17. Процедура представления числа n в виде суммы кубов двух чисел.
Procedure sum_number_cube(n : integer; var p : integer);
var
i, j, k : integer;
begin
k := 0; i := 1;
while i*i*i + 1 <= n do
begin
k := k + 1; i := i + 1
end;
p := 0;
for i := k downto 1 do
for j := 1 to i do
if i*i*i + j*j*j = n
then
begin
p := p + 1;
writeln(i, '*', i, '*', i, '+', j, '*', j, '*', j, '=', n)
end;
if p = 0
then
begin
write('Число ', n, ' нельзя представить в виде ');
writeln('суммы кубов двух чисел')
end
else
writeln('Число способов равно ', p)
end;
18. Процедура представления целого числа n в виде суммы квадратов трех чисел.
Procedure sum_square_number(n : integer; var p : integer);
var
157

k, x, y, z, p : integer;
begin
k := 0; x := 1;
while x*x + 2 <= n do
begin
k := k + 1; x := x + 1
end;
p := 0;
for x := 1 to k do
for y := 1 to x do
for z := 1 to y do
if x*x + y*y + z*z = n
then
begin
p := p + 1;
writeln(x, '*', x, '+', y, '*', y, '+', z, '*', z, '=', n)
end;
if p = 0
then
begin
write('Число ',n,' нельзя представить в виде ');
writeln('суммы квадратов трех чисел')
end
else writeln('Число способов равно ', p)
end;
19. Процедура определения цифры, стоящей на n-ом месте в записи подряд чисел
1234567891011121314...
Procedure location(n : integer; var c : integer);
var
p, s, v, m, q : integer;
Procedure number(n : integer; var k : integer);
begin
k := 0;
repeat
k := k + 1;
n := n div 10
until n = 0
end;
begin
p := 1; s := 0;
repeat
number(p, v);
s := s + v; p := p + 1
until s>=n;
m := s - n; p := p - 1; q := 1;
for i := 1 to m do q := q*10;
c := p div q;
c := c mod 10;
writeln('Последняя цифра в записи этих цифр будет ', c);
writeln('Она находится в числе ', p)
end;
158 
20. Процедуры вычисления степени натурального числа с натуральным показателем:
с циклом repeat ... until ...
Procedure extent(a, n : integer; var s : integer);
var
i : integer;
begin
i := 1; s := 1;
repeat
s := s*a; i := i + 1
until i = n
end;
с циклом for ... to ... do ...
Procedure extent(a, n : integer; var s : longint);
var
i : integer;
begin
s := 1;
for i := 1 to n do s := s*a
end;
функция вычисления степени числа:
Function extent(a, n : longint) : longint;
var
i : integer;
begin
extent := 1;
for i := 1 to n do extent := extent*a
end;
21. Процедура вычисления факториала числа:
итеративная
Procedure fac(n : integer; var f : longint);
var
i : integer;
begin
if n = 0 then f := 1 else for i := 1 to n do f := f*i
end;
рекурсивная
Procedure fac(n : integer; var f : longint);
begin
if (n = 0) or (n = 1) then f := 1
else
begin
159

fac(n - 1, f);
f := f*n
end
end;
22. Рекурсивная процедура умножения числа a на каждую цифру числа b, начиная с
единиц:
Procedure umnogenie(a, b, s : integer);
begin
if b <> 0
then
begin
s := s + a*(b mod 10);
umnogenie(a, b div 10, s div 10);
write(s mod 10:1)
end
else
if s <> 0 then write(s)
end;
23. Функции вычисления чисел ряда Фибоначчи.
итеративная
Function fib(n : integer) : integer;
var
f, f1, f2, i : integer;
begin
f1 := 1; f := 0;
for i := 1 to n do
begin
f2 := f1; f1 := f;
f := f1 + f2;
end;
fib := f
end;
рекурсивная
Function fib(n : integer) : integer;
begin
if (n = 1) or (n = 2)
then fib := 1
else fib := fib(n - 1) + fib(n - 2)
end;
160 
24. Процедура отделения корней на заданном промежутке [a; b] для заданной функции fx, т.е. определения промежутков, на которых может находиться хотя бы один корень
(h - шаг), (x1, x2 - границы полученных промежутков).
Procedure separation_root(a, b, h : real);
var
x1, x2, y1, y2 : real; k : integer;
Function fx(x : real) : real;
begin
fx := ???????????
end;
begin
k := 0; x1 := a; x2 := x1 + h;
y1 := fx(x1);
while x2 <= b do
begin
y2 := fx(x2);
if y1*y2 < 0
then
begin
k := k + 1;
writeln(k, '-й корень на [', x1:6:4, '; ', x2:6:4,']')
end;
x1 := x2; x2 := x1 + h;
y1 := y2
end
end;
25. Процедура уточнения корня некоторой функции func(x) методом деления пополам (a, b - границы промежутка, eps - точность вычисления, x - значение корня, d - погрешность вычисления).
Procedure half(a, b, eps : real; var x, d : real);
var
c : real;
begin
while abs(b - a) > eps do
begin
c := (a + b)/2;
if func(a)*func(c) < 0 then b := c
else a := c
end;
x := (a + b)/2;
d := abs(b - a)/2
end;
26. Процедура поиском минимума функции на промежутка с помощью ряда Фибоначчи.
{ Процедура определения минимума функции на промежутке }
Procedure minfib(a, b, e : real; var x : real);
label 1;
161

var
aa, bb, x1, x2, y1, y2 : real;
n
: integer;
{----------------------------------------------------------------------------------------}
{ Заданная исследуемая функция }
Function func(x : real) : real;
begin
func := ?????????????????
end;
{----------------------------------------------------------------------------------------}
{ Функция вычисления членов ряда Фибоначчи }
Function fib(n : integer) : real;
var
f, f1, f2 : real;
i
: integer;
begin
f1 := 1; f := 0;
for i := 1 to n do
begin
f2 := f1; f1 := f;
f := f1 + f2
end;
fib := f
end;
{----------------------------------------------------------------------------------------}
{ Процедура вычисления знач. аргумента и функции }
{ approach - приближение }
Procedure approach(a, b : real; n : integer; var x2, y2 : real);
begin
x2 := a + (b - a)*fib(n - 1)/fib(n);
y2 := func(x2)
end;
begin
n := 3;
approach(a, b, n, x2, y2);
while abs(b - a) > e do
begin
x1 := a + b - x2; y1 := func(x1);
if (x2 > x1) and (y2 > y1)
then
begin
n := n + 1;
approach(a, b, n, x2, y2);
b := x2; x2 := x1; y2 := y1; goto 1
end;
if (x2 <= x1) and (y2 > y1)
then
begin
n := n + 1;
approach(a, b, n, x2, y2);
a := x2; x2 := x1; y2 := y1; goto 1
end;
162 
if (x2 > x1) and (y2 < y1)
then
begin
n := n + 1;
approach(a, b, n, x2, y2);
a := x1; goto 1
end;
if (x2 <= x1) and (y2 <= y1)
then
begin
n := n + 1;
approach(a, b, n, x2, y2);
b := x1; goto 1
end;
n := n + 1;
approach(a, b, n, x2, y2);
1: end;
x := (a + b)/2;
end;
27. Процедура поиском минимума функции на промежутке с помощью “золотого сечения”.
Procedure mingold(a, b, e : real; var x : real);
var
x1, x2, y1, y2 : real;
{----------------------------------------------------------------------------------------}
Function func(x : real):real;
begin
func := ????????????
end;
{----------------------------------------------------------------------------------------}
Function f1(a, b : real) : real;
begin
f1 := 0.618*a + 0.382*b
end;
{----------------------------------------------------------------------------------------}
Function f2(a, b : real) : real;
begin
f2 := 0.382*a+0.618*b
end;
{----------------------------------------------------------------------------------------}
begin
x1 := f1(a, b); y1 := func(x1);
x2 := f2(a, b); y2 := func(x2);
while abs(b - a) > e do
if y1<y2 then
begin
b := x2; x2 := x1; y2 := y1;
x1 := f1(a, b); y1 := func(x1)
end
else
begin
163

a := x1; x1 := x2; y1 := y2;
x2 := f2(a, b); y2 := func(x2)
end;
x := (a + b)/2
end;
28. Процедура решения неопределённых уравнений вида ax + by = c:
Procedure The_equation(a, b, c : integer); {Решение уравнения ax + by = c}
label 1;
var
max, x, y, n : integer;
begin
if (nod(a, b) <> 1) and (c mod nod(a, b) = 0)
then begin n:= nod(a,b); a := a div n; b := b div n; c := c div n end
else if (nod(a, b) <> 1) and (c mod nod(a, b) <> 0)
then writeln('Уравнение не имеет решений');
if abs(a) > abs(b) then max := abs(a) else max := abs(b);
for x := -max to max do
for y := -max to x do
begin
if (a*x + b*y = 1) and (a > 0) and (b > 0)
then begin writeln('Решения уравнения x = ', x*c, '+', b,'*t, y = ', y*c, '-', a, '*t,');
writeln('где t - произвольное целое число'); goto 1 end;
if (a*x + b*y = 1) and (a < 0) and (b > 0)
then begin writeln('Решения уравнения x = ', x*c, '+', b,'*t, y = ', y*c, ' ', a, '*t,');
writeln('где t - произвольное целое число'); goto 1 end;
if (a*x + b*y = 1) and (a > 0) and (b < 0)
then begin writeln('Решения уравнения x = ', x*c, ' ', b,'*t, y = ', y*c, '-', a, '*t,');
writeln('где t - произвольное целое число'); goto 1 end;
if (a*x + b*y = 1) and (a < 0) and (b < 0)
then begin writeln('Решения уравнения x = ', x*c, ' ', b,'*t, y = ', y*c, ' ', a, '*t,');
writeln('где t - произвольное целое число'); goto 1 end
end;
1: end;
Повторение
О рекурсии
1. Подпрограмме на Паскале (т.е. функции или процедуре) разрешено обращаться к
самой себе - либо напрямую, либо через цепочку вызовов других подпрограмм, приводящую к первоначальной точке вызова.
О подпрограмме, которая вызывает саму себя, говорят, что она рекурсивна.
Многие математические функции и алгоритмы, будучи запрограммированы на Паскале, наиболее естественно выражаются именно в рекурсивной форме. В большинстве
случаев рекурсивное решение задачи получается достаточно простым, но в то же время
оказывается крайне неэффективным в сравнении с итеративной реализацией этого алгоритма.
164 
2. Рекурсивное определение какого-либо понятия или процесса должно содержать
два обязательных элемента: 1) условие прекращения рекурсии, задающее некоторое фиксированное значение для одного или нескольких простых этапов вычисления; 2) выражение более сложного этапа вычислений в терминах менее сложного. Правильно организованный рекурсивный процесс развивается таким образом, что любая сколь угодно сложная ситуация в конце концов сводится к условию прекращения рекурсии.
3. В качестве примера, демонстрирующего рекурсию, часто используют функцию
факториала, определяемую как произведение всех натуральных чисел от 1 до n (в математической нотации n!). Например, 4! = 1 . 2 . 3 . 4 = 24. Этому вычислительному процессу
можно придать и рекурсивную трактовку. Роль условия выхода из рекурсии здесь играет
равенство 0! = 1 или 1! = 1. Выражение сложного этапа через более простой имеет вид n! =
(n - 1)!  n.
4. В подпрограмме на Паскале рекурсивный вызов внешне выглядит точно так же,
как и вызов любой другой подпрограммы. Так, в функции fac, вычисляющей значение "nфакториал", ее тело имеет следующий вид:
if (n = 0) or (n = 1) then fac := 1 {завершение рекурсии}
{иначе - рекурсивный вызов}
else fac := fac(n - 1)*n
Имя функции fac получает значение 1, если n равно 0 или 1; если же n больше единицы, то значение fac определяется как произведение n и значения, полученного от рекурсивного обращения к fac(n - 1).
Упражнения
75. Покажите, что любое натуральное число и его пятая степень оканчиваются одной
и той же цифрой.
76. Некоторое четное число является суммой двух точных квадратов. Докажите, что
его половина является суммой двух точных квадратов.
77. Покажите, что квадрат числа, являющегося суммой двух точных квадратов, также можно представить в виде суммы двух точных квадратов.
78. Покажите, что произведение двух целых чисел, из которых каждое есть сумма
квадратов двух целых чисел, можно представить в виде суммы двух точных квадратов.
79. Покажите, что n7- n делится на 42 (n - натуральное число).
80. Рассмотрим числа вида 22 + 1 (их называют иногда "числами Ферма"); при n = 2,
3, 4 мы получим числа 17, 257, 65537. Эти числа оканчиваются на 7. Докажите, что при
любом натуральном n, больше 1, числа этого вида оканчиваются семеркой.
81. Сложили каких-то 3 целых числа, и их сумма разделилась на 6. Докажите, что
сумма кубов тех же чисел также разделится на 6.
82. Покажите, что сумма квадратов двух нечетных чисел не может быть точным
квадратом.
83. Число 365 нечетное. В то же время 365 можно представить в виде разности двух
точных квадратов: 365 = 392 - 342 и 365 = 1832 - 1822. Докажите, что любое нечетное число
можно представить в виде разности точных квадратов.
84. Целое число x заключено между 0 и 60 (0 < x < 60). При делении числа x на 3, 4,
5 получили соответственно остатки a, b, c. Докажите, что x равен остатку от деления числа
40a + 45b + 36c на 60. (На этом основан фокус - угадывания задуманного числа по остаткам от деления этого числа на 3, 4, 5.)
85. Число 148 делится на 37. Переставим в нем первую цифру с начала в конец: получится 481. Оно тоже делится на 37. Снова первую цифру (4) на последнее место. Опять
получим число, которое делится на 37. Верно ли аналогичное свойство для каждого трехзначного числа, делящегося на 37?
165

86. Если дана последовательность 15 чисел a1, a2, a3, ..., a15, то можно построить новую последовательность чисел b1, b2, b3, ..., b15, где bi равно количеству чисел первой последовательности, меньших ai, i = 1, 2, ..., 15. Построить последовательность (bn). Существует ли последовательность (ak), для которой последовательность (bk) выглядит так: 1, 0,
3, 6, 9, 4, 7, 2, 5, 8, 8, 5, 10, 13, 13?
87. Существует ли такое целое число, которое при зачеркивании первой цифры
уменьшается: а) в 57 раз; б) в 58 раз?
88. Можно ли разменять 25 руб. на рублевые, трехрублевые и пятирублевые купюры
так, чтобы получить всего 10 купюр?
89. Докажите, что если сумма квадратов двух целых чисел делится на 3, то и каждое
из них делится на 3.
90. Найдите какие-нибудь три последовательных натуральных числа, каждое из которых делится на квадрат целого числа, большего единицы.
91. Доказать, что из 9 последовательных натуральных чисел всегда можно выбрать
одно число, взаимно простое с остальными.
92. Найдите с точностью 0.0001 корни уравнений на указанных отрезках:
а)
x 2 cos 2 x  1  0,
б)
x 5  0,3 | x  1 | 0,

[0; ]; г ) x 3  x 2  x  1  0, [1;1];
2
[0;1];
д)
2 x  cos x  0,

[0; ];
2
x 1

 0,
[0; ].
2
4
93. Решите уравнения, используя отделение корней:
1) 4cosx + 0.3x = 0; 2) ln(x + 6.1) = 2sin(x - 1.4).
94. Сколько корней имеет уравнение sinx = x/100?
95. Пусть u > 0, n - натуральное. Значение n u можно найти, решив уравнение
x n  u  0. Для того чтобы применить метод деления отрезка пополам, надо сначала найти
a и b такие, что функция x n  u для x = a и x = b принимает значения разных знаков. Какие числа можно взять в качестве a и b?
Для данного u определить 3 u , 4 u .
в ) 0,9 x  sin
x  0,1  0, [0;1,5 ]; е )
tgx 
Ответы
К заданию 1
Program Task1;
uses WinCrt;
var
n, s, s1 : integer;
{----------------------------------------------------------------------------------------}
Procedure extent(a, n : integer; var s : integer);
var
i : integer;
begin
i := 1; s := 1;
repeat
s := s*a; i := i + 1
until i = n
end;
{----------------------------------------------------------------------------------------}
166 
begin
n := 1;
repeat
n := n + 1;
extent(2, n, s);
extent(3, n, s1);
until ((s - 2) mod (n - 1) <> 0) and ((s1 - 3) mod (n - 1) = 0);
writeln('Искомое число равно ', n - 1)
end.
К заданию 2
Program Task2;
uses WinCrt;
var
n, s, s1 : integer;
{----------------------------------------------------------------------------------------}
Procedure extent(a, n : integer; var s : integer);
var
i : integer;
begin
i := 1;
s := 1;
repeat
s := s*a;
i := i+1
until i=n
end;
{----------------------------------------------------------------------------------------}
begin
n := 1;
repeat
n := n+1;
extent(2, n, s);
extent(3, n, s1);
until ((s-2) mod (n-1)<>0) and ((s1-3) mod (n-1)=0);
writeln('Искомое число равно ', n-1)
end.
К заданию 3
Program Task3; { Сумма правильных делителей }
uses WinCrt;
var
i, a, b, s : integer;
{----------------------------------------------------------------------------------------}
Procedure math_divisor(n : integer; var s : integer);
var
d : integer;
begin
s := 0;
for d := 1 to n div 2 do
167

if n mod d = 0 then s := s + d
end;
{----------------------------------------------------------------------------------------}
begin
write('Введите левую границу промежутка >1 '); readln(a);
write('Введите правую границу промежутка '); readln(b);
for i := a to b do
begin
math_divisor(i, s);
write('Сумма правильных делителей числа ', i);
writeln(' равно ', s)
end
end.
Program Task3p2; { Точный квадрат и число делителей }
uses WinCrt;
var
i, n, k : integer;
{----------------------------------------------------------------------------------------}
Procedure number_division(n : integer; var k : integer);
var
d : integer;
begin
k := 0;
for d := 1 to n div 2 do
if n mod d = 0 then k := k + 1;
k := k + 1
end;
{----------------------------------------------------------------------------------------}
begin
write('Введите правую границу промежутка '); readln(n);
for i := 1 to n do
begin
write('Число делителей числа ', i*i, ' равно: ');
number_division(i*i, k);
write(k);
if k mod 2 <> 0 then writeln(' - число нечетное')
else writeln(' - число четное')
end
end.
К заданию 5
Program task5; { Определение цифр в записи 246810... }
uses WinCrt;
var
n, p, s, c, v, q, i, m :integer;
{----------------------------------------------------------------------------------------}
Procedure number(n : integer; var k : integer);
begin
k := 0;
repeat
168 
k := k + 1;
n := n div 10
until n = 0
end;
{----------------------------------------------------------------------------------------}
begin
write('Введите число цифр '); readln(n);
p := 2; s := 0;
repeat
number(p, v);
s := s + v; p := p + 2
until s >= n;
m := s - n; p := p - 2; q := 1;
for i := 1 to m do q := q*10;
c := p div q; c := c mod 10;
writeln('Последняя цифра в записи этих цифр будет: ', c);
writeln('Это цифра из числа ', p)
end.
К заданию 8
К примеру 1
Program ignoramus; { ignoramus - невежда, неуч }
uses WinCrt;
{----------------------------------------------------------------------------------------}
Procedure expert(n1, n2, n : integer); {expert - знаток}
var
a : integer;
begin
if n2 = 50 then write(n)
else
begin
a := n1;
n1 := n2;
n2 := (a + n2) div 2 + 2;
expert(n1, n2, n + 1)
end
end;
{----------------------------------------------------------------------------------------}
begin
write('Силы Незнайки иссякнут через ');
expert(1, 1, 1);
writeln(' дней')
end.
К примеру 2
Program larina;
uses WinCrt;
var
q : integer;
169

{----------------------------------------------------------------------------------------}
Procedure page(n, q, s : integer);
begin
if s >= q then writeln(n - 1)
else page(n + 1, q, s + n)
end;
{----------------------------------------------------------------------------------------}
begin
write('Введите сумму номеров, прочитанных страниц '); readln(q);
write('Номер последней прочитанной Татьяной страницы ');
page(1, q, 0)
end.
К примеру 3
Program Tsarevna_frog; { frog - лягушка }
uses WinCrt;
Procedure frog(n : real; k : integer);
begin
if trunc(n) > 100 then write(k)
else frog(n + 0.2*n + 2, k + 1)
end;
begin
write('Лягушка съест больше 100 комаров в ');
frog(12, 1); writeln(' день')
end.
К примеру 5
Program Task7_5;
uses WinCrt;
var
i : integer;
{----------------------------------------------------------------------------------------}
Procedure ameba(n, i, k : integer); {Деление амебы}
begin
if k = i then write(' ', n, ' ')
else ameba(2*n, i, k + 3)
end;
{----------------------------------------------------------------------------------------}
begin
writeln('Число клеток через 3, 6, 9, ..., 24 часа');
i := 0;
repeat
i := i + 3;
ameba(1, i, 0)
until i = 24;
writeln
end.
170 
Ответы к заданиям темы: ”Функции “.
К заданию 1
Program succession1a;
uses WinCrt;
var
a, i, n : integer;
{----------------------------------------------------------------------------------------}
Function Sum_sgr(a : integer) : integer;
var
s, p : integer;
begin
s := 0;
repeat
p := a mod 10;
s := s + p*p;
a := a div 10
until a = 0;
Sum_sgr := s
end;
{----------------------------------------------------------------------------------------}
Function Succ(a, n : integer) : integer;
var
i : integer;
begin
if n > 1 then for i := 2 to n do a := Sum_sgr(a);
Succ := a
end;
{----------------------------------------------------------------------------------------}
begin
write('Введите первый член последовательности '); readln(a);
write('Введите число членов последовательности '); readln(n);
for i := 1 to n do write(Succ(a, i), ' '); writeln
end.
Program Succession2b;
uses WinCrt;
var
a, i, n, k : integer;
{----------------------------------------------------------------------------------------}
Function Sum_sgr(a : integer) : integer;
var
s, p : integer;
begin
s := 0;
repeat
p := a mod 10;
s := s + p*p; a := a div 10
until a = 0;
Sum_sgr := s
end;
171

{----------------------------------------------------------------------------------------}
Function Succ(a, n : integer) : integer;
var
i : integer;
begin
if n > 1 then for i := 2 to n do a := Sum_sgr(a);
Succ := a
end;
{----------------------------------------------------------------------------------------}
begin
write('Введите первый член последовательности '); readln(a);
i := 0;
repeat
i := i + 1
until (Succ(a, i) = 1) or (Succ(a, i) = 89);
write('Член последовательности ', Succ(a, i));
writeln(' находится под номером ', i);
writeln('Члены последовательности');
for k := 1 to i do write(Succ(a, k), ' '); writeln
end.
К заданию 2
{ Минимум функции методом золотого сечения }
Program min_gold;
uses WinCrt;
var
a, b, x1, y1, x2, y2, x, y, e : real;
{----------------------------------------------------------------------------------------}
Function fx(x : real) : real;
begin
fx := 4*x*x*x*x - 14*x*x*x + 60*x*x - 70*x
end;
{----------------------------------------------------------------------------------------}
Procedure gold1(a, b : real; var x1, y1 : real);
begin
x1 := 0.618*a + 0.382*b; y1 := fx(x1)
end;
{----------------------------------------------------------------------------------------}
Procedure gold2(a, b : real; var x2, y2 : real);
begin
x2 := 0.382*a + 0.618*b; y2 := fx(x2)
end;
{----------------------------------------------------------------------------------------}
{ Основная программа }
begin
write('Введите начало промежутка '); readln(a);
write('Введите конец промежутка '); readln(b);
write('Введите точность '); readln(e);
gold1(a, b, x1, y1);
gold2(a, b, x2, y2);
while abs(b-a) > e do
172 
begin
if y1 < y2 then
begin
b := x2; x2 := x1;
y2 := y1; gold1(a, b, x1, y1)
end
else
begin
a := x1;
x1 := x2;
y1 := y2;
gold2(a, b, x2, y2)
end
end;
x := (a + b)/2;
writeln('y min = ', fx(x):4:12, ' при x = ', x:4:12);
writeln('С точностью до ', e:2:12)
end.
К заданию 4
Program Problem5c;
uses WinCrt;
var
a, b, c : integer;
{----------------------------------------------------------------------------------------}
Function nod(a, b : integer) : integer;
begin
if b = 0 then nod := abs(a)
else nod := nod(abs(b), abs(a) mod abs(b))
end;
{----------------------------------------------------------------------------------------------}
Procedure The_equation(a, b, c : integer); {Решение уравнения ax + by = c}
label 1;
var
max, x, y, n : integer;
begin
if (nod(a, b) <> 1) and (c mod nod(a, b) = 0)
then begin n:= nod(a,b); a := a div n; b := b div n; c := c div n end
else if (nod(a, b) <> 1) and (c mod nod(a, b) <> 0)
then writeln('Уравнение не имеет решений');
if abs(a) > abs(b) then max := abs(a) else max := abs(b);
for x := -max to max do
for y := -max to x do
begin
if (a*x + b*y = 1) and (a > 0) and (b > 0)
then begin writeln('Решения уравнения x = ', x*c, '+', b,'*t, y = ', y*c, '-', a, '*t,');
writeln('где t - произвольное целое число'); goto 1 end;
if (a*x + b*y = 1) and (a < 0) and (b > 0)
then begin writeln('Решения уравнения x = ', x*c, '+', b,'*t, y = ', y*c, ' ', a, '*t,');
writeln('где t - произвольное целое число'); goto 1 end;
if (a*x + b*y = 1) and (a > 0) and (b < 0)
173

then begin writeln('Решения уравнения x = ', x*c, ' ', b,'*t, y = ', y*c, '-', a, '*t,');
writeln('где t - произвольное целое число'); goto 1 end;
if (a*x + b*y = 1) and (a < 0) and (b < 0)
then begin writeln('Решения уравнения x = ', x*c, ' ', b,'*t, y = ', y*c, ' ', a, '*t,');
writeln('где t - произвольное целое число'); goto 1 end
end;
1: end;
{----------------------------------------------------------------------------------------}
begin
write('Введите значение коэффициента при x, a '); readln(a);
write('Введите значение коэффициента при y, b '); readln(b);
write('Введите значение свободного члена
c '); readln(c);
The_equation(a, b, c);
end.
К заданию 5
Уточнение корней уравнения нахождением минимума функции с помощью ряда
Фибоначчи.
Program equation;
uses WinCrt;
var
a, aa, b, bb, e, x : real;
{--------------------------------------------------------------------------------------------}
Procedure minfib(a, b, e : real; var x : real);
label 1;
var
aa, bb, x1, x2, y1, y2 : real;
n
: integer;
{----------------------------------------------------------------------------------------}
Function func(x : real) : real;
begin
func := abs(sin(2*x) - ln(x))
end;
{----------------------------------------------------------------------------------------}
Function fib(n : integer) : real;
var
f, f1, f2 : real;
i
: integer;
begin
f1 := 1; f := 0;
for i := 1 to n do
begin
f2 := f1;
f1 := f;
f := f1 + f2
end;
fib := f
end;
{----------------------------------------------------------------------------------------}
Procedure approach(a, b : real; n : integer;
174 
var x2, y2 : real);
begin
x2 := a + (b - a)*fib(n - 1)/fib(n);
y2 := func(x2)
end;
begin
n := 3; approach(a, b, n, x2, y2);
while abs(b - a) > e do
begin
x1 := a + b - x2;
y1 := func(x1);
if (x2 > x1) and (y2 > y1)
then
begin
n := n + 1;
approach(a, b, n, x2, y2);
b := x2;
x2 := x1;
y2 := y1; goto 1
end;
if (x2 <= x1) and (y2 > y1)
then
begin
n := n + 1;
approach(a, b, n, x2, y2);
a := x2;
x2 := x1;
y2 := y1; goto 1
end;
if (x2 > x1) and (y2 < y1)
then
begin
n := n + 1;
approach(a, b, n, x2, y2);
a := x1; goto 1
end;
if (x2 <= x1) and (y2 <= y1)
then
begin
n := n + 1;
approach(a, b, n, x2, y2);
b := x1; goto 1
end;
n := n + 1;
approach(a, b, n, x2, y2);
1: end;
x := (a + b)/2;
end;
{----------------------------------------------------------------------------------------}
begin
write('Введите нижнюю границу промежутка '); readln(a);
aa := a;
175

write('Введите правую границу промежутка '); readln(b);
bb := b;
write('Введите точность приближения '); readln(e);
minfib(a, b, e, x);
write('Корень уравнения на промежутке (');
writeln(aa:1:0,',',bb:2:0,') равен ', x:6:12)
end.
Глава 8. Элементы комбинаторики
Здесь мы рассмотрим некоторые примеры из очень обширного круга задач, для решения которых используются ЭВМ и персональные компьютеры. Это вопросы комбинаторики и теории вероятностей.
1. Размещения
Прежде вспомним некоторые основные понятия из математики, в частности из теории множеств.
Во-первых, что такое множество вообще? Понятие множества является основополагающим в математике и неопределяемым.
Под множеством понимается некоторая совокупность объектов, объединенных
по какому-то общему признаку.
Так, можно говорить о множестве стульев и столов в классе, множестве натуральных
чисел, целых, рациональных и действительных (вещественных) чисел.
Объекты, входящие в множество, мы будем называть элементами.
Число 5 является элементом множества натуральных чисел. Стол является элементом множества столов в классе. Обычно множества обозначаются большими латинскими
буквами
A, B, C, D, ..., X, Y, Z, а их элементы - малыми буквами a, b, c, d, ..., x, y, z.
О том факте, что a является элементом множества A говорят, что a принадлежит
множеству A.
Обычно элементы множества записываются в фигурных скобках
A   a1 , a2 , a3 ,..., an .
Пусть нам даны множества A, с уже указанными его элементами, и множество B =
{a1, a2, a3, a4}.
Как вы заметили, каждый элемент множества B является и элементом множества A.
В этом случае говорят, что B является подмножеством множества A.
Определение. Если каждый элемент множества B является в то же время элементом
и множества A, то говорят, что B есть подмножество (часть) A.
Очень часто нам будет важно знать не только элементы множества, но и порядок их
расположения в множестве.
Если учитывается порядок расположения элементов в множестве, тогда множества,
имеющие одинаковые элементы, но имеющие их разное расположение, будут для нас различными.
Например: Z = {z1, z2, z3, z4 } и B = {z2, z1, z3, z4} будут считаться разными, так как у
них различен порядок расположения элементов.
176 
Множество, в котором задан порядок следования элементов, называются упорядоченным.
Рассмотрим некоторые простые примеры.
Пример 1. В классе 12 учебных предметов. В день проводится 5 разных уроков.
Сколькими способами может быть составлено расписание занятий.
Для простоты рассуждений обозначим учебные предметы числами от 1 до 12:
1, 2, 3, 4, 5, ..., 10, 11, 12.
По условию задачи, нам необходимо из этих 12 чисел выбирать по 5 чисел. Причем
эти наборы из пяти чисел могут отличаться не только числами, но и расположением чисел,
например, один из наборов будет: {1, 2, 3, 4, 5}; набор, который получается при перестановке этих же чисел {2, 1, 3, 4, 5}, также будет удовлетворять условию задачи.
В самом деле, пусть первый набор будет состоять из следующих предметов: {алгебра, физика, химия, история, литература}; тогда набор, полученный при перестановке хотя бы двух предметов уже даст новое расписание: {физика, алгебра, химия, история, литература}.
Таким образом, наборы из 5 чисел могут отличаться не только самими числами, но и
порядком их расположения.
Такие подмножества называются в комбинаторике размещениями.
Определение. Размещением из n элементов по k называется всякое упорядоченное
подмножество данного множества, содержащее k элементов.
О размещениях можно сказать несколько иначе, правда менее строго с математической точки зрения, но более понятно для нас.
Размещением из n элементов по k называется всякое подмножество данного множества, состоящее из k элементов, которое может отличаться не только элементами, но и порядком их расположения.
Например, из множества M = {1, 2, 3, 4} можно образовать 12 различных размещений, из 4 по 2:
{1, 2} {1, 3} {1, 4} {2, 3} {2, 4} {3, 4}
{2, 1} {3, 1} {4, 1} {3, 2} {4, 2} {4, 3}
Число размещений, взятых из n элементов по k, мы будем обозначать символом Ank и
n!
определять по формуле: Ank =
.
( n  k )!
4!
4! 2 ! 3  4
Значит, A42 =
=
=
= 12.
2!
( 4  2 )!
2!
Возвращаемся к примеру 1. В нем, как теперь уже стало ясно, надо найти число размещений из 12 по 5.
12!
12!
По формуле находим: A125 =
=
(12  5)!
7!
Вычислить число размещений можно другим способом:
( n  k )! ( n  k  1)  ( n  k  2) ...  n
n!
 ( n  k  1)  ( n  k  2)...n.
=
Ank =
( n  k )!
( n  k )!
Итак, A nk  (n  k  1)  (n  k  2)...(n  k  k ).
Словами можно сказать, что число размещений из n элементов по k равно произведению k элементов n  (n  1)...(n  k  1).
Например, A53  5  4  3  60, A124  12  11  10  9.
177

Таким образом, составив процедуру вычисления размещений по этому принципу, мы
избегаем недопустимо больших чисел, которые могут образовываться при вычисление
факториалов и упрощаем составление программ, а также имеем возможность в дальнейшем применять процедуру размещений в других программах.
Процедура размещений из n элементов по k элементов.
Procedure placement(n, k : integer; var r : longint);
var
i : integer;
begin
r := 1;
for i := 1 to k do r := r*(n - k + i)
end;
Программа
Program Problem1;
uses WinCrt;
var
n, k, r : longint;
{----------------------------------------------------------------------------------------}
{ Процедура вычисления числа размещений из n по k }
Procedure placement(n, k : integer; var r : longint);
var
i : integer;
begin
r := 1;
for i := 1 to k do r := r*(n - k + i)
end;
{----------------------------------------------------------------------------------------}
begin
write('Введите число всех предметов '); readln(n);
write('Введите число уроков в день '); readln(k);
Placement(n, k, r);
writeln('Число вариантов расписания равно ', r)
end.
Пример 2. Сколько различных четырехзначных чисел можно написать при помощи
цифр 0, 1, 2, ..., 9?
Рассуждения могут быть очень простыми. Нам надо выяснить сколькими способами
можно выбрать по 4 цифры из 10, причем важен порядок расположения цифр, так как
1234 и 2134 дают разные числа. Значит необходимо определить число размещений из 10
элементов по 4, A104 .
Но из этого количества чисел мы должны исключить те, которые начинаются цифрой 0, например, 0123, 0213 и т.п. Эти числа уже не будут четырехзначными.
Сколько таких чисел? Да столько, сколько трехзначных чисел получится из 9 цифр
(без нуля), т. е. равное числу размещений из 9 элементов по 3, A93 .
Окончательное количество четырехзначных чисел, которые можно составить из 10
цифр равно разности: A104  A93 .
178 
Программа
Program Problem2;
uses WinCrt;
var
n, k, a, a1 : longint;
{----------------------------------------------------------------------------------------}
Procedure placement(n, k : integer; var r : longint);
var
i : integer;
begin
r := 1;
for i := 1 to k do r := r*(n - k + i)
end;
{----------------------------------------------------------------------------------------}
begin
write('Введите заданное ко-во цифр '); readln(n);
write('Введите ко-во цифр, из скольких составляется число '); readln(k);
placement(n, k , a);
placement(n - 1, k - 1, a1);
writeln('Число различных 4-х знач. чисел, которые можно');
writeln('написать при помощи цифр 0, 1, 2, .., 9 равно ', a - a1)
end.
Задание 1
Составьте программы с использованием процедуры размещений.
1. Сколькими различными способами собрание, состоящее из 40 человек, может выбрать из своей среды председателя, его заместителя и секретаря?
2. Сколько не более чем трехзначных чисел можно составить из цифр 1, 2, 3, 4, 5 так,
чтобы цифры в числах не повторялись?
Задачи, решаемые с помощью размещений
Пример 3. Некто забыл нужный ему номер телефона, который состоит из одной из
десяти букв и пяти цифр, но он помнит, что в образовании этого номера участвуют цифры
3, 5, 7, 9. Какое наибольшее количество проб надо сделать, чтобы дозвониться нужному
абоненту?
В искомый номер должны войти четыре цифры, которые можно разместить на 5 местах A54 различными способами, но пятая цифра может быть любой из 10 цифр (0, 1, 2, ...,
9). Поэтому различных телефонных номеров без буквы будет 10  A54 .
Комбинируя эти номера с каждой из десяти букв, получаем:
10  10  A54 .
179

Составим программу с использованием процедуры размещений.
Program Problem3;
uses WinCrt;
var
p : longint;
{----------------------------------------------------------------------------------------}
Procedure placement(n, k : integer; var r : longint);
var
i : integer;
begin
r := 1;
for i := 1 to k do r := r*(n - k + i)
end;
{----------------------------------------------------------------------------------------}
begin
placement(5, 4, p);
p := 10*10*p;
writeln('Надо сделать ', p, ' проб, чтобы дозвониться')
end.
Пример 4. Сколько размещений из n элементов по m будет начинаться с первого
элемента?
Соображения по составлению программы
Из n элементов выберем первый элемент и строго закрепим его на первом месте в
получаемых размещениях.
Тогда, в исходном множестве останется n - 1 элементов, из которых надо выбирать
еще по m - 1 - му элементу и добавлять к уже имеющемуся и стоящему на первом месте
первому элементу.
Теперь остается выяснить, сколькими способами можно из n - 1 выбрать по m 1.
Это можно сделать A nm11 способами.
Поскольку первый элемент строго закреплен на первом месте в получаемых размещениях, то число всевозможных способов и будет равно A nm11 .
Программа
Program Problem4;
uses WinCrt;
var
p
: longint;
m, n : integer;
{----------------------------------------------------------------------------------------}
Procedure placement(n, k : integer; var r : longint);
var
i : integer;
begin
r := 1;
for i := 1 to k do r := r*(n - k + i)
end;
{----------------------------------------------------------------------------------------}
180 
begin
write('Введите число всех элементов '); readln(m);
write('Введите число выбираемых элементов '); readln(n);
placement(m - 1, n - 1, p);
writeln('Число размещений из ', m, ' элементов по ', n, ',');
writeln('которые нач. с первого элемента, равно ', p)
end.
Пример 5. Составлены размещения из 10 элементов по 7 элементов. Сколько из этих
размещений будут содержать: а) первый элемент, б) второй и четвертый элементы?
Решение
Во-первых, чем эта задача отличается от предыдущей?
В предыдущей задаче к первому элементу было строгое требование, - он должен
находиться в образуемых размещениях обязательно на первом месте.
В этом примере, первый элемент просто должен присутствовать в получаемых размещениях, но совсем необязательно чтобы он находился на первом месте, значит он может занимать любое из 7 мест в получаемых размещениях.
Пронумеруем элементы множества цифрами от 1 до 7, тогда заданное множество
элементов может быть записано так: {1, 2, 3, 4, 5, 6, 7}. Первый элемент выбираем из заданного множества, а "незанятые" места обозначим "x". Как видно, получается 7 подмножеств.
{1, x , x , x , x , x , x }
{x ,1, x , x , x , x , x }
{x , x ,1, x , x , x , x }
{x , x , x ,1, x , x , x }
{x , x , x , x ,1, x , x }
{x , x , x , x , x ,1, x }
{x , x , x , x , x , x ,1}
Отсюда следует, что его можно расположить в получаемых размещениях A 71 способами.
Во-вторых, после того, как "вытащили” первый элемент из 10 в нем осталось 9 элементов. Из этих 9 надо выбрать и добавить к первому элементу еще 6, чтобы всего получаемых эл. было бы 7. Это можно сделать A96 способами.
всего A9 столбцов

{
12
,
,
3
,
4
,
5
,
6
,
7
}
(13
, ,4,5,6,7,8} ... ... ...

{213
, , ,4,5,6,7} {314
, , ,5,6,7,8} ... ... ...

, , ,5,6,7} {3,415
, , ,6,7,8} ... ... ...
{2,314

1
, , ,6,7} {3,4,516
, , ,7,8} ... ... ...
A 7  ст р ок {2,3,415
{2,3,4,516
, , ,7} {3,4,5,61
, ,7,8} ... ... ...

, ,7} {3,4,5,6,718
, , } ... ... ...
{2,3,4,5,61
{2,3,4,5,6,71
, ) {3,4,5,6,7,81
, } ... ... ...

всего A96 столбцов

В итого мы имеем количество способов, равное произведению размещений A71  A96 .
Продумайте решение пункта б) этой задачи.
Программу составьте самостоятельно
6
181

Задание 2
1. Сколько размещений из m элементов по n будет начинаться любым элементом за
исключением первого?
2. Составлены размещения из 10 элементов по 7 элементов. Сколько из этих размещений не будет содержать: а) первого элемента, б) третьего и пятого?
Упражнения
96. Сколько можно составить трехзначных чисел из нечетных цифр, если каждую из
этих цифр использовать только один раз?
97. Сколько трехзначных чисел можно составить из всех цифр так, чтобы цифры в
числах не повторялись?
98. Собрание, на котором присутствует 20 человек, избирает в президиум двух человек, один из которых должен быть председателем, а другой - секретарем. Каким числом
способов это можно сделать?
99. Сколько различных слов, каждое из которых содержит 4 буквы, можно составить
из букв слова выборка?
100. Сколько различных четырехзначных чисел можно написать при помощи цифр
0, 1, 2, ..., 9?
101. Сколько различных правильных дробей можно составить из чисел 3, 5, 7, 11, 13,
17, 19, 23?
2. Перестановки
Пример 6. Каким числом способов 10 человек могут находиться в очереди?
Рассуждая над этой задачей, нам становится понятным, что необходимо 10 элементов (10 человек) разместить на 10 местах в очереди, т.е. необходимо выполнить размещения из 10 элементов по 10 - A1010 , которое равно:
A1010 = 10  9  8  ...  3  2  1 = 10!
Размещения из n элементов по n называются перестановками из n элементов. Таким
образом, две различные перестановки из n элементов могут отличаться друг от друга не
числом элементов, а только порядком расположения элементов.
Определение. Пусть имеется конечное множество M = {a1, a2, ..., an}. Всякое упорядоченное множество, состоящее из n элементов множества M, называется перестановкой
этого множества.
Согласно определению, число всевозможных различных перестановок из n элементов равно:
Pn  A nn  n  (n  1)  (n  2)...3  2  1  n ! (эн фактор иал).
Не забывайте, что принято 0! = 1.
Для решения нашей задачи, надо составить программу с процедурой вычисления
факториала числа.
Program Problem6;
uses WinCrt;
var
n, f : longint;
{----------------------------------------------------------------------------------------}
182 
Procedure Factorial(n : integer; var f : longint);
var
i : integer;
begin
f := 1;
if n = 0 then f := 1
else for i := 1 to n do f := f*i
end;
{----------------------------------------------------------------------------------------}
begin
write('Введите число элементов множества '); readln(n);
Factorial(n, f);
writeln('Десять человек могут находится в очереди ', f, ' способами')
end.
Пример 7. Сколько четных пятизначных чисел можно составить из цифр
2, 3, 4, 5, 9?
Математический алгоритм решения
Четными будут те числа, которые оканчиваются четной цифрой. В данном примере
четных цифр две.
Допустим, что одна из четных цифр находится во всех случаях на последнем месте,
тогда все получаемые числа будут четными. Сколько таких чисел будет? Их будет столько, сколько перестановок можно сделать из оставшихся 4-х цифр, т. е. 4! Но среди заданных цифр есть еще одна четная. Допустим, что теперь эта вторая цифра находится на последнем месте, тогда снова будут получаться четные числа и их также будет 4!
Окончательное число четных пятизначных чисел равно 2  4 !
Программу составить нетрудно. Выполните это самостоятельно.
Задание 3
Сколько пятизначных чисел, кратных 5, можно изобразить цифрами
0, 1, 2, 3, 5?
3. Перестановки с повторениями
Пример 8. Сколько различных слов, каждое из которых состоит из семи букв, можно
составить из букв слова "коробок".
В отличие от предыдущего примера здесь не все буквы слова различны (там были
все цифры разными). Если бы все буквы были различны, то из них можно было бы составить 7! различных слов.
Однако не все перестановки букв дают новые слова. Очевидно, что перестановка
букв "к", так же как и букв "о", между собой не дают нового слова. Следовательно, рассматриваемая задача свелась к тому, чтобы определить число перестановок, в результате
которых получается одно и то же слово. Число перестановок буквы "к" между собой, в результате которых получаются одинаковые слова равно 2! После каждой такой перестановки буква "о" может быть переставлена 3! способами. Применяя правило произведения, по-
183

лучим, что каждое новое слово будет повторяться 2 ! 3 ! раз, и поэтому число различных
7!
слов, которое можно составить из слова "коробок", равно
.
2 ! 3 !
Вообще, пусть дано множество M = {a, b, c, ...}, состоящее из n элементов, из которых элемент a повторяется n1 раз, элемент b - n2 раз, элемент c - n3 раз, ... так, что
n1  n2  n3 ...  n.
Требуется найти число перестановок с заданным числом повторений входящих в него элементов.
Число перестановок в этом случае определяется по формуле:
Pn (n1 , n2 , n3 ,... ) 
n!
,
n1 ! n2 ! n3 !...
где n1  n2  n3 ...  n. Если n1  n2  n3 ...  1, то из этой формулы получается:
Pn  n !
Программа
Program Problem8;
uses WinCrt;
var
s, k1, k2 : longint;
{----------------------------------------------------------------------------------------}
Procedure Factorial(n : integer; var f : longint);
var
i : integer;
begin
f := 1;
if n = 0 then f := 1
else for i := 1 to n do f := f*i
end;
{----------------------------------------------------------------------------------------}
begin
Factorial(7, s); Factorial(3, k1); Factorial(2, k2);
s := s div (k1*k2);
writeln('Из слова "КОРОБОК" можно составить ', s, ' различных слов')
end.
Задание 4
Сколькими способами можно расставить на книжной полке 4 книги по теории вероятностей, 3 книги по теории игр и 2 книги по математической логике, если книги по каждому предмету одинаковые?
184 
4. Сочетания
Пусть M - конечное (не обязательно упорядоченное) множество, состоящее из n элементов.
Определение. Сочетанием из n элементов по k называется любое подмножество
множества M  {a1 , a2 ,..., an }, состоящее из k элементов. Два сочетания из n элементов по
k мы будем считать различными в том случае, если в одном из них есть, хотя бы один
элемент, не содержащийся в другом.
Другими словами, в сочетаниях не важен порядок элементов, а важен лишь их состав. Так, например, из множества M = {1, 2, 3, 4} можно составить четыре различных сочетания из 4 по 3: {1, 2, 3}, {1,2,4}, {2, 3, 4}, {1, 3, 4}.
Число различных сочетаний из n элементов по k равно:
n!
C nk 
Если k = 0, тогда C n0  1.
k ! ( n  k )!
Учитывая, что число размещений из n элементов по k равно, но
n!
Ank 
,
( n  k )!
можно выразить число сочетаний через число размещений, тогда получим:
Ank
k
Cn 
.
k!
Пример 9. Дано 10 точек, из которых никакие три не лежат на одной прямой и никакие четыре точки не лежат в одной плоскости. Сколько различных плоскостей можно провести через эти точки?
Из геометрии нам известна аксиома, что через три точки, не лежащие на одной прямой можно провести плоскость и притом только одну.
Поскольку это так, тогда, если плоскость проходит через три точки A, B, C, то через
точки B, A, C или C, B, A и т.п., проходит та же плоскость, т. е. порядок расположения
трех точек, через которые проходит плоскость не имеет значения. А значит число различных плоскостей, проведенных через каждые три точки из 10 равно числу сочетаний из 10
элементов по 3.
Составим процедуру вычисления числа сочетаний из n элементов по k.
Для этого удобней воспользоваться второй формулой, в которой вычисляется только
n!
один факториал числа k. В формуле C nk 
их надо вычислять целых три (n!, (n
k ! ( n  k )!
- k)! и k!) и может возникнуть ситуация, когда будут получаться очень большие числа, которые могут выходить за пределы указанного целого типа.
Можно найти и другую формулу для числа сочетаний, в которой можно избежать
больших чисел и вычисления факториалов чисел.
( n  k )! ( n  k  1)( n  k  2)...( n  k  k )
n!
C nk 


( n  k )! k !
( n  k )! k !
( n  k  1)( n  k  2)... ( n  k  k )

.
k!
( n  k  1)  ( n  k  2)...( n  k  k )
Итак, пользуемся формулой: C nk 
.
k!
В процедуре, в качестве входных формальных переменных будут две переменные n
и k, для числа всех элементов и числа выбираемых элементов. Выходной параметр для
значения сочетания обозначим c, имя процедуры - Сombination.
185

Получим: Procedure Combination(n, k : integer; var с : longint);
Входные параметры имеют тип integer, а выходной - longint, так как значение числа
сочетаний может быть даже очень большим числом.
Переменные самой процедуры - i, - переменная для цикла for и p - промежуточная
переменная для факториала k!.
В процедуре устанавливаются первоначальные значения для числа сочетаний (c :=
1).
Организуется цикл for от 1 до k, в котором в переменную с будет накапливаться
произведение, которое и является числом сочетаний из n элементов по k:
k
k
n k i
,
(1)
где
- знак произведения от 1 до k.


i
i 1
i 1
Давайте проверим, будет ли эта формула выдавать нам число сочетаний из n элементов по k. Пусть n = 5, k = 3, тогда по формуле для числа сочетаний будем иметь:
5!
3 ! 4  5
C 53 

 10,
3 ! 2 ! 3 !1 2
а по формуле (1), получаем:
3

i 1
5  3  i 5  3 1 5  3  2 5  3  3 3  4  5




 10.
i
1
2
3
1 2  3
Таким образом, этой формулой можно пользоваться при подсчете числа сочетаний в
программе.
Окончательно процедура вычисления числа сочетаний будет следующей:
Procedure combination(n, k : integer; var с : longint);
var
i : longint;
begin
с := 1;
for i := 1 to k do с := с*(n - k + i) div i
end;
Для составления программы решения данной задачи, надо в основной программе обратиться к процедуре combination, причем фактические значения переменных будут 10, общее число точек и 3 - число точек через которые проходит одна плоскость.
Программа
Program Problem9;
uses WinCrt;
var
pl : longint;
{----------------------------------------------------------------------------------------}
Procedure combination(n, k : integer; var c : longint);
var
i : longint;
begin
c := 1;
for i := 1 to n - k do c := c*(n - k + i) div i
end;
186 
{----------------------------------------------------------------------------------------}
begin
combination(10, 3, pl);
writeln('Число плоскостей равно: ', pl)
end.
Пример 10. Сколько различных вариантов хоккейной команды можно составить из 9
нападающих, 5 защитников и 3 вратарей, если в состав команды должны войти 3 нападающих, 2 защитника и 1 вратарь?
Соображения по составлению программы
Из 9 нападающих можно выбрать троих числом способов: C93 Из 5 защитников можно выбрать двоих C52 способами. Из 3 вратарей можно выбрать одного C31 способами.
Общее число возможных способов равно произведению числа способов выбора нападающих, защитников и вратарей: C 93  C 52  C 31 .
Программа
Program Problem10;
uses WinCrt;
var
h1, h2, h3 : longint;
{----------------------------------------------------------------------------------------}
Procedure Combination(n, k : integer; var c : longint);
var
i : longint;
begin
c := 1;
for i := 1 to k do c := c*(n - k + i) div i
end;
{----------------------------------------------------------------------------------------}
begin
combination(9, 3, h1);
combination(5, 2, h2);
combination(3, 1, h3);
write('Хоккейную команду можно составить ', h1*h2*h3);
writeln(' способами');
end.
Задание 5
1. Собрание, на котором присутствуют 30 чел., в том числе две женщины, выбирает
4 чел. для работы на избирательном участке. Сколько может встретиться таких случаев,
когда в число избранных войдут обе женщины?
2. В лотерее разыгрывается 5 предметов. Всего в урне 100 билетов. Первый подошедший к урне вынимает из нее 5 билетов. Каким числом способов он может их вынуть,
чтобы три из них оказались выигрышными?
187

5. Сочетания и бином Ньютона
В математике известна формула бинома (двучлена) Ньютона. Она используется для
возведения двучлена a + b в n-ю степень. Эта формула имеет вид:
(a  b) n  C n0  a n  b0  C n1  a n1  b1 ...C n5  a n5  b5 ...C nn1  a1  bn1  C nn  a0  bn .
Числа C nk в этой формуле называются биномиальными коэффициентами. Надо отметить, что биномиальные коэффициенты образует треугольник Паскаля. Этот треугольник имеет вид:
1
1
1
1
1
1
2
3
4
5
1
1
3
6
1
10
4
10
1
5
1
1 6 15 20 15
6
1
.................................
Его можно записать иначе и сразу обозначить строки треугольника:
Номера строк.
0
1
2
3
4
5
...
n
Треугольник Паскаля.
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
..............
Cn0Cn1 ....................Cnn
Пример 11. Вычислить сумму пяти средних элементов девятой строки треугольника
Паскаля.
Всего в девятой строке треугольника Паскаля 10 элементов. Пять средних элементов
будут находиться начиная с третьего места и по 7-е место.
Эти элементы будут следующими: C92 , C93 , C94 , C95 , C96 .
Ясно, что для вычисления их суммы необходимо организовать цикл по "верхним"
индексам сочетаний. Каждый цикл надо вызывать процедуру числа сочетаний из 9 элементов по j (j - переменная цикла) и прибавлять к переменной, заведенной для суммы.
188 
Программа
Program Problem11;
uses WinCrt;
var
s, j, s1 : longint;
{----------------------------------------------------------------------------------------}
Procedure Combination(n, k : integer; var c : longint);
var
i : longint;
begin
c := 1;
for i := 1 to k do c := c*(n - k + i) div i
end;
{----------------------------------------------------------------------------------------}
begin
s := 0;
for j := 2 to 6 do
begin
combination(8, j, s1); s := s + s1
end;
writeln('Сумма пяти средних элементов 9-й строки равна ', s)
end.
Пример 12. Составить программу вывода на экран n заданных строк треугольника
Паскаля.
Понятно, что для вывода строк треугольника Паскаля на экран необходимо организовать два цикла for. Один - по числу строк, второй - по числу элементов в каждой строке.
Первый, внешний цикл, для числа строк должен быть организован от 0 до n, пусть с
переменной j1.
Второй, внутренний цикл, надо организовать от 0 до j1. Это легко объясняется тем,
что в каждой строке должно быть на 1 больше элементов, чем номер ее строки. В нулевой
строке 1 элемент, в 1-й 2 элемента, во 2-й три элемента и т. д., в n-й строке будет n + 1
элементов. Такое вызвано тем, что элементы начинают нумероваться с нуля.
Программа
Program Problem12;
uses WinCrt;
var
j, j1, n, p : longint;
{----------------------------------------------------------------------------------------}
Procedure Combination(n, k : integer; var c : longint);
var
i : longint;
begin
c := 1;
for i := 1 to k do c := c*(n - k + i) div i
end;
{----------------------------------------------------------------------------------------}
begin
189

write('Введите число строк треугольника Паскаля ');
readln(n);
writeln('Треугольник Паскаля ');
for j1 := 0 to n do
begin
for j := 0 to j1 do
begin
combination(j1, j, p);
write(p, ' ')
end;
writeln
end
end.
Задание 6
Составить программу вычисления суммы четырех средних членов десятой строки
треугольника Паскаля.
Пример 13. Из колоды, содержащей 52 карты, вынули 10 карт. Сколькими различными способами это можно сделать? В скольких случаях среди этих карт окажется хотя
бы один туз? В скольких случаях окажется ровно один туз? В скольких случаях - ровно 4
туза?
Каждый выбор карт из колоды есть выбор 10-множеств из 52 множеств. Это может
10
быть сделано C52
способами.
Найти число способов, когда среди выбранных карт есть хотя бы один туз, на первый взгляд сложнее - надо разбирать случаи, когда есть ровно один туз, ровно два туза,
ровно три туза, ровно четыре туза. Но проще найти сначала, в скольких случаях среди выбранных карт нет ни одного туза - во всех остальных случаях будет хотя бы один туз. Но
если среди выбранных карт нет ни одного туза, то выбор совершался не из 52, а из 48 карт
10
(всех карт, кроме тузов), а потому число таких выборов равно C48
. Следовательно, хотя
10
10
бы один туз будет в C52  C48 случаях.
Чтобы найти, в скольких случаях будет ровно один туз, разобьем операцию выбора
карт на две - сначала выбирают из четырех тузов один туз - это можно сделать C41 способами. А потом из оставшихся 48 карт выберем 9, что можно сделать C489 способами.
По правилу произведений получаем, что весь выбор можно сделать C41  C489 способами.
Наконец, выбор, содержащий четыре туза, можно сделать C486 способами - надо
взять 4 туза и выбрать еще 6 карт из 48.
Программа
Program Problem13;
uses WinCrt;
var
t, t1 : real;
{----------------------------------------------------------------------------------------}
Procedure Combination(n, k : integer; var c : real);
var
190 
i : longint;
begin
c := 1;
for i := 1 to k do c := c*(n - k + i)/i
end;
{----------------------------------------------------------------------------------------}
begin
combination(52, 10, t); combination(48, 10, t1);
writeln('Хотя бы один туз будет в ', t - t1:12:0, ' случаях');
combination(48, 9, t); combination(4, 1, t1);
writeln('Ровно один туз будет в ', t*t1:12:0, ' случаях');
combination(48, 6, t);
writeln('Четыре туза будет в ', t:12:0,' случаях')
end.
Обратите внимание! В программе указан тип real переменных t, t1 и в процедуре
для числа сочетаний c.
Это вызвано тем, что получаются очень большие числа и целого типа, даже longint,
"не хватает" для значения этих переменных.
Тогда результат будет выдаваться значением вещественного числа в экспоненциальной форме. Такой вывод результата не нагляден и не всегда может устраивать пользователя. Поэтому будем применять в программе форматированный вывод результата, с которым вы уже знакомы.
Таким образом, в нашей программе для вывода значений вещественных переменных
указано всего 10 позиций, а для дробной части указано 0 позиций, т. е. дробной части при
выводе числа не будет.
Задание 7
Сколькими способами можно расставить на 32 черных полях шахматной доски 12
белых и 12 черных шашек?
***
6. Для дополнительных занятий
Пример 14. Сколько всех делителей у числа 210? У числа 30030? У целого числа n?
Первая мысль, которая возникает, - это делить заданное натуральное число на простые числа и подсчитать число простых делителей. Остальные делители получаются всевозможными сочетаниями из простых делителей. Значит, возникает необходимость подсчитать число таких сочетаний, причем сочетания должны быть различными.
Но такой путь является достаточно сложным и долгим. Более простой путь решения
можно избрать, если знать следующее математическое утверждение.
Пусть p1, ..., pm - различные простые делители числа q. Если q  p11a ... pmam , где
a1 ,..., am - некоторые натуральные числа, тогда число всех делителей числа q (включая 1 и
q) равно числу сочетаний с повторениями (кортежей) показателей степеней a 1, a2, ..., am,
которое, в свою очередь, равно произведению:
(a1  1)...(am  1).
Основываясь на этом предложении составим программу.
191

Алгоритм для составления программы может быть таким:
1. Определяется число простых делителей, равных 2.
2. Число этих делителей увеличивается на 1 и присваивается переменной s.
3. Определяется число нечетных простых делителей.
4. Для каждого простого нечетного делителя устанавливается их число, увеличивается на 1 и умножается на s.
5. Результат - число всех делителей выводится на экран.
Программа
Program Problem14;
uses WinCrt;
var
s, q, m, j, n : integer;
begin
write('Введите целое число '); readln(n);
m := n;
q := 0;
s := 0;
while m mod 2 = 0 do
begin
q := q + 1;
m := m div 2
end;
s := q + 1; j := 3; q := 0;
while j <= m do
begin
if m mod j =0 then
begin
q := q + 1;
m := m div j
end;
s := s*(q + 1);
if m mod j <> 0 then j := j + 2
end;
writeln('К-во всех делителей числа ', n, ' равно ', s)
end.
Задание 8
Во скольких точках пересекаются 15 прямых линий, если четыре из них параллельны между собой и через каждую точку пересечения проходит не более двух прямых?
Библиотека часто встречающихся процедур и функций
29. Процедура размещений из n элементов по k элементов.
Procedure placement(n, k : integer; var r : longint);
var
i : integer;
192 
begin
r := 1;
for i := 1 to k do r := r*(n - i + 1)
end;
30. Процедура числа сочетаний из n элементов по k элементов.
Procedure Combination(n, k : integer; var c : longint);
var
i : longint;
begin
c := 1;
for i := 1 to k do c := c*(n - k + i) div i
end;
Упражнения
102. Определить число всех диагоналей 5-, 8 -, 12 - и 15 - угольников?
103. Из двух спортивных обществ, насчитывающих по 100 фехтовальщиков каждое,
надо выделить по одному фехтовальщику для участия в состязаниях. Сколькими способами можно это сделать?
104. У одного человека есть 7 книг по информатике, а у другого - 9 книг. Сколькими
способами они могут обменяться друг с другом по две книги?
105. Для премий на олимпиаде по информатике выделено 3 экземпляра одной книги,
два экземпляра другой и один экземпляр третьей книги. Сколькими способами могут быть
вручены премии, если в олимпиаде участвовало 20 человек и никому не дают двух книг
сразу? Та же задача, если никому не дают двух экземпляров одной и той же книги, но могут быть вручены две или три различные книги.
106. Во скольких точках пересекаются 8 прямых линий, если две из них параллельны
между собой и через каждую точку пересечения проходит не более двух прямых?
107. Вычислить сумму четырех крайних членов одиннадцатой строки треугольника
Паскаля.
108. Сколько хорд можно провести через 4 точки, лежащие на одной окружности?
109. На отрезке AB дано пять точек: C, D, E, F, K. Сколько различных отрезков,
включая отрезок AB, получилось при этом?
110. Сколькими способами группу учащихся из восьми человек можно разбить на
две подгруппы, состоящие из трех и пяти учеников.
111. Имеется 6 пар перчаток различных размеров. Сколькими способами можно выбрать из них одну перчатку на левую руку и одну перчатку на правую руку так, чтобы эти
перчатки были различных размеров?
112 Сколькими способами можно составить флаг, состоящий из трех горизонтальных полос различных цветов, если имеется материал пяти различных цветов?
113. Сколькими способами можно расставить белые фигуры (2 коня, 2 слона, 2 ладьи, ферзя и короля) на первой линии шахматной доски?
114. Найти число точек пересечения диагоналей, лежащих внутри выпуклого nугольника, если никакие три из них не пересекаются в одной точке.
193

Ответы
К заданию 1
К примеру 1
Program Task1;
uses WinCrt;
var
p : longint;
{----------------------------------------------------------------------------------------}
Procedure placement(n, k : integer; var r : longint);
var
i : integer;
begin
r := 1;
for i := 1 to k do r := r*(n - k + i)
end;
{----------------------------------------------------------------------------------------}
begin
placement(40, 3, p);
writeln('Число различных способов равно ', p)
end.
К примеру 2
Program Task1_2;
uses WinCrt;
var
s, r1, r2, r3 : longint;
{----------------------------------------------------------------------------------------}
Procedure placement(n, k : integer; var r : longint);
var
i : integer;
begin
r := 1;
for i := 1 to k do r := r*(n - k + i)
end;
{----------------------------------------------------------------------------------------}
begin
placement(5, 1, r1);
placement(5, 2, r2);
placement(5, 3, r3);
s := r1 + r2 + r3;
writeln('Не более чем трехзнач. чисел можно составить');
writeln('из цифр 1, 2, 3, 4, 5; ', s, ' способами')
end.
К заданию 2
К примеру 1
Program Task2_1;
uses WinCrt;
var
p1, p2, p : longint;
m, n
: integer;
{----------------------------------------------------------------------------------------}
194 
Procedure placement(n, k : integer; var r : longint);
var
i : integer;
begin
r := 1;
for i := 1 to k do r := r*(n - k + i)
end;
{----------------------------------------------------------------------------------------}
begin
write('Введите число всех элементов '); readln(m);
write('Введите число выбираемых элементов '); readln(n);
placement(m, n, p1);
placement(m - 1, n - 1, p2);
p := p1 - p2;
writeln('Число размещений из ', m, ' элементов по ', n, ',');
writeln('которые не начин. с первого элемента, равно ', p)
end.
К примеру 2
Program Task2_2;
uses WinCrt;
var
p1, p2, p : longint;
m, n, k : integer;
{----------------------------------------------------------------------------------------}
Procedure placement(n, k : integer; var r : longint);
var
i : integer;
begin
r := 1;
for i := 1 to k do r := r*(n - i + 1)
end;
{----------------------------------------------------------------------------------------}
begin
placement(7, 1, p1);
placement(9, 6, p2);
p := p1*p2;
writeln('Число размещений из 10 элементов по 7, ');
writeln('которые содержат 1-й элемент, равно ', p)
end.
К заданию 3
Program Task3_1;
uses WinCrt;
var
z, z1 : longint;
{----------------------------------------------------------------------------------------}
Procedure Factorial(n : integer; var f : longint);
var
i : longint;
begin
f := 1;
195

if n=0 then f := 1 else for i := 1 to n do f := f*i
end;
{----------------------------------------------------------------------------------------}
begin
Factorial(4, z); z := 2*z; Factorial(3, z1); z := z - z1;
writeln('Можно составить ', z, ' пятизначных чисел, ');
writeln('кратных 5, при помощи цифр 0, 1, 2, 3, 5')
end.
К заданию 4
Program Task4_1;
uses WinCrt;
var
s, k1, k2, k3 : longint;
{----------------------------------------------------------------------------------------}
Procedure Factorial(n : integer; var f : longint);
var
i : integer;
begin
f := 1;
if n = 0 then f := 1 else for i :=1 to n do f := f*i
end;
{----------------------------------------------------------------------------------------}
begin
Factorial(9, s); Factorial(4, k1);
Factorial(3, k2); Factorial(2, k3);
s := s div (k1*k2*k3);
writeln('Книги можно расставить ', s, ' способами')
end.
К заданию 5
К примеру 1
Program Task5_1;
uses WinCrt;
var
i : longint;
{----------------------------------------------------------------------------------------}
Procedure Combination(n, k : integer; var c : longint);
var
i : longint;
begin
c := 1;
for i := 1 to k do c := c*(n - k + i) div i
end;
{----------------------------------------------------------------------------------------}
begin
combination(28, 2, i);
write('Из 30 человек, где 2 женщины, ');
writeln('можно выбрать 4');
write('человек, в составе которых 2 женщины, ');
writeln(i,' способами')
end.
196 
К примеру 2
Program Task5_2;
uses WinCrt;
var
w, b, r : longint;
{----------------------------------------------------------------------------------------}
Procedure Combination(n, k : integer; var c : longint);
var
i : longint;
begin
c := 1;
for i := 1 to k do c := c*(n - k + i) div i
end;
{----------------------------------------------------------------------------------------}
begin
combination(5, 3, w);
combination(97, 2, b);
r := w*b;
writeln('3 выигрышных билета из 5, можно вынуть из урны');
writeln('со 100 билетами, где 5 выигрышных, ', r, ' способами')
end.
К заданию 6
Program Task6_1;
uses WinCrt;
var
s, j, s1 : longint;
{----------------------------------------------------------------------------------------}
Procedure Combination(n, k : integer; var c : longint);
var
i : longint;
begin
c := 1;
for i := 1 to k do c := c*(n - k + i) div i
end;
{----------------------------------------------------------------------------------------}
begin
s := 0;
for j := 3 to 6 do
begin
combination(9, j, s1);
s := s + s1
end;
writeln('Сумма 4-х средних членов 10-й строки: ', s)
end.
К заданию 7
Program Task7_1;
uses WinCrt;
var
t, t1 : real;
{----------------------------------------------------------------------------------------}
Procedure Combination(n, k : integer; var c : real);
197

var
i : longint;
begin
c := 1;
for i := 1 to k do c := c*(n - k + i)/i
end;
{----------------------------------------------------------------------------------------}
begin
combination(32, 12, t);
combination(20, 12, t1);
writeln('Шашки можно расставить ',t*t1:10:0,' способами')
end.
К заданию 8
Program Task8_1;
uses WinCrt;
var
s1, f1, k : longint;
{----------------------------------------------------------------------------------------}
Procedure Combination(n, k : integer; var c : longint);
var
i : longint;
begin
c := 1;
for i := 1 to k do c := c*(n - k + i) div i
end;
{----------------------------------------------------------------------------------------}
Procedure Factorial(m : integer; var f : longint);
var
j : integer;
begin
f := 1;
if m = 0 then f := 1
else for j := 1 to m do f := f*j
end;
{----------------------------------------------------------------------------------------}
begin
combination(15, 2, s1);
Factorial(3, f1); k := s1 - f1;
writeln('Прямые пересекутся в ', k, ' точках')
end.
198 
Глава 9. Элементы теории вероятностей
1. Классическое определение вероятности
Самый удобный инструмент для первого знакомства с вероятностями - игральная
кость: кубик, грани которого занумерованы числами 1, 2, ..., 6.
Поскольку кубик совершенно симметричен, мы считаем, что все шесть исходов бросания кости, т.е. выпадения цифр 1 или 2, или 3, или 4, или 5, или 6 имеют совершенно
одинаковую возможность.
Если отвлечься от реального содержания исходов испытания и интересоваться лишь
тем, произошел или не произошел тот или иной исход, мы получим понятие элементарного события, которое в теории вероятностей является основным и не определяется.
В теории вероятностей под событием мы будем понимать все то, что может произойти, но может и не произойти в результате выполнения некоторой совокупности (комплекса) условий. Такие события называются случайными событиями.
Например, случайными событиями будут:
а) попадание в цель при выстреле;
б) выпадение орла при бросании монеты;
в) наудачу взятое изделие - стандартное;
г) наудачу взятое изделие - бракованное;
д) выпадение определенного числа очков при бросании игральной кости и т.д.
Условимся события обозначать большими буквами латинского алфавита A, B, C, ... и
т. д. В дальнейшем, если данный комплекс условий многократно повторяется, мы вместо
слов "совокупность условий выполнена" будем говорить: "произведено испытание" или
"произведен опыт". Другими словами, событие мы будем рассматривать как результат
испытания.
Так в примере а) выстрел - это испытание, а попадание в цель - это событие; в примере б) подбрасывание монеты - это испытание, а выпадение орла - это событие и т. д.
Условимся буквой P обозначать вероятность события, и сформулируем определение
вероятности события.
Рассмотрим следующий пример. В урне содержится девять одинаковых, тщательно
перемешанных между собой шаров, причем четыре из них - красных, три - синие и два белые.
Поставлена задача: найти количественную оценку того, что взятый наудачу шар будет цветным. Каждый из возможных результатов испытания (извлечение шара из урны)
будем называть элементарным исходом.
В нашем примере возможны девять элементарных исходов: C1, C2 - появился белый
шар, C3, C4, C5 - появился синий шар, C6, C7, C8, C9 - появился красный шар.
Элементарные исходы, при которых событие наступает, называются благоприятствующими исходами.
В нашем примере событию: "взятый шар цветной", благоприятствуют следующие
исходы: C3, C4, C5, C6, C7, C8, C9. Поэтому вероятность того, что взятый шар окажется
цветным, равна P=7/9.
199

Вероятностью события A называется отношение числа событий, благоприятствующих событию A (m), к общему числу всех равновозможных событий (n), т. е.
m
P  ; m  n.
n
Из определения вероятности вытекают следующие ее свойства:
1. Наибольшую вероятность имеет достоверное событие, т.к. для него все элементарные исходы - благоприятствующие, т. е. P = 1.
2. Наименьшую вероятность имеет невозможное событие - P = 0.
3. Вероятность любого случайного события удовлетворяет неравенству:
0 < P < 1.
Рассмотрим примеры, для решения которых используется вероятность событий. Нас
будет интересовать применение комбинаторики к вычислению вероятностей.
Вот несколько примеров вычисления вероятностей с помощью сочетаний, размещений и перестановок.
Пример 1. Пусть мешок содержит одинаковые по размерам и материалу шары, помеченные числами от 1 до 90. Из мешка вытаскивают какие-то 5 шаров. Какова вероятность, что среди этих шаров один помечен числом 90?
Вначале приведем математическое решение задачи, затем составим алгоритм и программу на языке Паскаль, т.е. будем придерживаться традиционной схемы решения задач
на компьютере:
математическая модель - алгоритм - программа - отладка.
Событием в этой задаче является извлечение пятерки шаров (например, попали пять
шаров с числами 24, 35, 42, 64, 83).
Каждая такая пятерка является подмножеством из множества 90 элементов, поэтому
число таких подмножеств равно числу сочетаний из 90 элементов по 5:
5
- это число и будет числом всех равновозможных событий, которое обозначим n,
C90
5
n  C 90
.
Какое число событий будет благоприятствовать появлению шара с номером 90?
Допустим, что шар с номером 90 извлечен из мешка, тогда в мешке останется 89 шаров, из которых извлекаются еще 4 шара в добавление к одному с номером 90.
Извлечь 4 шара из 89 можно C894 способами, именно это число событий будет благо4
приятствовать событию - появлению шара с номером 90; m  C 89
.
Искомая вероятность будет равна: P 
m C894
 5 .
n C90
Алгоритм
1. Начало:
а) имя программы;
б) описание переменных и их типов;
в) описание процедуры вычисления числа сочетаний.
2. Выполнение операторов:
а) вызов процедуры сочетаний и вычисление числа сочетаний из 90 по 5;
б) вызов процедуры сочетаний и вычисление числа сочетаний из 89 по 4;
в) вычисление вероятности; г) вывод результата.
3. Конец.
200 
По алгоритму составим программу, используя процедуру вычисления числа сочетаний.
Программа
Program Problem1;
uses WinCrt;
var
n1, m : longint;
p
: real;
{----------------------------------------------------------------------------------------}
Procedure combination(n, k : integer; var s : longint);
var
i : longint;
begin
s := 1;
if k = 0 then s := 1
else for i := 1 to n - k do s := s*(k + i) div i
end;
{----------------------------------------------------------------------------------------}
begin
combination(90, 5, n1);
combination(89, 4, m);
p:=m/n1;
writeln('Вероятность появления шара с номером 90 равна ', p:6:4)
end.
Пример 2. Из пруда, в котором плавают 40 щук, выловили 5 щук, пометили их и пустили обратно в пруд. Во второй раз выловили 9 щук. Какова вероятность, что среди них
окажутся ровно две помеченные щуки?
Математическое решение
Выясним общее число возможных событий, т.е. сколькими способами можно выловить 9 щук из 40 плавающих. Оно равно числу сочетаний из 40 по 9:
C409 .
Сколько событий будут благоприятствовать тому, что среди этих 9 щук будут 2 помеченные.
Во-первых, две помеченные щуки можно выбрать из 5 ранее помеченных следующим количеством способов: C52 .
Во-вторых, к этим двум щукам надо добавить еще не помеченных 7 щук, которые
можно выбрать из 35 не помеченных (ведь пять щук помеченные) количеством способов:
C357 .
Значит, общее число благоприятствующих событий будет равно произведению числа способов из 5 по 2 на число способов из 35 по 7:
C52 * C357 .
Тогда, искомая вероятность равна:
C52 * C357
C409
201

Вообще, если Y является m-подмножеством в n-множестве X и из X выбираются k-подмножество A, то вероятность того, что среди выбранных элементов содержится ровно r элементов из Y, равна:
Cn * Ck  r
P  m m n m
Cn
Алгоритм составления программы достаточно прост и поэтому сразу составим программу. Она будет такой:
Программа
Program Problem2;
uses WinCrt;
var
s1, s2, s3, p : real;
{----------------------------------------------------------------------------------------}
Procedure combination(n, k : integer; var s : real);
var
i : longint;
begin
s := 1;
if k = 0 then s := 1 else for i := 1 to n - k do s := s*(k + i)/i
end;
{----------------------------------------------------------------------------------------}
begin
combination(40, 9, s1);
combination(35, 7, s2);
combination(5, 2, s3);
p := (s2*s3)/s1;
writeln('Вероятность появления двух помеченных щук равна ', p:6:4)
end.
Задание 1
Составить программы решения следующих задач.
1. Имеется 6 билетов в театр, 4 из которых на места первого ряда. Какова вероятность того, что из трех наудачу выбранных билетов два окажутся на места первого ряда?
2. Для выполнения упражнения по перетягиванию каната на уроке физкультуры 12
мальчиков должны разделиться по жребию на две группы, по 6 человек в каждой. Какова
вероятность того, что двое наиболее сильных учеников окажутся в одной группе?
Пример 3. Из коробки, содержащей карточки с буквами О, Н, К, Ь, наудачу извлекают одну карточку за другой и располагают в порядке извлечения. Какова вероятность,
что в результате получится слово "КОНЬ"?
202 
Математическое решение задачи
Число равновозможных событий, т. е. число способов, которыми можно вытащить
карточки с буквами равно числу перестановок из 4 элементов, которое, в свою очередь,
равно 4!
Число событий благоприятствующих получению слова "конь" - одно, так как только
одним способом можно получить это слово.
Вероятность получения слова "конь" равна: 1/4!
Алгоритм
В программе используем процедуру вычисления факториала числа. Дальнейшее составление программы выполните самостоятельно.
Задание 2
Составьте программу решения следующей задачи.
Из коробки, содержащей карточки с буквами А, К, О, Р, Р, Т, Т, извлекают одну за
другой буквы и располагают в порядке извлечения. Какова вероятность, что получится
слово "ТРАКТОР"?
2. Формула Бернулли
Схема повторных независимых испытаний.
Рассмотрим опыт, который состоит в том, что испытания повторяются многократно,
причем выполнены следующие условия:
1) все испытания независимы друг от друга, т.е. вероятность появления события А в
каждом из них не зависит от того, произошло или не произошло рассматриваемое событие
в других опытах;
2) каждое испытание имеет только два исхода:
а) событие А произошло; б) событие А не произошло;
3) вероятность появления события А в каждом испытании постоянна и равна p, а
следовательно, вероятность не появления события А равна q = 1 - p.
Так как в каждом из n проводимых испытаний событие А может произойти или не
произойти, то полученная схема повторных независимых испытаний содержит 2n точек.
Примерами повторных независимых испытаний с двумя исходами могут служить:
1) многократное подбрасывание монеты;
2) стрельба по цели n раз одиночными выстрелами, если нас интересует только попадание или промах;
3) массовый контроль деталей, при котором требуется только установить, какой является деталь, стандартной или нестандартной.
Некоторые задачи, описываемые по такой схеме, можно решить, используя формулу
для непосредственного подсчета вероятностей или теореме о вероятности суммы и вероятности произведения событий. Однако, проще воспользоваться формулой Бернулли.
Пусть необходимо вычислить вероятность появления события А ровно m раз при проведении n повторных независимых испытаний.
Вероятность появления события А равна p, а вероятность не появления события А
равна q, тогда вероятность появления события А ровно m раз при проведении n независимых испытаний равна:
Pn ( m)  C nm  pm  q n m (m = 0, 1, 2, ..., n).
203

Эту формулу называют формулой Бернулли.
Пример 4. Известно, что при каждом взвешивании равновозможна как положительная, так и отрицательная ошибка. Какова вероятность того, что при пяти взвешиваниях
получатся три положительные ошибки?
Математическое решение задачи
Проводится 5 независимых испытаний с двумя исходами, причем в каждом испытании p = q = 0,5. Тогда по формуле Бернулли вероятность появления трех положительных
ошибок равна:
P5 (3)  C 53  0,53  0,52 .
Алгоритм составления программы
Надо использовать не только процедуру вычисления числа сочетаний из n элементов
по m, но и процедуру вычисления степени заданного вещественного числа a. Эта процедура нам знакома из предыдущего занятия.
Программа
Program Problem4;
uses WinCrt;
var
s1
: longint;
p, st, st1 : real;
{----------------------------------------------------------------------------------------}
Procedure combination(n, k : integer; var s : longint);
var
i : longint;
begin
s := 1;
if k = 0 then s := 1
else for i := 1 to n - k do s := s*(k + i) div i
end;
{----------------------------------------------------------------------------------------}
Procedure extent(a : real; n : integer; var q : real);
var
i : integer;
begin
q := 1;
for i := 1 to n do q := a*q
end;
{----------------------------------------------------------------------------------------}
begin
combination(5, 3, s1);
extent(0.5, 3, st);
extent(0.5, 2, st1);
p := s1*st*st1;
writeln('Искомая вероятность равна ', p:6:4)
end.
204 
Задание 3
Для данного баскетболиста вероятность забросить мяч в корзину при каждом броске
равна 0,4. Что вероятнее ожидать: попадание трех мячей при четырех бросках мяча или
попадания четырех мячей при шести бросках, если броски мяча считаются независимыми?
Упражнения
115. Известно, что при каждом взвешивании равновозможна как положительная, так
и отрицательная ошибка. Какова вероятность того, что при пяти взвешиваниях получатся
три положительные ошибки?
116. Из урны, содержащей белый и черный шары, извлекают шар, записывают его
цвет и возвращают в урну. После n извлечений получаем кортеж длины n из букв Б и Ч.
Какова вероятность, что он содержит k букв Б?
117. Для данного участника игры вероятность наброса кольца на колышек равна 0,3.
Какова вероятность того, что при шести бросках кольца три кольца окажутся на колышке,
если броски кольца считать независимыми?
118. Вероятность отказа каждого прибора при испытании равна 0,4. Что вероятнее
ожидать: отказ двух приборов при четырех независимых испытаниях или трех приборов
при шести испытаниях?
119. Партия изделий содержит 5% брака. Какова вероятность того, что среди взятых
на испытание четырех изделий одно окажется бракованным?
3. Дискретные случайные величины
3.1. Дискретная случайная величина, закон распределения вероятностей
Под случайной величиной мы будем понимать величину, значение которой изменяется случайным образом от одного испытания к другому.
Определение. Величина X называется дискретной случайной величиной, если
множество ее возможных значений представляет собой конечную или бесконечную
последовательность чисел x1, x2, x3, ..., xi, ... и если каждое событие X = xi является
случайным событием, т.е. имеет определенную вероятность pi (события X = xi мы
будем называть элементарными событиями).
Примерами дискретных случайных величин являются: число X выпадений герба при
бросании двух монет; число X очков, выпадающих на верхней грани игральной кости;
число вынутых из урны белых или черных шаров, если в ней содержится определенное
число белых и черных шаров; число стандартных изделий в определенной партии изготовленных изделий и др.
Законом распределения (вероятностей) случайной величины X мы будем называть
любое правило или закон, позволяющее находить все вероятности P(X  x i )  pi (i = 1, 2,
...). Другими словами, закон распределения задает вероятность pi как функцию, определенную на множестве элементарных случайных событий X = xi.
Как и любую функцию ее можно задать различными способами: словесным описанием, таблицей, формулой, графиком.
205

Пример 1. Число X выпадений герба при бросании двух монет есть дискретная случайная величина, закон распределения вероятностей которой можно задать таблицей:
X
0
1
2
P
1/4
1/2
1/4
Если случайная величина X может принимать лишь конечное число различных значений x1, x2, x3, ..., xk, то их вероятности образуют полную группу случайных событий, и
поэтому сумма их вероятностей равна единице:
p1 + p2 + ... + pk = 1.
Если множество (различных) возможных значений величины X бесконечно, то конечную сумму в этой формуле можно заменить на бесконечный ряд сумма которого тоже
равна 1.

p
i 1
i
1
Пример 2. Число X очков, выпадающее на верхней грани правильной игральной кости, есть дискретная случайная величина с законом распределения, записанным таблицей
X
1
2
3
4
5
6
P
1/6
1/6
1/6
1/6
1/6
1/6
Этот закон распределения был установлен теоретическим путем на основе логических заключений. Но законы распределения можно устанавливать и опытным путем, что
мы и постараемся сделать, используя ЭВМ.
3.2. Определение законов распределения дискретных величин эмпирическим (опытным) путем
Как мы уже знаем, для случайного события статистическим аналогом вероятности
служит относительная частота, которую можно получить, повторяя опыт или наблюдение
n раз и регистрируя относительную частоту m/n появления события.
Тогда закон распределения вероятностей можно записать в виде следующей таблицы:
X
...
xk
x1
x2
Относительная
...
m1 n
m2 n
mk n
частота
При достаточно большом числе n повторений испытания мы вправе считать, что относительны частоты mi/n будут близки к соответствующим вероятностям pi= P(X = xi) (i =
1, 2, ..., k).
Попытаемся программными средствами Турбо Паскаля построить закон распределения числа очков, выпадающей на верхней грани игральной кости.
Составить процедуру, подсчитывающую относительные частоты выпадения очков
нетрудно. Она может быть построена так:
Procedure Game(n, num : longint; var p : real);
var
m, x, i : longint;
begin
randomize;
m := 0;
for i := 1 to n do
206 
begin
x := random(6) + 1;
if x = num then m := m + 1
end;
p := m/n
end;
Здесь, переменная n - число повторений испытания, которые задет пользователь,
num - число очков на верхней грани игральной кости, вероятность выпадения которых
надо определить, - это 1, 2, 3, 4, 5 или 6.
С помощью функции случайных чисел random(6) + 1 вырабатывается случайное целое число из промежутка [1, 6], т.е., по сути дела, моделируется выпадение числа очков
при "бросание" игральной кости.
С помощью условного оператора if x = num then m := m + 1 подсчитывается число
появления указанного числа очков при повторении испытания (бросания).
После завершения цикла, определяется относительная частота появления заданного
числа очков и выводится в переменной p.
Программа
Program Problem1;
uses WinCrt;
var
n, num : longint;
p
: real;
{----------------------------------------------------------------------------------------}
Procedure Game(n, num : longint; var p : real);
var
m, x, i : longint;
begin
randomize;
m := 0;
for i := 1 to n do
begin
x := random(6) + 1;
if x = num then m := m + 1
end;
p := m/n
end;
{----------------------------------------------------------------------------------------}
{ Основная программа }
begin
write('Введите число повторений испытания '); readln(n);
writeln('Введите число очков, вероятность');
write('выпадения которых надо найти '); readln(num);
Game(n, num, p);
writeln('Относительная частота появления события ', p:1:9);
writeln('Сравните с теоретически найденной вероятностью ', 1/6:1:9)
end.
Можно видеть, что при увеличении числа повторений испытания относительная частота приближается к теоретически предсказанной вероятностью.
207

Однако возникают много вопросов. Самый первый из них - сколько повторений испытания надо сделать, чтобы с достаточной уверенностью можно было утверждать, что
относительная частота равна вероятности? Какова степень этой "уверенности" или, выражаясь более точно, достоверности (достаточной уверенности)?
Чтобы ответить на эти и другие вопросы, надо обратиться к "числовым характеристикам распределения".
3.3. Числовые характеристики распределения
3.3.1. Математическое ожидание
Рассмотрим дискретную случайную величину X, которая принимает следующие значения x1, x2, ..., xk
с вероятностями p1, p2, ..., pk. Произведем n независимых испытаний для определения значений величины X,
и пусть каждое значение xi встретится ni раз (i = 1, 2, ..., k), так что n1 + n2 + ... + nk = n.
Этот процесс очень похож на n - кратное бросание игральной кости, а значения x1, x2, ..., xk на выпадение соответствующего числа очков (1, 2, 3, 4, 5, 6); n1, n2, n3, ..., nk - на число выпадения этого числа очков.
Среднее арифметическое из полученных значений определяется формулой:
x1n1  x 2n2 ... x k nk
n
_
x
(1)
(каждое значение надо учитывать слагаемым столько раз, сколько раз оно встретилось!).
_
x в следующем виде:
_
n
n
n
x  x1 1  x 2 2 ... x k k
n
n
n
Представим среднее арифметическое
(2)
При большом числе испытаний (n) относительные частоты ni/n будут близки соответствующим вероятностям
ni/n = pi = P(X = xi),
тогда, значение среднего арифметического x будет приблизительно равно
k
x1 p1  x 2 p2 ... x k pk   x i pi
i 1
Определение. Математическим ожиданием MX дискретной случайной величины X называется сумма
произведений всех ее возможных значений xi на их вероятности pi:
k
M X   x i pi
i 1
Если множество возможных значений дискретной случайной величины X бесконечно, то математическое ожидание будет выражаться суммой бесконечного ряда:

MX   xi pi
i 1
При этом мы всегда будем предполагать, что этот бесконечный ряд абсолютно сходится (т.е. имеет
конечную сумму), в противном случае считается, что математическое ожидание случайной величины не существует.
Математическое ожидание MX называют также средним значением случайной величины X, подчеркивая тем самым статистический смысл этого понятия (статистическим аналогом математического ожидания служит среднее арифметическое из эмпирических значений случайной величины).
Надо заметить, что в отличие от среднего арифметического значения, которое само по себе является
случайной величиной, так как зависит от числа испытаний, математическое ожидание является числом, которое связано только с законом распределения случайной величины.
Математическое ожидание MX называют еще центром распределения случайной величины X.
Это название произошло из-за аналогии с понятием центра тяжести для системы материальных точек,
расположенных на одной прямой; если на оси x в k точках с координатами x 1, x2, ..., xk сосредоточены массы
p1, p2, ..., pk, то координата xc центра тяжести системы находится по формуле
208 
k
x c   x i pi
i 1
для распределения вероятностей
k
p
i 1
1
i
и результат становится равным
k
x
i 1
i
pi
3.3.2. Свойства математического ожидания как операции осреднения
Эти свойства справедливы для математических ожиданий случайных величин вообще и дискретных
случайных величин, в частности.
1. Математическое ожидание постоянной равно этой постоянной:
MC = С.
2. Постоянный множитель C можно выносить за знак математического ожидания:
MCX = CMX.
3. Математическое ожидание суммы двух случайных величин равно сумме их математических ожиданий:
M(X + Y) = MX + MY.
Это свойство выражает линейность математического ожидания.
Математическое ожидание линейной комбинации случайных величин равно линейной комбинации их
математических ожиданий.
3.3.3. Умножение математических ожиданий
Математическое ожидание произведения независимых случайных величин равно произведению их
математических ожиданий.
M (X Y )  M X  M Y .
3.3.4. Дисперсия, среднее квадратическое отклонение и другие характеристики рассеяния
Математическое ожидание MX называют центром распределения случайной величины. Обозначим
MX = a.
Тогда рассеянием случайной величины X называется отклонение X - a этой величины от ее центра a.
Чем больше эта разность, тем больше рассеяние случайной величины от MX.
Непосредственный подсчет математического ожидания этой разности равен нулю M(X - a) = MX - a =
0, и поэтому не может быть числовой характеристикой рассеяния случайной величины.
Основной числовой характеристикой рассеяния случайной величины X служит среднее квадратическое отклонение  ( X ) , определяемое по формуле
 (X )  M (X  a) 2
Расчеты удобнее производить с подкоренным выражением, которое получило специальное название
дисперсии случайной величины X и обозначают DX:
DX = M(X - a)2
Таким образом, дисперсия есть средний квадрат отклонения случайной величины от ее центра распределения. Эта величина уже дает большие возможности для оценки случайной величины и нахождения
закона распределения ее вероятности.
Для вычисления дисперсии может быть применима формула:
DX = M(X - a)2 = M(X - C)2 - (a - C)2 ,
209

где C - любое число. В частности, при C = 0 получаем:
DX = MX2 - a2 = MX2 - (MX)2
3.3.5. Правила вычисления дисперсий и средних квадратических отклонений
1. Дисперсия постоянной величины равна нулю:
DC = 0, где C - постоянная.
2. При линейном преобразовании случайной величины X, т.е. для линейной функции
Y = kX + b,
дисперсия увеличивается в k раз, а среднее квадратическое отклонение - в |k|2 раз:
DY = D(KX + b) = k2 DX,
3. Теорема сложения дисперсий: если случайные величины X и Y независимы, то дисперсия и суммы
равна сумме их дисперсий:
D(X + Y) = DX + DY,
и следовательно,
 (X  Y )   2 (X )   2 (Y )
Следствие. Дисперсия линейной комбинации попарно независимых случайных величин X1, X2, ..., Xn
может быть вычислена по формуле
D(C1X1 + C2X2 + ... + CnXn) = C1 D2X1 + C2 D2X2 + ... + Cn D2Xn.
В частности, если все величины X1, X2, ..., Xn имеют одинаковую дисперсию
DX i   2 (i = 1, 2, ..., n),
то дисперсия их среднего арифметического равна
D
X 1  X 2 ... X n DX 1  DX 2 ... DX n  2


n
n
n2
и, следовательно, среднее квадратическое отклонение равно
 X 1  X 2 ... X n  
.



n
n

4. Некоторые законы распределения дискретных случайных величин
4.1. Биномиальное распределение
Пример 1. В урне находятся белые и черные шары. Доля белых шаров в урне равна
p. Случайное событие А заключается в том, что вынутый наугад шар будет белого цвета;
вероятность этого случайного события равна p - доле белых шаров в урне. Вынув из урны
шар, отмечают, белый он или нет, затем вынутый шар возвращают в урну и шары тщательно перемешивают. После этого снова вынимают наугад один шар и так повторяют n
раз.
Случайная величина X - это число появлений события А, т.е. белого шара, при nкратном повторении испытания. Возможными значениями величины X являются числа 0,
1, 2, ..., n (0 - белый шар не появляется ни разу при всех n испытаниях, 1 - белый шар появляется один раз, 2 - два раза, ..., n - раз, т.е. во все испытаниях).
Найдем закон распределения вероятностей случайной величины X.
Событие X = n означает появление события А во всех испытаниях; по правилу
умножения вероятностей (с учетом условия независимости испытаний) получим
210 
P (X  n)  P (A1  A2 ...An )  pn .
Аналогично находим P (X  0)  q n , где q  1  p  P (A).
Событие X = m (m = 1, 2, ..., n-1) означает, что за n испытаний случайное событие А
наступит точно m раз, а значит противоположное событие наступит n - m раз.
Вероятность того, что событие А наступит в первых m испытаниях и не наступит в
остальных n - m испытаниях, подсчитаем по правилу умножения вероятностей:
P ( A1  A2 ... A m  A m 1 ... A n )  p m q n m .
Эта вероятность не зависит от того, в каких именно испытаниях наступит событие А.
Поэтому по правилу сложения вероятностей искомая вероятность P (X  m) равна вероятности pm q n m , умноженной на число C nm способов выбора m испытаний, в которых
наступит событие A, из общего числа n испытаний:
(1)
P (X  m)  C nm pm q n m .
Здесь C nm есть число сочетаний из n элементов по m. Таким образом, мы получим
следующую таблицу распределения вероятностей:
X
0
1
...
m
...
n-1
n
q
npq
C
p
q
np
q
p
P(X=m)
...
...
Этот закон распределения называется биномиальным законом распределения вероятностей. Название связано с тем, что вероятности совпадают с членами разложения бинома (q + p)n по степеням p:
(q  p) n  q n  npq n1 ...C nm pm q n m ... pn .
Для вычисления вероятностей по формуле (1) придется не только возводить в степень, но и вычислять число сочетаний из n элементов по k. При этом могут быть достаточно большие числа, что даже установив их вещественный тип можем выйти за пределы
допустимого диапазона и получить ошибку при работе программы на Турбо Паскале.
Чтобы избежать этого, составим рекуррентное соотношение, с помощью которого можно
вычислять вероятности.
Вероятность P(X = m) равна
P (X  m)  C nm pm q n m ,
а вероятность P(X = m - 1) вычисляется по формуле
P (X  m  1)  C nm 1 pm 1 q n ( m 1) .
n
n1
m
n
m
n m
n1
n
Разделим левые и правые части этих равенств, получим:
n!
m m n m
Cn p q
P ( X  m)
m !(n  m)!
p (m  1)!(n  (m  1))! p
 m 1 m 1 n ( m 1) 
 
 
n!
P (X  m  1) C n p q
q
m !(n  m)!
q
(m  1)!(n  (m  1))!
(n  m  1) p
.
mq
Таким образом, начиная с P(X = 0), вероятности P(X = m) могут быть вычислены по
следующей рекуррентной формуле:
P ( X  m)
( n  m  1) p
(n  m  1) p

.
или P (X  m)  P (X  m  1) 
P( X  m  1)
mq
m(1  p)
Теперь, для вычисления вероятностей достаточно вычислить вероятность при m = 0,
а затем воспользоваться приведенным соотношением.
При m = 0 получаем P ( X  0)  C n0 p0 q n0  1  1  q n  (1  p) n .

211

Для возведения в натуральную степень вещественного числа составим процедуру:
{ Процедура возведения в степень }
Procedure Extent(a : real; n : integer; var e : real);
var
i : integer;
begin
e := 1;
if n = 0 then e := 1
else for i := 1 to n do e := e*a
end;
Используя эту процедуру нетрудно составить процедуру вычисления вероятностей,
используя рекуррентное соотношение. Она может быть построена как итеративно, так и
рекурсивно. Итеративная процедура приводится ниже, а рекурсивную составьте самостоятельно.
{ Рекуррентная процедура вычисления вероятности }
{биномиального закона распределения }
Procedure Recurro_binomial(n, m : integer; p : real; var pp : real);
var
i : integer;
begin
Extent(1 - p, n, pp);
for i := 1 to m do pp := (pp*(n - i + 1)*p)/(i*(1 - p))
end;
Используем эти процедуры для решения следующей задачи.
Пример 2. Из большой партии изделий берут на пробу 10 штук. Известно, что доля
нестандартных изделий во всей партии составляет 25 %. Требуется найти вероятность того, что более пяти отобранных изделий окажутся нестандартными.
Математическое решение задачи
Отбор каждого изделия будем считать испытанием, а обнаружение нестандартности
у отобранного изделия - событием А. Вероятность p события А равна доле нестандартных
изделий во всей партии, т. е. p = 0.25.
Количество X нестандартных изделий среди отобранных будет случайной величиной с биномиальным распределением вероятностей, если только изделия для пробы отбираются по схеме случайной повторной выборки (изделие после проверки возвращается
обратно в общую партию). При этом вероятности подсчитываются по формуле (1) при n =
10, p = 0.25, q = 1 - 0.25 = 0.75.
По правилу сложения вероятностей складываем вероятности при m = 6, 7, 8, 9, 10 и
находим искомую вероятность P(X > 5).
Программа
{ Биномиальный закон распределения вероятностей }
Program Problem2;
uses WinCrt;
var
212 
p, pp, sum : real;
n, i
: longint;
{----------------------------------------------------------------------------------------}
{ Процедура возведения в степень }
Procedure Extent(a : real; n : integer; var e : real);
var
i : integer;
begin
e := 1;
if n = 0 then e := 1 else for i := 1 to n do e := e*a
end;
{--------------------------------------------------------------------------------------}
{ Рекуррентная процедура вычисления вероятности }
{ биномиального закона распределения }
Procedure Recurro_binomial(n, m : integer; p : real; var pp : real);
var
i : integer;
begin
Extent(1 - p, n, pp);
for i := 1 to m do pp := (pp*(n - i + 1)*p)/(i*(1 - p))
end;
{----------------------------------------------------------------------------------------}
{ Основная программа }
begin
write('Введите число всех изделий '); readln(n);
write('Введите вероятность появления нестандартного изделия '); readln(p);
writeln('Биномиальный закон распределения вероятностей'); writeln;
for i := 0 to n do write(i:6, ' '); writeln;
writeln;
sum := 0;
for i := 0 to n do
begin
Recurro_binomial(n, i, p, pp);
write(pp:1:4, ' ');
if i >= 6 then sum := sum + pp;
end;
writeln; writeln;
writeln('Вероятность того, что более пяти отобранных');
writeln('изделий окажутся нестандартными равна ', sum:1:6)
end.
Задание
Составьте программу решения задачи, используя процедуры из предыдущего примера.
Из коробки, содержащей 5 стандартных и 3 нестандартных болта, извлекаются
наудачу болты по одному до появления стандартного. Найти закон распределения для
числа нестандартных болтов, извлеченных до появления стандартного. Рассмотреть случай, когда извлеченный нестандартный болт в коробку возвращается перед новым извлечением.

213
4.2. Числовые характеристики биномиального распределения
При подсчете математического ожидания и дисперсии биномиального распределения воспользуемся методом математической индукции.
Для упрощения расчетов представим случайную величину X - число успехов при nкратном повторении испытания - в виде суммы более простых величин. В качестве таких
величин возьмем индикаторы успехов: 1 - "успех", 0 - "неудача". Таким образом, индикатор Xk принимает значение 1 в случае успеха при k-ом повторении испытания и значение
0 в противном случае. Поэтому
X = X1 + X2 + ... + Xn,
так как эта сумма состоит из единиц и нулей, причем число единиц в ней равно числу
успехов при n-кратном повторении испытания.
Отсюда следует, что
MX = MX1 + MX2 + ... + MXn
(в силу свойства линейности математического ожидания).
Так как биномиальное распределение связано с последовательностью независимых
испытаний по схеме Бернулли, то индикаторы X1, X2, ..., Xn - независимые случайны величины; поэтому можно применить и теорему сложения дисперсий, что дает
DX = DX1 + DX2 + ... + DXn.
По условию задачи вероятность успеха при каждом повторном испытании одна и та
же и равна p. Поэтому распределение вероятностей любого индикатора Xk дается таблицей
1
0
Xk
p
q
где q = 1 - p; k = 1, 2, ..., n.
Непосредственный подсчет математического ожидания и дисперсии индикатора Xk
приводит нас к следующему результату:
MX k  1 p  0  q  p;
2
DX k  M (X k  p)  (1  p) 2 p  (0  p) 2 q  q2 p  p2 q  pq.
Следовательно, для биномиального распределения имеем
MX = np,
DX = npq,
и, значит,
 (X )  npq.
Математическое ожидание и дисперсия относительной частоты X/n:
X 1
M
 M X  p,
n n
X
1
pq
pq
X
D  2 DX 
,
  
.
 n
n n
n
n
Мы пришли к очень важному, применительно к программированию, выводу.
Математическое ожидание относительной частоты случайного события есть вероятность этого события. Формула среднего квадратического отклонения показывает, что рассеяние относительной частоты уменьшается с увеличением числа повторений испытания.
Пример 3. Составить закон распределения случайной величины, выражающей число
попаданий в мишень при четырех выстрелах, если вероятность попадания при каждом выстреле равна 0.3. Вычислить ее математическое ожидание и дисперсию по формулам для
характеристик случайной величины, распределенной по биномиальному закону.
214 
{ Биномиальный закон распределения вероятностей }
Program Problem3;
uses WinCrt;
var
p, pp, mx, dx : real;
n, i
: integer;
{-------------------------------------------------------------------------------------}
{ Процедура возведения в степень }
Procedure Extent(a : real; n : integer; var e : real);
var
i : integer;
begin
e := 1;
if n = 0 then e := 1
else for i := 1 to n do e := e*a
end;
{---------------------------------------------------------------------------------------}
{ Рекуррентная процедура вычисления биномиального закона }
{ распределения }
Procedure Recurro_binomial(n, m : integer; p : real; var pp : real);
var
i : integer;
begin
Extent(1 - p, n, pp);
for i := 1 to m do pp := (pp*(n - i + 1)*p)/(i*(1 - p))
end;
{----------------------------------------------------------------------------------------}
{ Основная программа }
begin
write('Введите число выстрелов '); readln(n);
write('Введите вероятность попадания при каждом выстреле '); readln(p);
writeln('Биномиальный закон распределения вероятностей');
writeln;
for i := 0 to n do write(i:6, ' '); writeln;
for i := 0 to n do
begin
Recurro_binomial(n, i, p, pp);
write(pp:1:4, ' ')
end;
writeln;
mx := n*p;
dx := n*p*(1 - p);
writeln('Математическое ожидание, т.е. число попаданий ');
writeln('при четырех выстрелах ', mx:4:6);
writeln('Дисперсия равна ', dx:4:6);
writeln('Среднее квадратическое отклонение ', sqrt(dx):4:6)
end.
Пример 4. Длительной проверкой установлено, что из каждых 10 приборов 8 - точных. Составить таблицу распределения числа точных приборов из взятых наудачу пяти
приборов. Вычислить математическое ожидание и дисперсию.
215

{ Биномиальный закон распределения вероятностей }
Program Problem4;
uses WinCrt;
var
p, pp, mx, dx : real;
n, i
: integer;
{----------------------------------------------------------------------------------------}
{ Процедура возведения в степень }
Procedure Extent(a : real; n : integer; var e : real);
var
i : integer;
begin
e := 1;
if n = 0 then e := 1
else for i := 1 to n do e := e*a
end;
{----------------------------------------------------------------------------------------}
{ Рекуррентная процедура вычисления биномиального закона }
{ распределения }
Procedure Recurro_binomial(n, m : integer; p : real; var pp : real);
var
i : integer;
begin
Extent(1 - p, n, pp);
for i := 1 to m do pp := (pp*(n - i + 1)*p)/(i*(1 - p))
end;
{---------------------------------------------------------------------------------------}
{ Основная программа }
begin
write('Введите число взятых наудачу приборов '); readln(n);
p := 0.8;
writeln('Вероятность появления точного прибора ', p:1:6);
writeln('Биномиальный закон распределения вероятностей');
writeln;
for i := 0 to n do write(i:6, ' '); writeln; writeln;
for i := 0 to n do
begin
Recurro_binomial(n, i, p, pp);
write(pp:1:4, ' ')
end;
writeln; writeln;
mx := n*p; dx := n*p*(1 - p);
writeln('Математическое ожидание, т.е. число точных ');
writeln('приборов из взятых наудачу пяти ', mx:4:6);
writeln('Дисперсия равна ', dx:4:6);
writeln('Среднее квадратич. отклонение ', sqrt(dx):4:6)
end.
216 
Задание 4
1. Вероятность рождения мальчика равна 0.515. Как велика вероятность того, что из
10 наугад выбранных рождений будет 6 мальчиков? Предположение независимости может
считаться выполненным.
2. Необходимо исследовать 1000 проб руды. Вероятность промышленного содержания металла в каждой пробе равна 0.2. Определить математическое ожидание и среднее
квадратическое отклонение числа проб с промышленным содержанием металла.
4.3. Наиболее вероятное число событий биномиального распределения
Из распределения вероятностей по биномиальному закону видно, что вероятность
вначале возрастает, а затем убывает. Естественно возникает вопрос о числе событий,
имеющей наибольшую вероятность.
P (X  m  1) (n  m) p n  m p


 ,
(m  0, 1, 2, ..., n  1).
P ( X  m)
(m  1)q m  1 q
При возрастании m от 0 до n-1 это отношение убывает от np/q до p/nq. Если np > q и
nq > p, то рассматриваемое отношение переходит от значений больших 1, к значениям,
меньшим 1. А это означает, что вероятность P(X = m) сначала возрастает, а затем убывает.
И лишь в крайних случаях, когда np < q или nq < p, вероятности P(X = m) изменяются монотонно.
Во всех случаях наиболее вероятное значение X = m0 находится из неравенств
n  (m0  1) p
n  m0 p
  1,
  1,
m0
q
m0  1 q
откуда следует, что np  p  1  m0  np  p.
Этому неравенству удовлетворяет только одно целое число m0 , если только np + p не
является целым числом: в последнем случае имеются два наиболее вероятных значения X
= np + p - 1 и X = np + p. В частном случае, когда произведение np - целое число, оно и является наиболее вероятным значением величины X.
Пример 5. Вероятность появления бракованной детали равна 0.02. Определить
наиболее вероятное число годных деталей в партии из 1000 штук, а также математическое
ожидание и дисперсию случайной величины.
{ Биномиальный закон распределения вероятностей }
{ Наиболее вероятное число исходов }
Program Problem5;
uses WinCrt;
var
p, m1, m2, mx, dx : real;
n, m0
: integer;
{----------------------------------------------------------------------------------------}
{ Основная программа }
begin
write('Введите общее число деталей в партии '); readln(n);
write('Введите вероятность появления бракованной детали ');
readln(p);
m1 := n*p + p - 1; m2 := n*p + p;
217

if (m1 = m2) and (m1 = trunc(m1)) then m0 := trunc(m1)
else m0 := trunc(m2);
mx := n*p; dx := n*p*(1 - p);
write('Наиболее вероятное число бракованных деталей ');
writeln(' в этой партии равно ', m0);
writeln('Математическое ожидание равно ', mx:1:6);
writeln('Дисперсия случайной величины равна ', dx:1:6)
end.
Из этого примера видно, что наиболее вероятное число появление событий при малой вероятности и большом числе исходов - m0, равно математическому ожиданию дискретной случайной величины mx (m0 = mx).
Задание 5
1. Найти наивероятнейшее число нестандартных деталей среди 500 деталей, если вероятность для каждой быть нестандартной равна 0.035.
2. Всхожесть семян составляет в среднем 80%. Найти наивероятнейшее число всхожих семян среди девяти семян.
4.4. Гипергеометрическое распределение
Биномиальное распределение вероятностей точно только при условии отбора изделий по схеме случайной повторной выборки.
На практике изделия для проверки отбираются по схеме случайной бесповторной
выборки, т.е. изделия из партии отбираются каждый раз случайно, но отобранные изделия
не возвращаются в партию.
Схема случайной бесповторной выборки приводит уже не к биномиальному, а к так
называемому гипергеометрическому закону распределения.
Пример 1. В урне находится N шаров, из которых M белых. Пусть один за другим
без возврата (или одновременно, что одно и то же) вынимается n  M) шаров. Тогда вероятность того, что среди этих вынутых n шаров будет m белых шаров, равна
PN , M (n, m) 
C Mm C NnmM
(k  0, 1, ,..., n).
C Nn
Для вычисления гипергеометрических вероятностей найдем рекуррентную формулу
для вычислений. Здесь тем более могут получаться очень большие числа.
Логика рассуждений будет такая же, как и при нахождении подобной формулы для
биномиального закона распределения.
C mm C NnmM
PN , M (n, m)
C Nn
m
n m
m 1

 C Nn(Mm 1) ,
m 1 n ( m 1)  C M  C N  M : C M
C M C N M
PN , M (n, m  1)
C Nn
отсюда получаем:


P(X  m)  P(X  m  1)  C Mm  C NnmM : C Mm1  C Nn(Mm1)  .
Для начального значения, при m = 0, находим:
218 
P (X  0) 

C M0  C Nn  M
C
n
N

(N  M  n  1)(N  M  n  2)... (N  M  n  n)

(N  n  1)(N  n  2)... (N  n  n)
(N  M  n  1)(N  M  n  2)... (N  M )
.
(N  n  1)(N  n  2)... N
Надо заметить, что если число изделий в партии велико, а число отобранных изделий составляет весьма малую долю всей партии, поэтому расчет вероятностей по формулам биномиального распределения дает достаточно хорошие приближения.
{ Гипергеометрический закон распределения вероятностей }
Program Problem1;
uses WinCrt;
var
p, s, s1, s2
: real;
nn, mm, n, m, k : longint;
{----------------------------------------------------------------------------------------}
{ Процедура вычисления числа сочетаний из n элементов по k }
Procedure Combination(n, k : integer; var s : real);
var
i : longint;
begin
s := 1;
if k = 0 then s := 1
else for i := 1 to n - k do s := s*(k + i)/i
end;
{----------------------------------------------------------------------------------------}
{ Основная программа }
begin
write('Введите число всех шаров в урне '); readln(nn);
write('Введите число всех белых шаров в урне '); readln(mm);
write('Введите число извлекаемых из урны шаров ');
readln(n);
writeln('Введите число белых шаров, вероятность');
write('получения которых Вы хотите найти '); readln(k);
Combination(nn, n, s); Combination(mm, k, s1);
Combination(nn - mm, n - k, s2);
p := (s1*s2)/s;
writeln;
writeln('Вероятность того, что среди вынутых ', n);
writeln('шаров будет ', k, ' белых шаров, равна ', p:1:6)
end.
Математическое ожидание гипергеометрического распределения равно
n
C mm C NnmM
M
MX  m
n .
n
N
CN
m0
Дисперсия определятся формулой:
N n M  M
DX 
n 1   .
N 1 N 
N
219

Задание 6
Партия содержит 1000 изделий, из них 250 изделий нестандартных; из партии случайно, но без возврата, отбирают 10 изделий. Требуется найти вероятность того, что более
пяти отобранных изделий окажутся нестандартными. Определить математическое ожидание и дисперсию случайной величины.
5. Распределение Пуассона
Распределение Пуассона часто встречается в задачах, связанных с потоком событий.
Под потоком событий будем понимать последовательность событий, наступающих
одно за другим в случайные моменты времени.
Примерами могут быть: поток вызовов на телефонной станции, поток заявок в системе массового обслуживания, последовательность распада частиц некоторого количества радия и др.
Простейший поток событий характеризуется следующими свойствами:
а) вероятность наступления того или иного числа событий за любой промежуток
времени зависит только от длительности этого промежутка (а не от начала отсчета);
б) указанная вероятность не зависит от того, какое число событий наступило до
начала рассматриваемого промежутка времени (отсутствие последствия);
в) за малый промежуток времени вероятность наступления одного события приближенно пропорциональна длительности такого промежутка, а вероятностью наступления
двух или более событий можно пренебречь.
В качестве случайной величины X мы рассмотрим число событий простейшего потока, наступающих за фиксированный промежуток времени t.
Значениями этой случайной величины могут быть любые целые числа
m = 0, 1, 2, 3, ...
Соответствующие вероятности обозначим через
pm (t)  P(X  m);
pm(t) есть вероятность того, что за фиксированный промежуток m времени t наступит ровно m событий простейшего потока.
Пусть t  0 - малая величина, сравним вероятности pm (t) и pm (t  t).
В результате несложных математических рассуждений приходим, что в пределе при
t  0 мы получаем для искомой вероятности p0(t) линейное дифференциальное уравнение первого порядка
p0' (t )  p0 (t ).
Решая это уравнение при начальном условии p0(0) = 1, находим искомую вероятность отсутствия событий за промежуток времени t;
p0 (t )  e t .
Нетрудно получить и общую формулу для расчета вероятностей pm (t ) при
m  1, 2, 3, ... .
(t ) m  t
e
(m  0, 1, 2, ... ).
m!
Эта формула и дает закон распределения случайной величины X - числа событий
простейшего потока, наступающих за промежуток времени t.
pm (t ) 
220 
Статистический смысл параметра  в этой формуле можно выяснить, если единицу
времени разбить на N равных промежутков t 1 N , тогда получаем приближенное равенство p1 (t ) 

,
N
мы можем толковать его правую часть как относительную частоту наступления некоторого события простейшего потока за промежуток времени наблюдения t ; это означает, что
 есть среднее число наступления таких событий за единицу времени.
Обычно произведение  t обозначают a и записывают закон распределения в виде
am a
P ( X  m) 
e
(m  0, 1, 2, ... ).
m!
Этот закон распределения и называют законом распределения Пуассона или законом
редких явлений.
Замечание. При малых значениях p и больших значениях n распределение Пуассона
может быть применено в качестве приближенного значения для биномиального распределения.
Обозначим np = a, тогда p = a/n, q = 1 - p = 1 - a/n. Разложим вероятность
P (X  m)  C nm pm q n m в степенной ряд по степеням 1/n; ограничиваясь членами порядка
1/n, получим
m
n m
n(n  1)... (n  m  1)  a  a
m m n m
Cn p q


  1  
 n  n
m!

a
1
a2 
a m  1   2  m  1 ( n m) n1 n  a m  m(m  1)
  a n  ma 2  ...


... e 

1   1   ... 1 
e
1 

m !  n  n 
n 
m! 
2n


a2

 am
ma

m
 1

a 
m(m  1)
a 2 m(m  1) 
 a 
2
 . . ..

. . . e 1 
. . . 
e  a 1   ma 

1 
 
m!
2n
n
2
2
 m!

 n





Первый член этого разложения дает как раз вероятность в распределении Пуассона,
откуда и следует приближенная (асимптотическая) формула
am a
m m n m
Cn p q

e
(a  np);
m!
второй член в скобках может служить для оценки относительной погрешности этой приближенной формулы:
1
a2 m(m  1) 
 ma 


n
2
2

Составим процедуру для вычисления вероятности по формуле Пуассона.
Для этого выведем рекуррентную формулу для вычисления вероятности:
am a
e
P (X  m)
a
m!

 ,
m 1
P (X  m  1)
m
a
e a
(m  1)!
отсюда получаем соотношение:
a
P (X  m)  P (X  m  1)  .
m
0
a a
При m = 0, получим P (X  0) 
e  e a .
0!
221

Пользуясь этими двумя формулами легко составить функцию вычисления вероятностей по формуле Пуассона.
{ Функция вычисления вероятности распределения Пуассона }
Function PS(m : integer; a : real) : real;
var
i : integer;
pp : real;
begin
pp := exp(-a);
if m = 0 then pp := exp(-a)
else for i := 1 to m do pp := pp*a/i;
PS := pp
end;
Составим программы решения следующих задач, используя эту процедуру.
Пример 1. Вероятность изделию быть бракованным равна 0.05. Найти вероятность
того, что среди 1000 изделий 40 бракованных.
{ Распределение Пуассона }
Program Problem1;
uses WinCrt;
var
n, m : longint;
p, a : real;
{----------------------------------------------------------------------------------------}
{ Функция вычисления вероятности распределения Пуассона }
Function PS(m : integer; a : real) : real;
var
i : integer;
pp : real;
begin
pp := exp(-a);
if m = 0 then pp := exp(-a)
else for i := 1 to m do pp := pp*a/i;
PS := pp
end;
{----------------------------------------------------------------------------------------}
{ Основная программа }
begin
write('Введите общее число изделий '); readln(n);
write('Введите вероятность изделия быть бракованным '); readln(p);
writeln('Введите число бракованных изделий, вероятность ');
write('появления которых Вы находите '); readln(m);
a := n*p;
writeln('Вероятность ', m, ' бракованных изделий в ');
writeln('партии из ',n, ' изделий равна ', PS(m, a):1:6)
end.
222 
Пример 2. Вероятность сбить самолет одним выстрелом из винтовки в определенных условиях равна 0.003. Определить вероятность поражения самолета, если сделано по
одному выстрелу из 300 винтовок.
{ Распределение Пуассона }
Program Problem2;
uses WinCrt;
var
n : longint;
p, a : real;
{----------------------------------------------------------------------------------------}
{ Функция вычисления вероятности распределения Пуассона }
Function PS(m : integer; a : real) : real;
var
i : integer;
pp : real;
begin
pp := exp(-a);
if m = 0 then pp := exp(-a)
else for i := 1 to m do pp := pp*a/i;
PS := pp
end;
{---------------------------------------------------------------------------------------}
begin
write('Введите общее число выстрелов '); readln(n);
write('Введите вероятность попадания при одном выстр. ');
readln(p);
a := n*p;
write('Вероятность поражения самолета при ');
writeln(n, ' выстрелах равна ', (1 - PS(0, a)):1:6)
end.
Пример 3. Прибор состоит из 200 деталей, каждая из которых за время t может выйти из строя с вероятностью p = 0.01.
Найти вероятность того, что за время t выйдут из строя: а) 3 детали; б) не более трех
деталей; в) не менее двух деталей; г) от двух до четырех деталей включительно.
{ Распределение Пуассона }
Program Problem3;
uses WinCrt;
var
n, m, i
: longint;
p, a, Sum : real;
{----------------------------------------------------------------------------------------}
{ Функция вычисления вероятности распределения Пуассона }
Function PS(m : integer; a : real) : real;
var
i : integer;
pp : real;
begin
pp := exp(-a);
if m = 0 then pp := exp(-a)
223

else for i := 1 to m do pp := pp*a/i;
PS := pp
end;
{----------------------------------------------------------------------------------------}
begin
write('Введите общее число деталей '); readln(n);
write('Введите вероятность выхода изделия из строя '); readln(p);
writeln('Введите число изделий, вероятность выхода из');
write('строя которых Вы находите '); readln(m); writeln;
a := n*p;
Sum := 0;
for i := 0 to 3 do Sum := Sum + PS(i, a);
writeln('Вероятность того, что за указанное время ');
write('выйдет из строя ',m, ' изделия равна ');
writeln(PS(m, a):1:6);
writeln('не более ',m, ' изделий ', Sum:1:6);
Sum := 0;
for i := 0 to 1 do Sum := Sum + PS(i, a);
Sum := 1 - Sum;
writeln('выйдет из строя не менее 2 деталей ', Sum:1:6);
Sum := 0;
for i := 2 to 4 do Sum := Sum + PS(i, a);
writeln('выйдет из строя от 2 до 4 деталей ', Sum:1:6)
end.
Пример 4. При контролируемом производственном процессе доля брака равна 0.02.
При обнаружении в партии из 150 изделий более 5 бракованных изделий вся партия задерживается. Определить вероятность того, что партия будет принята.
{ Распределение Пуассона }
Program Problem4;
uses WinCrt;
var
n, m, i : longint;
p, a, PP : real;
{----------------------------------------------------------------------------------------}
{ Процедура вычисления вероятности распределения Пуассона }
Function PS(m : integer; a : real) : real;
var
i : integer;
pp : real;
begin
pp := exp(-a);
if m = 0 then pp := exp(-a)
else for i := 1 to m do pp := pp*a/i;
PS := pp
end;
{----------------------------------------------------------------------------------------}
{ Основная программа }
begin
write('Введите общее число изделий '); readln(n);
write('Введите вероятность изделия быть бракованным ');
224 
readln(p);
writeln('Введите число бракованных изделий, вероятность ');
write('появления которых Вы находите '); readln(m);
a := n*p;
PP := 0;
for i := 0 to m do PP := PP + PS(i, a);
writeln('Вероятность ', m, ' бракованных изделий в ');
writeln('партии из ',n, ' изделий равна ', PP:1:6)
end.
Задание 7
Торговая база получила 1000 радиоприемников. Вероятность повреждения каждого
из них в пути 0.0001. Найти вероятность того, что в пути будет повреждено 4 приемника.
5.1. Числовые характеристики распределения Пуассона
Математическое ожидание


am a
a m 1
a
MX  m
e  e  a 
 e a  a  ea  a.
m!
m0
m 1 (m  1)!
Это позволяет выяснить статистический смысл параметра a в распределении Пуассона: параметр a есть среднее число событий, наступающих за время t в простейшем потоке. Отсюда можно дать статистическое толкование параметру  : так как  = a/t, то параметр  есть среднее число событий, наступающих за единицу времени.
Дисперсия равна DX  M X 2  (M X ) 2  (a2  a)  a2  a.
Дисперсия совпадает с математическим ожиданием. Эти результаты хорошо согласуются с представлением распределения Пуассона в качестве предельного для биномиального распределения при p  0, n  , np  a.
Действительно, при этом MX = np = a, DX = npq = a(1 - p)  a.
5.2. Предельная теорема Муавра-Лапласа
Если вероятность p наступления события A в каждом испытании постоянна и отлична от нуля и единицы, а число испытаний достаточно велико, то вероятность P(X = m) того, что в n независимых испытаниях событие A наступит m раз, приближенно равна:
1
P ( X  m) 
f (x ).
npq
Значение функции Гаусса f (x ) 
1
e

x2
2
,
а
x
m  np
.
2
npq
Используя эти формулы можно составить процедуру вычисления вероятности по локальной формуле Муавра-Лапласа, но прежде составим функцию вычисляющую значение
функции Гаусса:
{ Функция Гаусса }
Function G(x : real) : real;
begin
G := exp(-sqr(x)/2)/sqrt(2*Pi)
end;
225

Тогда процедура вычисления вероятности по локальной формуле Муавра-Лапласа
будет следующей:
{ Процедура нахожд. вероятн. по локальной форм. Муавра-Лапласа }
Procedure Local_Laplace(n, m : longint; p : real; var pp : real);
var
x : real;
begin
x := (m - n*p)/sqrt(n*p*(1 - p));
pp := G(x)/sqrt(n*p*(1 - p))
end;
Пример 1. Вероятность того, что данное изделие будет забраковано, равна 0.2.
Определить вероятность того, что в партии из 400 изделий будет 104 бракованных.
{ Использование локальной формулы Лапласа для вычисл. вероятн. }
Program Problem1;
uses WinCrt;
var
n, m : longint;
p, pp : real;
{----------------------------------------------------------------------------------------}
{ Функция Гаусса }
Function G(x : real) : real;
begin
G := exp(-sqr(x)/2)/sqrt(2*Pi)
end;
{----------------------------------------------------------------------------------------}
{ Процедура нахожд. вероятн. по локальной форм. Муавра-Лапласа }
Procedure Local_Laplace(n, m : longint; p : real; var pp : real);
var
x : real;
begin
x := (m - n*p)/sqrt(n*p*(1 - p));
pp := G(x)/sqrt(n*p*(1 - p))
end;
{----------------------------------------------------------------------------------------}
{ Основная программа }
begin
write('Введите число изделий в партии '); readln(n);
write('Введите вероятность быть бракованным для одного ');
write('изделия '); readln(p);
write('Введите число изделий, вероятность которых надо ');
write('найти '); readln(m);
Local_Laplace(n, m, p, pp);
writeln('Вероятность появления ', m, ' бракованных');
writeln('изделий среди ', n, ' изделий равна ', pp:1:6)
end.
Пример 2. Появление бракованного изделия в партии оценивается вероятностью 0.5.
Взято 100 изделий. Какова должна быть частота бракованных изделий, чтобы вероятность
такой частоты была бы равна 0.0782?
226 
{ Использование локальной формулы Лапласа для вычисл. вероятн. }
Program Problem2;
uses WinCrt;
var
n, m : longint;
p, Pm : real;
{----------------------------------------------------------------------------------------}
{ Функция Гаусса }
Function G(x : real) : real;
begin
G := exp(-sqr(x)/2)/sqrt(2*Pi)
end;
{----------------------------------------------------------------------------------------}
{ Процедура определения частоты. 1-й способ. }
Procedure Frequency1(n : longint; p, Pm : real;
var m : longint);
var
x, pp : real;
begin
m := -1;
repeat
m := m + 1;
x := (m - n*p)/sqrt(n*p*(1 - p));
pp := G(x)/sqrt(n*p*(1 - p))
until pp >= Pm
end;
{----------------------------------------------------------------------------------------}
{ Основная программа }
begin
write('Введите общее число изделий в партии '); readln(n);
write('Введите вероятность быть бракованным для одного ');
write('изделия '); readln(p);
write('Введите вероятность получения частоты '); readln(Pm);
Frequency1(n, p, Pm, m);
writeln('Частота бракованных изделий равна ', m)
end.
Пример 3. По данным длительной проверки качества выпускаемых запчастей брак
составляет 13%. Определить вероятность того, что в непроверенной партии из 200 запчастей пригодных будет а) 174; б) от 150 до 180.
Program Problem3a;
uses WinCrt;
var
n, m
: longint;
p, q, pp : real;
{----------------------------------------------------------------------------------------}
{ Функция Гаусса }
Function G(x : real) : real;
begin
G := exp(-sqr(x)/2)/sqrt(2*Pi)
end;
227

{----------------------------------------------------------------------------------------}
{ Локальная формула Муавра-Лапласа }
Procedure Local_Laplace(n, m : longint; p : real; var pp : real);
var
x : real;
begin
x := (m - n*p)/sqrt(n*p*(1 - p));
pp := G(x)/sqrt(n*p*(1 - p))
end;
{----------------------------------------------------------------------------------------}
begin
write('Введите число запчастей в партии '); readln(n);
write('Введите вероятность быть бракованным для одной запчасти ');
readln(q);
write('Введите число запчастей, вероятность которых надо ');
write('найти '); readln(m);
p := 1 - q;
Local_Laplace(n, m, p, pp);
writeln('Вероятность появления ', m, ' пригодных');
writeln('запчастей среди ', n, ' изделий равна ', pp:1:6)
end.
Задания 8
1. Найти вероятность того, что при 600 выстрелах мишень будет поражена 250 раз,
если вероятность поражения мишени при дном выстреле равна 0.4.
2. Вероятность рождения мальчика равна 0.515. Найти вероятность того, что из 200
новорожденных будет 95 девочек.
3. Найти вероятность того, что из 500 посеянных семян не взойдет 130, если всхожесть семян оценивается вероятностью 0.75.
5.3. Интегральная формула Муавра-Лапласа
Если вероятность p наступления события в каждом испытании постоянна и отлична
от нуля и единицы, а число испытаний достаточно велико, то вероятность того, в n независимых испытаниях событие состоится число раз, заключенное в границах от [m1; m2]
(m1 < m2), приближенно равна:
1
Pn (m1  m  m 2 )  (x 2 )  (x 1 ),
2
m1  np
m 2  np
,
x2 
,
где x 1 
npq
npq
2
x

t2
2
 e dt - функция Лапласа.
2 0
Для применения этой формулы, необходимо составить функцию вычисления интеа (x ) 
грала
x
e
0

t2
2
dt
228 
Для его вычисления воспользуемся способом разложения подынтегральной функции в ряд
с последующим интегрированием членов полученного степенного ряда с заданной степенью точности. (Подробнее об этом см. в главе "Числовые и функциональные ряды", "Приближенное вычисление интегралов с помощью рядов").
При составлении функции учтем то обстоятельство, что при x  5 значение функции
равно 1, а при x  5 значение функции равно -1.
В результате получим следующую функцию для вычисления интегральной функции
Муавра-Лаплапса:
{ Рекуррентная функция вычисления интеграла вероятностей }
{ Пределы интегрирования от 0 до x. Функция Муавра-Лапласа }
Function FF(x : real) : real;
var
n : integer;
u, I : real;
begin
if x >= 5
then FF := 1
else if x <= -5
then FF := -1
else
begin
u := x; n := 0; I := 0;
repeat
I := I + u;
n := n + 1;
u := -u*(x*x*(2*n - 1)/(2*n*(2*n + 1)) )
until abs(u) < 0.00001;
FF := 2*I/sqrt(2*Pi)
end
end;
Используя эту функцию, составим процедуру для вычисления вероятности появления события из заданного интервала [m1; m2].
{ Процедура вычисл. вероятн. наст. событ. из промеж. [m1; m2] }
Procedure Interval(n, m1, m2 : longint; p : real; var PP : real);
var
x1, x2 : real;
begin
x1 := (m1 - n*p)/sqrt(n*p*(1 - p));
x2 := (m2 - n*p)/sqrt(n*p*(1 - p));
PP := (FF(x2) - FF(x1))/2
end;
Дальнейшее не представляет труда. Полученные функция и процедура дают нам
возможность решать довольной большой круг задач определения вероятности наступления событий. Разберем это на конкретных примерах.
Пример 1. Вероятность некоторого события равна 0.4 в каждом из n испытаний.
Найти вероятность того, что число появления события при n = 1500 будет заключено
между 1) 570 и 630; 2) 600 и 660; 3) 620 и 680; 4) 580 и 640.
229

Программа
{ Применение интегральной формулы Муавра-Лапласа }
Program Problem1;
uses WinCrt;
var
n, m1, m2 : longint;
p, PP
: real;
{----------------------------------------------------------------------------------------}
{ Рекуррентная функция вычисления интеграла вероятностей }
{ Пределы интегрирования от 0 до x. Функция Муавра-Лапласа }
Function FF(x : real) : real;
var
n : integer; u, I : real;
begin
if x >= 5
then FF := 1
else if x <= -5
then FF := -1
else
begin
u := x; n := 0; I := 0;
repeat
I := I + u; n := n + 1;
u := -u*(x*x*(2*n - 1)/(2*n*(2*n + 1)))
until abs(u) < 0.00001;
FF := 2*I/sqrt(2*Pi)
end
end;
{----------------------------------------------------------------------------------------}
{ Процедура вычисл. вероятн. наст. событ. из промеж. [m1; m2] }
Procedure Interval(n, m1, m2 : longint; p : real; var PP : real);
var
x1, x2 : real;
begin
x1 := (m1 - n*p)/sqrt(n*p*(1 - p));
x2 := (m2 - n*p)/sqrt(n*p*(1 - p));
PP := (FF(x2) - FF(x1))/2
end;
{----------------------------------------------------------------------------------------}
{ Основная программа. Число бракованных изделий из промежутка }
begin
write('Введите общее число изделий '); readln(n);
write('Введите вероятность наступление одного события '); readln(p);
write('Введите левую границу промежутка '); readln(m1);
write('Введите правую границу промежутка '); readln(m2);
Interval(n, m1, m2, p, PP);
writeln('Вероятность того, что число бракованных изделий');
write('находится в промежутке [',m1, '; ', m2, '] равна ');
writeln(PP:1:8)
end.
230 
Пример 2. Число отклонений от установленного стандарта при обточке металлических болванок составляет, по данным длительной проверки ОТК, 0.12 от взятого количества продукции. Определить вероятность того, что из взятых наудачу 25 образцов не менее 21 будет соответствовать стандарту.
Программа
{ Применение интегральной формулы Муавра-Лапласа }
Program Problem2;
uses WinCrt;
var
n
: longint;
e, p, PP : real;
{----------------------------------------------------------------------------------------}
{ Рекуррентная функция вычисления интеграла вероятностей }
{ Пределы интегрирования от 0 до x. Функция Муавра-Лапласа }
Function FF(x : real) : real;
var
n : integer;
u, I : real;
begin
if x >= 5
then FF := 1
else if x <= -5
then FF := -1
else
begin
u := x; n := 0; I := 0;
repeat
I := I + u; n := n + 1;
u := -u*(x*x*(2*n - 1)/(2*n*(2*n + 1)))
until abs(u) < 0.00001;
FF := 2*I/sqrt(2*Pi)
end
end;
{----------------------------------------------------------------------------------------}
{ Процедура вычисления вероятности частоты наступления событий }
{ при заданной точности e }
Procedure Probability(n : longint; p, e : real; var PP : real);
var
x : real;
begin
x := e/sqrt(n*p*(1 - p));
PP := FF(x)
end;
{----------------------------------------------------------------------------------------}
{ Основная программа }
begin
write('Введите вероятность приема одного сообщения ');
write('без ошибок '); readln(p);
write('Введите общее число сообщений '); readln(n);
writeln('На сколько число принятых сообщений должно быть');
231

write('безошибочным, (точность) прин. сообщ. '); readln(e);
Probability(n, p, e, PP);
writeln('Искомая вероятность равна ', PP:1:8)
end.
Пример 3. На склад поступает продукция трех фабрик, причем изделия первой фабрики на складе составляют 30%, второй - 32% и третьей - 38%. В продукции первой фабрики 60% изделий высшего сорта, второй - 25%, третьей - 50%. Найти вероятность того,
что среди 300 наудачу взятых со склада изделий число изделий высшего сорта заключено
между 130 и 170.
В этой задаче прежде надо определить вероятность получения числа изделий высшего сорта со всех трех фабрик, т.е. их наличие на складе.
Пусть H1 - изделие сделано на 1-ой фабрике, P(H1) = 0.3; H2 - изделие сделано на 2ой фабрике, P(H2) = 0.32; H3 - изделие сделано на 3-ей фабрике, P(H3) = 0.38.
A - изделие высшего сорта. В задаче даны PHi(A), i = 1, 2, 3;
3
p  P ( A)   P (H i )PH i ( A).
i 1
{ Применение интегральной формулы Муавра-Лапласа }
Program Problem3;
uses WinCrt;
var
n, m1, m2 : longint;
p, PP
: real;
{----------------------------------------------------------------------------------------}
{ Рекуррентная функция вычисления интеграла вероятностей }
{ Пределы интегрирования от 0 до x. Функция Муавра-Лапласа }
Function FF(x : real) : real;
var
n : integer;
u, I : real;
begin
if x >= 5
then FF := 1
else if x <= -5
then FF := -1
else
begin
u := x; n := 0; I := 0;
repeat
I := I + u;
n := n + 1;
u := -u*(x*x*(2*n - 1)/(2*n*(2*n + 1)))
until abs(u) < 0.00001;
FF := 2*I/sqrt(2*Pi)
end
end;
{----------------------------------------------------------------------------------------}
{ Процедура вычисл. вероятн. наст. событ. из промеж. [m1; m2] }
Procedure Interval(n, m1, m2 : longint; p : real; var PP : real);
var
x1, x2 : real;
232 
begin
x1 := (m1 - n*p)/sqrt(n*p*(1 - p));
x2 := (m2 - n*p)/sqrt(n*p*(1 - p));
PP := (FF(x2) - FF(x1))/2
end;
{----------------------------------------------------------------------------------------}
begin
write('Введите общее число изделий '); readln(n);
p := 0.6*0.3 + 0.25*0.32 + 0.5*0.38;
write('Введите левую границу промежутка '); readln(m1);
write('Введите правую границу промежутка '); readln(m2);
Interval(n, m1, m2, p, PP);
writeln('Вероятность того, что число изделий высшего');
write('сорта находится в [',m1, '; ', m2, '] равна '); writeln(PP:1:8)
end.
Задание 9
1. Вероятность изделия быть бракованным равна 0.05. Найти вероятность того, что
среди 1000 изделий число бракованных находится в промежутке от 40 до 70 включительно.
2. По данным длительной проверке качества выпускаемых запчастей брак составляет
13%. Определить вероятность того, что в непроверенной партии из 200 запчастей пригодных будет от 150 до 180.
Следствие 1. Если вероятность p наступления события A в каждом испытании постоянна и отлична от нуля и единицы, а число испытаний достаточно велико, то вероятность того. что в n независимых испытаниях абсолютная величина отклонения числа
наступления события A от произведения np не превзойдет положительного числа e, приближенно равна:
 e 
,
(2)
Pn (| m  np|  e)  

npq


(m - частота появления события A в n испытаниях).
Составим процедуру вычисления вероятности отклонения частоты m от заданного
произведения np. Она будет достаточно простой и мы дадим ее без дополнительных пояснений.
{ Процедура вычисления вероятности частоты наступления событий }
{ при заданной точности e - отклонении частоты от np }
Procedure Probability(n : longint; p, e : real; var PP : real);
var
x : real;
begin
x := e/sqrt(n*p*(1 - p));
PP := FF(x)
end;
Пример 4. Вероятность приема сообщения без ошибок равна 0.5. Найти вероятность
того, что из 100 независимо друг от друга принятых сообщений число принятых без ошибок будет отличаться от 50 по абсолютной величине не более, чем на 5.
233

{ Применение интегральной формулы Муавра-Лапласа }
Program Problem4;
uses WinCrt;
var
n
: longint;
e, p, PP : real;
{----------------------------------------------------------------------------------------}
{ Рекуррентная функция вычисления интеграла вероятностей }
{ Пределы интегрирования от 0 до x. Функция Муавра-Лапласа }
Function FF(x : real) : real;
var
n : integer;
u, I : real;
begin
if x > 5
then FF := 1
else if x < -5
then FF := -1
else
begin
u := x; n := 0; I := 0;
repeat
I := I + u;
n := n + 1;
u := -u*(x*x*(2*n - 1)/(2*n*(2*n + 1)))
until abs(u) < 0.00001;
FF := 2*I/sqrt(2*Pi)
end
end;
{----------------------------------------------------------------------------------------}
{ Процедура вычисления вероятности отклонения частости от }
{ вероятности в одном испытании (по абсолютной величине) }
{ Частость появления события А в n испытаниях }
Procedure ProbabilityLap(n : longint; p, e : real; var PP : real);
var
x : real;
begin
x := e*sqrt(n/(p*(1 - p)));
PP := FF(x)
end;
{----------------------------------------------------------------------------------------}
{ Основная программа }
begin
write('Введите вероятность того, что деталь ');
write('нестандартная '); readln(p);
write('Введите число случайно отобранных деталей '); readln(n);
write('Укажите отклонение частости от вероятности '); readln(e);
ProbabilityLap(n, p, e, PP);
writeln('Искомая вероятность равна ', PP:1:8)
end.
234 
Очень часто приходится сталкиваться с задачей определения числа испытаний n при
заданном значении отклонения e абсолютной величины частоты m от произведения np,
вероятности p наступления события в одном испытании и гарантированной вероятности
PP.
Из формулы (2) найдем значение n - числа появления событий при указанных выше
условиях:
2
 e 1
n 
.
 x  pq
Для составления процедуры вычисления числа n, эту формулу удобнее представить в
виде следующих двух формул, последовательное применение которых дает довольно точный результат:
e
n
,
n  n2 .
x pq
На Паскале последовательное вычисления значения n запишется следующими двумя
строками:
n := round(e/(x*sqrt(p*(1 - p))) + 0.5);
n := sqr(n)
Найти x можно из условия FF (x )  PP, зная значение гарантированной вероятности
и определив значение функции FF.
Это можно сделать с помощью цикла repeat ... until ..., предварительно установив
шаг для вычисления x равным eps.
x := 0;
repeat
x := x + eps
until FF(x) >= PP;
Составьте самостоятельно процедуру вычисления значения n и выполните следующее задание.
Задание 10
Автоматическая штамповка клемм для предохранителей дает 10% отклонений от
принятого стандарта. Сколько клемм необходимо взять наудачу, чтобы вероятность того,
что среди них число стандартных отличается от np по модулю меньше чем на 10, была
равна 0.9586?
Вероятность отклонения абсолютной величины частости m/n от вероятности p в
каждом из n независимых испытаний, при заданном значении отклонения e.
Из формулы (2) нетрудно получить формулу для вычисления вероятности отклонения абсолютной величины частости m/n в n независимых испытаниях от вероятности p
наступления события в каждом испытании

m
n 

  e
n
 pq 
m
 частость появления события A в n испытаниях) или можно использовать две форn
мулы:
(
235

 n
.
x  e
 pq 
Составим процедуру вычисления такой вероятности.
m
 (x ),
n
(3)
{ Процедура вычисления вероятности отклонения частости от }
{ вероятности в одном испытании (по абсолютной величине) }
Procedure ProbabilityLap(n : longint; p, e : real; var PP : real);
var
x : real;
begin
x := e*sqrt(n/(p*(1 - p)));
PP := FF(x)
end;
Пример 5. Вероятность того, что деталь нестандартная, равна 0.2. Определить вероятность того, что среди случайно отобранных 2500 деталей частость появления нестандартных деталей отклонится от вероятности по абсолютной величине не более, чем на
0.004.
{ Применение интегральной формулы Муавра-Лапласа }
Program Problem5;
uses WinCrt;
var
n
: longint;
e, q, PP : real;
{----------------------------------------------------------------------------------------}
{ Рекуррентная функция вычисления интеграла вероятностей }
{ Пределы интегрирования от 0 до x. Функция Муавра-Лапласа }
Function FF(x : real) : real;
var
n : integer;
u, I : real;
begin
if x >= 5
then FF := 1
else if x <= -5
then FF := -1
else
begin
u := x; n := 0; I := ;
repeat
I := I + u;
n := n + 1;
u := -u*(x*x*(2*n - 1)/(2*n*(2*n + 1)))
until abs(u) < 0.00001;
FF := 2*I/sqrt(2*Pi)
end
end;
{----------------------------------------------------------------------------------------}
{ Процедура нахождения числа испытаний n, чтобы обеспечить }
{ заданную вероятность отклонения частоты от np }
236 
Procedure Number(p, e, PP : real; var n : longint);
var
x : real;
begin
x := 0;
repeat
x := x + 0.01
until FF(x) >= PP;
n := round(e/(x*sqrt(p*(1 - p))) + 0.5);
n := sqr(n)
end;
{----------------------------------------------------------------------------------------}
{ Основная программа }
begin
write('Введите вероятность отклонения клемм от принято');
write('го стандарта '); readln(q);
write('Введите число стандартных клемм отличающихся ');
write('от np (по модулю) '); readln(e);
write('Укажите вероятность этого отклонения '); readln(PP);
Number(q, e, PP, n);
writeln('Искомое число взятых наудачу клемм равно ', n)
end.
Из формулы (3) найдем отклонение e - частости m/n от вероятности в каждом испытании - p, при заданном числе независимых испытаний - n и гарантированной вероятности
PP:
pq
e x
.
n
Процедуру вычисления отклонения частости составьте самостоятельно.
Задание 11
Вероятность события в каждом испытании равна 0.4. Произведено 800 независимых
испытаний. Найти границу отклонения частости появления события от вероятности его
появления в отдельном испытании, которую можно гарантировать с вероятностью, равной
0.95.
Вычисление значения числа испытаний n по заданному отклонению e частости m/n
от вероятности p в каждом из независимых испытаний и вероятности этого отклонения
(гарантированной вероятности).
Пример 6. Вероятность некоторого события хотят установить статистически. Для
этого проводят некоторое количество испытаний, и частость появления события принимают за его вероятность. Сколько надо произвести испытаний, чтобы с вероятностью 0.97
можно гарантировать, что вероятность события в одном испытании будет отличаться от
частости полученной из опыта, не более, чем на 0.01?
Одна из идей, которыми можно воспользоваться и реализовать программными средствами, состоит в том, чтобы непосредственным подбором числа n найти его искомое значение.
237

Для этого достаточно организовать цикл, завершающим условием которого является: FF (x )  PP, где PP - гарантированная вероятность, FF(x) - значение функции МуавраЛапласа.
Чтобы найти x нужно воспользоваться соотношением: x := 2*e*sqrt(n).
В результате можно составить следующую процедуру:
{ Процедура вычисления числа испытаний при заданной гарантиро- }
{ ванной вероятности и заданной точности частости }
Procedure NumberExperiment(e, PP : real; var n : longint);
var
x : real;
begin
n := 0;
repeat
n := n + 1;
x := 2*e*sqrt(n)
until FF(x) >= PP
end;
Основываясь на этой процедуре составьте программу.
Второй способ нахождения значения n уже применялся нами в других программах.
Он основывается на следующей процедуре:
{ Процедура вычисления числа испытаний при заданной гарантиро- }
{ ванной вероятности и заданной точности частости }
Procedure Number2(e, PP : real; var n : longint);
var
x : real;
begin
x := 0;
repeat
x := x + 0.0001
until FF(x) >= PP;
n := trunc(sqr(x/(2*e)))
end;
{ Применение интегральной формулы Муавра-Лапласа }
Program Problem6;
uses WinCrt;
var
n
: longint; e, pp : real;
{----------------------------------------------------------------------------------------}
{ Рекуррентная функция вычисления интеграла вероятностей }
{ Пределы интегрирования от 0 до x. Функция Муавра-Лапласа }
Function FF(x : real) : real;
var
n : integer; u, I : real;
begin
if x >= 5
then FF := 1
else if x <= -5
238 
then FF := -1
else
begin
u := x; n := 0; I := 0;
repeat
I := I + u; n := n + 1;
u := -u*(x*x*(2*n - 1)/(2*n*(2*n + 1)))
until abs(u) < 0.00001;
FF := 2*I/sqrt(2*Pi)
end
end;
{----------------------------------------------------------------------------------------}
{ Процедура вычисления числа испытаний при заданной гарантиро- }
{ ванной вероятности и заданной точности частости
}
Procedure NumberExperiment(e, PP : real; var n : longint);
var
x : real;
begin
n := 0;
repeat
n := n + 1;
x := 2*e*sqrt(n)
until FF(x) >= PP
end;
{----------------------------------------------------------------------------------------}
{ Основная программа }
begin
write('Введите гарантированную вероятность '); readln(PP);
write('Введите точность вычисления частости '); readln(e);
NumberExperiment(e, PP, n);
writeln('Число испытаний равно ', n );
writeln('С точностью до ', e:1:8)
end.
Задание 12
Для решения следующей задачи примените два способа.
Сколько необходимо произвести испытаний для того, чтобы с вероятностью 0.9948
можно было бы ожидать, что частость наступления события А будет отличаться по абсолютной величине от его постоянной для всех испытаний вероятности, равной 3/5, не менее, чем на 0.01?
Упражнения
120. Автоматическая штамповка металлических клемм для соединительных пластин
дает 20% отклонений от принятого стандарта. Определить вероятность наличия в партии
из 600 клемм от 100 до 125 клемм, не соответствующих стандарту.
121. Нужно исследовать 400 проб руды. Вероятность промышленного содержания
металла в каждой пробе одинакова и равна 0.8. Определить вероятность того, что число
проб с промышленным содержанием металла будет заключено между 290 и 350.
239

122. В каких границах находится частость наступления события при 1200 независимых испытаниях, вероятность отклонения которой от числа 2/3 равна 0.9857? Каковы границы частоты наступления события в этой задаче?
123. При массовом выпуске некоторой продукции бывает в среднем 4% брака. Определить вероятность того, что в партии из 625 единиц продукции отклонение частости от
указанного процента брака будет менее, чем 0.02.
124. Средний процент нарушений работы кинескопа телевизора в течение гарантийного срока равен 12%. Вычислить вероятность того, что из 200 телевизоров более 160 выдержат гарантийный срок.
125. Посажено 600 семян кукурузы с вероятностью прорастания 0.9 для каждого семени. Найти границу абсолютной величины отклонения частости взошедших семян от вероятности p = 0.9, если эта граница должна быть гарантирована с вероятностью P = 0.995.
126. было посажено 400 деревьев. Найти вероятность того, что число принявшихся
деревьев больше 250, если вероятность, что отдельное дерево приживется, равна 0.8.
127. В некоторой местности имеется 3 % больных малярией. Производится обследование 500 человек. С какой вероятностью среди обследованных окажется 3  0,5% больных малярией?
Вероятность некоторого события равна 0.4 в каждом из n испытаний. Найти вероятность того, что:
а) Частость наступления события при n = 1500 отклонится от p = 0.4 в ту или другую
сторону меньше, чем на 0.02.
б) Число появления события будет заключено между 1) 570 и 630; 2) 600 и 660; 3)
620 и 680; 4) 580 и 640.
в) В каких граница находится та частость события при n = 1200, вероятность отклонения которой от p = 2/3 равна 0.985? В каких границах заключено число появления событий в этой задаче?
г) Сколько необходимо произвести испытаний, чтобы вероятность того, что отклонение частости m/n от вероятности p = 3/8 в ту или другую сторону будет меньше, чем на
0.01, была равна 0.995?
6. Двумерные случайные величины
Вначале введем понятие независимости случайных величин.
Дискретные случайные величины X и Y называются независимыми, если независимы при любых i и I события X = xi и Y = yI (i = 1, 2, ..., n; I = 1, 2, ..., m).
Понятие независимости случайных величин распространяется на любое конечное
число случайных величин.
Случайные величины, которые рассматривались ранее, называются еще одномерными. В теории вероятностей рассматриваются еще, так называемые двумерные, трехмерные
и вообще многомерные случайные величины.
Определение. Случайная величина называется двумерной, если все значения ее имеют вид (xi, yI), причем 1  i  n, 1  I  m.
Событие, заключающееся в том, что двумерная величина примет значение (x i,yi),
означает произведение двух событий:
1) случайная величина X примет xi;
240 
2) случайная величина Y примет значение yi. Вероятность этого события обозначим
piI: piI = = P(X = xi; Y = yi). Совокупность всех пар значений (x i, yi) и соответствующих им
вероятностей piI составляет закон распределения двумерной случайной величины.
Обозначим через P (Y=yi) условную вероятность того, что X=xi случайная величина
Y примет значение yi относительно события, состоящего в том, что случайная величина X
приняла значение xi. По определению эту вероятность считаем равной:
P(X  x i ; Y  y j )
PX  x i (Y  y j ) 
.
P(X  x i )
Пример 1. Известны результаты стрельб для 2-х стрелков при 3-ч выстрелах: X число попаданий первого стрелка, Y - число попаданий второго стрелка.
xi
pi
1
0.3
2
0.2
3
0.5
yi
pi
1
0.1
2
0.6
3
0.3
Найти среднее число попаданий каждого стрелка и среднее квадратическое отклонение этих случайных величин.
Решение
По формуле для вычисления математического ожидания M (X )   x i pi определяi
ем математическое ожидание каждого стрелка M(X) и M(Y). Математические ожидания
показывают среднее число попаданий каждого стрелка и сравним их.
По формуле D(X )    x i  M (x ) pi находим дисперсии, а затем и средние квадра2
i
тические отклонения. Сравнив их, выясним который из стрелков получает лучший результат при стрельбе.
Программа
Program Two_dimensional_aleatory_variables1;
uses WinCrt;
Const
k = 10;
Type
t = array[1..k] of real;
var
Px , Py : t;
MX, MY, DX, DY : real;
n, m, i
: integer;
begin
write('Введите число выстрелов первого стрелка '); readln(n);
write('Введите число выстрелов второго стрелка '); readln(m);
writeln;
writeln('Вводите вероятности попаданий первого стрелка');
MX := 0;
for i := 1 to n do
begin
write('Вероятность попадания при ', i, '-ом выстреле ');
readln(px[i]);
241

MX := MX + i*px[i]
end;
writeln('Среднее число попаданий первого стрелка ', MX:2:4);
writeln;
writeln('Вводите вероятности попаданий второго стрелка');
MY := 0;
for i := 1 to m do
begin
write('Вероятность попадания при ', i, '-ом выстреле ');
readln(py[i]);
MY := MY + i*py[i]
end;
writeln('Среднее число попаданий второго стрелка ', MY:2:4);
writeln;
DX := 0;
for i := 1 to n do DX := DX + sqr(i - MX)*px[i];
DY := 0;
for i := 1 to m do DY := DY + sqr(i - MY)*py[i];
if sqrt(DX) < sqrt(DY)
then writeln('Первый стрелок стреляет лучше')
else
if sqrt(DX) > sqrt(DY)
then writeln('Второй стрелок стреляет лучше')
else writeln('Стрелки стреляют с одинаковой точностью')
end.
Пример 2. По данным задачи 1 найти ряд распределения случайной величины Z,
равной а) X + Y; б) 5X + 3Y.
Определить в каждом случае математическое ожидание и дисперсию.
Решение
а) Для нахождения значений Z можно воспользоваться матрицей сумм значений X и
Y.
X\Y
1
2
3
1
(1 + 1)
(1 + 2)
(1 + 3)
2
(2 + 1)
(2 + 2)
(2 + 3)
3
(3 + 1)
(3 + 2)
(3 + 3)
Выполнить такое сложение можно с помощью следующей процедуры:
Procedure Sum(n, m : integer; x, y : t; var zz : t);
var
i, I, k : integer;
begin
k := 0;
for i := 1 to n do
for I := 1 to m do
begin
k := k + 1;
zz[k] := x[i] + y[I]
end
end;
242 
В результате получаются значения Z, среди которых будут повторяющиеся (2, 3, 3,
3, 4, 5, 4, 5, 6).
Необходимо выбрать только различные значения суммы Z = X + Y.
Это можно выполнить с помощью процедуры, которая детально рассматривается в
главе "Задачи с массивами чисел".
{ Процедура отбора различных элементов в массиве Z }
Procedure Different(n, m : integer; var z : t; var k : integer);
label 1;
var
i, I : integer;
begin
k := 0;
for i := 1 to n*m do
begin
for I := 1 to k do
if z[i] = z[I] then goto 1;
k := k + 1;
z[k] := z[i];
1: end
end;
Получим, для нашего примера, что Z может принимать значения 2, 3, 4, 5, 6. Определим вероятности, учитывая, что X и Y независимы.
P(Z = 2) = P(X = 1)P(Y = 1);
P(Z = 3) = P(X = 1)P(Y = 2) + P(X = 2)P(Y = 1);
P(Z = 4) = P(X = 1)P(Y = 3) + P(X = 2)P(Y = 2) + P(X = 3)P(Y = 1);
P(Z = 5) = P(X = 2)P(Y = 3) + P(X = 3)P(Y = 2);
P(Z = 6) = P(X = 3)P(Y = 3);
В результате получаем ряд распределения вероятностей.
Используя свойства математического ожидания и дисперсии и результаты примера
1, находим M(Z) = M(X) + M(Y); D(Z) = D(X) + D(Y).
Программа
Program Problem2;
uses WinCrt;
const
p = 20;
type
t = array[1..p] of integer;
tt = array[1..p] of real;
var
x, y, z
: t;
px, py, pz
: tt;
n, m, k, n1, i
: integer;
MX, MY, MZ, DX, DY, DZ : real;
{-----------------------------------------------------------------------------------------------}
{ Процедура суммирования значений X и Y и получение Z }
Procedure Sum(n, m : integer; x, y : t; var z : t);
243

var
i, I, k : integer;
begin
k := 0;
for i := 1 to n do
for I := 1 to m do
begin
k := k + 1;
z[k] := x[i] + y[I]
end
end;
{-----------------------------------------------------------------------------------------------}
{ Процедура отбора различных элементов в массиве Z }
Procedure Different(n, m : integer; var z : t; var k : integer);
label 1;
var
i, I : integer;
begin
k := 0;
for i := 1 to n*m do
begin
for I := 1 to k do
if z[i] = z[I] then goto 1;
k := k + 1;
z[k] := z[i];
1: end
end;
{-----------------------------------------------------------------------------------------------}
{ Основная программа }
begin
write('Введите число стрелков '); readln(n1);
write('Введите число выстрелов, сделанных первым стрелком '); readln(n);
write('Введите число выстрелов, сделанных вторым стрелком '); readln(m);
writeln('Вводите вероятности попаданий первого стрелка');
MX := 0;
for i := 1 to n do
begin
write('Вероятность попадания при ', i, '-ом выстреле ');
readln(px[i]);
MX := MX + i*px[i]
end;
writeln('Среднее число попаданий первого стрелка ', MX:2:4);
writeln;
writeln('Вводите вероятности попаданий второго стрелка');
MY := 0;
for i := 1 to m do
begin
write('Вероятность попадания при ', i, '-ом выстреле ');
readln(py[i]);
MY := MY + i*py[i]
end;
writeln('Среднее число попаданий второго стрелка ', MY:2:4);
244 
writeln;
DX := 0;
for i := 1 to n do DX := DX + sqr(i - MX)*px[i];
DY := 0;
for i := 1 to m do DY := DY + sqr(i - MY)*py[i];
MZ := MX + MY; DZ := DX + DY;
writeln('Искомый ряд распределения вероятностей');
for i := 1 to n do
begin
x[i] := i;
y[i] := i
end;
Sum(n, m , x, y, z);
Different(n, m, z, k);
for i := 1 to k do write(z[i]:4, ' '); writeln;
pz[1] := px[1]*py[1];
pz[2] := px[1]*py[2] + px[2]*py[1];
pz[3] := px[1]*py[3] + px[2]*py[2] + px[3]*py[1];
pz[4] := px[2]*py[3] + px[3]*py[2];
pz[5] := px[3]*py[3];
for i := 1 to k do write(pz[i]:2:2, ' '); writeln;
writeln('Математическое ожидание равно ', MZ:2:4);
writeln('Дисперсия равна ', DZ:2:4)
end.
Задание 13
1. Составьте программу решения задачи 2(б).
2. Независимые случайные величины X и Y заданы рядами распределения:
xi
pi
1
0.1
2
0.3
3
0.6
yi
pi
-2
0.6
-1
0.3
0
0.1
Составить закон распределения их суммы и произведения. Найти M(X), M(Y), M(X +
Y), M(XY), D(X), D(Y), D(XY), D(X + Y) и проверить справедливость равенств M(X + Y)
= M(X) + M(Y), M(XY) = M(X)M(Y), D(X + Y) = D(X) + D(Y).
7. Функция распределения случайной величины
7.1. Новый способ задания случайной величины
Ранее дискретная случайная величина характеризовалась законом распределения.
Однако задать случайную величину можно и иначе, например так называемой функцией
распределения
Этот способ является более общим, чем предыдущий и приводит нас к рассмотрению непрерывных случайных величин.
Рассмотрим событие, состоящее в том, что случайная величина Y примет какоенибудь значение, меньшее произвольного числа x, т.е. Y < x. Оно имеет определенную вероятность. Обозначим ее F(x) = P(Y < x).
245

При изменении x будут, вообще говоря, меняться вероятности P (Y  x )  F (x ). Поэтому F(x) можно рассматривать как функцию переменной величины x. Случайная величина будет полностью охарактеризована, если для каждого x (  x  ) будет известно значение функции.
Определение. Функцией распределения случайной величины Y называется функция
F(x), выражающая для каждого x вероятность того, что случайная величина Y примет
какое-нибудь значение, меньшее x.
Будем говорить, что известно распределение случайной величины Y, если известна
ее функция распределения F(x).
Пример 1. Пусть вероятность изготовления нестандартного изделия при некотором
технологическом процессе равна 0.06. Контролер берет из партии изделие и сразу проверяет его качество. Если оно оказывается нестандартным, дальнейшие испытания прекращаются, а партия задерживается. Если же изделие оказывается стандартным, контролер
берет следующее и т. д., но всего проверяет не более пяти изделий. Найти функцию распределения случайной величины Y - числа проверяемых изделий.
Решение
Нам известен закон распределения случайной величины:
Число проверяемых изделий
Вероятность
1
0.06
2
0.056
3
0.053
4
0.050
5
0.0781
Случайная величина Y не принимает значений, меньших 1. Следовательно, если x 
1, то событие Y < x невозможно, а вероятность его равна нулю. Поэтому равна нулю
функция распределения случайной величины Y для всех значений x  1. Для всех x, удовлетворяющих двойному неравенству 1 < x  2, функция F(x) равна 0.06. Действительно,
если, например, x = 1.2, то F(x) означает вероятность события Y  12
. . Но случайная величина Y принимает значение, меньшее 1.2, в одном случае: значение 1 с вероятностью 0.06.
Покажем, что для всех x, удовлетворяющих двойному неравенству 2 < x  3,
F (x )  0.06  0.056  0116
. . Пусть, например, x  3. Тогда F(3) выражает вероятность события Y  3. Это возможно в двух случаях: или случайная величина Y принимает значение 1 (с вероятностью 0.06), или 2 (с вероятностью 0.056). Применяя теорему сложения
вероятностей, мы и получим указанное значение функции F(x) при x = 3.
Аналогичными рассуждениями можно найти функцию распределения. Запишем ее в
виде таблицы.
x
x1
1<x  2
2<x  3
3<x  4
4<x  5
x>5
F(x)
0
0.06
0.116
0.169
0.219
1
Программа
В программе обратите внимание на организацию форматированного вывода результата.
Program Function1; { Функция распределения случайной величины }
uses WinCrt;
Const
246 
k = 20;
type
t = array[1..k] of integer;
tt = array[0..k] of real;
var
x : t;
p : tt;
i, n : integer; pp : real;
begin
write('Введите общее число проверяемых изделий '); readln(n);
writeln('Вводите число изделий и соответствующие им вероятности');
for i := 1 to n do
begin
write('Число изделий '); readln(x[i]);
write('Соответствующая вероятность '); readln(p[i])
end;
for i := 1 to n do write(x[i]:2+i*2); writeln;
for i := 1 to n do write(p[i]:1:4, ' ':3); writeln;
writeln('Значения аргумента функции распределения x');
write('(-бесконечность; ', x[1], ']; ':4);
for i := 1 to n-1 do write('(', x[i], '; ',x[i + 1], ']', '; ':3);
write('(', x[n], '; +бесконечность)'); writeln;
write('
',0:4, ' '); pp := 0;
for i := 1 to n - 1 do
begin
pp := pp + p[i];
write(pp:1:4, ' ':2)
end;
write(0:4, ' '); writeln
end.
Пример 2. Прибор состоит из двух блоков, вероятность безотказной работы каждого
из которых в течение времени t  T равна 0.5. Найти ряд распределения для числа блоков,
работающих в момент t = T. Найти функцию распределения F(x) дискретной случайной
величины X, заданной в задаче.
Решение
Ряд распределения вероятностей
xi
pi
0
1/4
1
1/2
2
1/4
Если x <= 0, то F(x) = 0, так как нет ни одного значения X левее нуля.
Если 0 < x  1, то в промежуток (   ; x) попадает одно значение X = 0, следовательно, F(x) = P(X = 0) = 1/4 = 0.25.
Если 1 < x  2, то в промежуток (   , x) попадает два значения X = 0 и X=1, следовательно, F(x) = P(X = 0) + P(X =1) = 3/4 = 0.75.
Если 2 < x <   , то в промежуток (   , x) попадают все значения X т.е. X=0, X = 1,
X = 2. Следовательно, F(x) = 1.
Получаем
247

если
x  0,
 0,
0.25, если 0  x  1,

F (x )  
0. 75, если 1  x  2,
 1,
если
x  2.
Свойства функции распределения: F(   ) = 0; F(   ) = 1; 0  F(x)  1; если
x 2  x 1 , то F (x 2 )  F (x 1 ).
Другими словами, функция распределения любой случайной величины является неубывающей функцией, а изменяется она от 0 до 1 при изменении x от   до   .
Программа
Program Function2; { Функция распределения случайной величины }
uses WinCrt;
Const
k = 20;
type
t = array[1..k] of integer;
tt = array[0..k] of real;
var
x
: t;
p, pp : tt;
i, n, m : integer;
xx
: real;
{----------------------------------------------------------------------------------------}
{ Функция распределения случайной величины }
Function Fx(xx : real) : real;
begin
if xx <= 0
then Fx := 0
else
if (xx > 0) and (xx <= 1)
then Fx := pp[1]
else
if (xx > 1) and (xx <= 2)
then Fx := pp[2]
else Fx := 1
end;
{----------------------------------------------------------------------------------------}
begin
write('Введите общее число испытаний '); readln(n);
writeln('Вводите число испытаний и соответствующие им вероятности');
for i := 1 to n do
begin
write('Число испытаний '); readln(x[i]);
write('Соответствующая вероятность '); readln(p[i])
end;
for i := 1 to n do write(x[i]:3+i*2); writeln;
for i := 1 to n do write(p[i]:1:4, ' ':3); writeln;
writeln('Значения аргумента функции распределения x');
write('(-бесконечность; ', x[1], ']; ':4);
for i := 1 to n-1 do write('(', x[i], '; ',x[i + 1], ']', '; ':4);
248 
write('(', x[n], '; +бесконечность)'); writeln;
write('
',0:4, ' ');
m := 0; pp[0] := 0;
for i := 1 to n - 1 do
begin
m := m + 1;
pp[m] := pp[m-1] + p[i];
write(pp[m]:1:4, ' ':2)
end;
write(1:4, ' '); writeln;
writeln('Функция распределения случайной величины');
write('Введите значение аргумента '); readln(xx);
writeln('Значение функции F(x) равно ' , Fx(xx):1:4)
end.
Вероятность попадания случайной величины X в промежуток [a; b) определяется
формулой
P (a  X  b)  F (b)  F (a).
(1)
Задание 14
1. Зная формулу (1) дополните программу примера 2 так, чтобы можно было бы вычислять вероятность попадания случайной величины в заданный промежуток [a; b].
2. Пользуясь функцией распределения случайной величины Y - числа проверяемых
изделий (пример 1), вычислить вероятность того, что при приеме партии будет проверено
от одного до трех изделий. (Составьте программу).
8. Непрерывные случайные величины
Определение 1. Случайная величина называется непрерывной, если функция ее распределения всюду непрерывна, а производная функции распределения непрерывна во всех
точках, за исключением, быть может, конечного числа точек на любом конечном интервале.
Примерами непрерывных случайных величин могут служить: диаметр детали, которую токарь обтачивает до заданного размера, рост человека, дальность полета снаряда и
др.
Определение 2. Плотностью вероятности f(x) непрерывной случайной величины
называется производная ее функции распределения F(x), т.е. f(x) = F'(x). (1)
8.1. Второе определение непрерывной случайной величины
Величина X называется непрерывной случайной величиной, если вероятность попадания ее значения в любой интервал (x1, x2) может быть представлена в виде интеграла (2)
от некоторой функции p(x) - плотности распределения вероятностей.
x2
P (x 1  X  x 2 ) 
 p(x )dx
(2)
x1
Плотность распределения вероятностей вполне определяет закон распределения непрерывной случайной величины X (или, как мы будем говорить, непрерывный закон рас-
249

пределения). При этом функция p(x) должна быть неотрицательной (что связано с не отрицательностью вероятностей) и должна быть нормирована условием

 p(x )dx  1,
(3)

отражающим достоверность события (  X  ). Если все возможные значения случайной величины X сосредоточены в конечном интервале (a, b), то мы будем считать, что
вне этого интервала плотность p(x) = 0 и, значит, условие (3) сводится к условию

 p(x )dx  1.
(3')

Плотность вероятности p(x) случайной величины X и ее функция распределения F(x)
взаимно определяют друг друга. Действительно, если известна функция распределения
F(x) случайной величины X, то плотность вероятности ее найдется по равенству (1).
Наоборот, пусть известна плотность вероятности p(x) случайной величины X. Функция
распределения F(x) определяется равенством:
F (x )  P (  X  x ).
Но согласно формуле (3) вероятность того, что случайная величина X примет какоенибудь значение от   до x, равна:
x
P (  X  x ) 
 p(x )dx .
(4)

Из этих двух равенств получаем:
x
F (x ) 
 p(x )dx .
(5)

Таким образом, для полной характеристики случайной величины достаточно задать
или функцию распределения, или плотность вероятности ее. Однако в большинстве случаев имеют дело с плотностью вероятности из-за удобств при теоретических исследованиях и из-за простых геометрических истолкований.
9. Примеры непрерывных законов распределения
9.1. Равномерное распределение в интервале (a, b)
Говорят, что случайная величина X распределена равномерно в конечном интервале
(a, b), если все ее возможные значения сосредоточены на этом интервале и если плотность
распределения ее вероятностей на этом интервале и если плотность распределения ее вероятностей на этом интервале постоянна. Если эту постоянную обозначить буквой C, то
плотность равномерного распределения задается формулой
пр и
  x  ,
C
p(x )  
(1)
( ,  ).
 0 вне интер вала
Для случайной величины X, равномерно распределенной в интервале ( ,  ) , вероятность попадания в любой интервал (x1, x2), лежащий внутри интервала ( ,  ) , пропорциональна длине этого интервала.
(2)
P x 1  X  x 2   C  x 2  x 1 .
Параметр C определяется из условия нормирования:
P (  X   )  C (   )  1,
250 
1
.
 
Подставляя полученное значение C в формулу (2), мы находим, что вероятность попадания значения величины X в интервал (x1, x2) равна отношению длины этого интервала
к длине всего интервала ( ,  ) :
x 2  x1
P (x 1  X  x 2 ) 
.
(3)
 
Заметим, что обычно употребляемое выражение "выберем точку X наудачу в интервале ( ,  ) " означает, что рассматриваемая точка X представляет собой случайную величину с равномерным распределением вероятностей в интервале ( ,  ) . Точно так же, если
говорят, что выбирается наудачу направление на плоскости, то имеют в виду, что выбираемый угол есть случайная величина с равномерным распределением вероятностей в интервале (0, 2 ) .
откуда C 
9.2. Математическое ожидание и дисперсия непрерывной случайной
величины
Определение. Математическим ожиданием M(X) непрерывной случайной величины
X, плотностью вероятности которой является функция p(x), называется величина интеграла

MX 
 xp(x )dx ,
(4)

если он сходится абсолютно, а дисперсией называется величина интеграла

DX 
 (x  a)
2
 p(x )dx ,
(5)

если он сходится [где a = M(X)].
Легко заметить полную аналогию определений математического ожидания непрерывной и прерывной случайных величин. В формуле (5) суммирование заменено интегрированием (что вполне естественно для непрерывной случайной величины). Роль xi играет
непрерывно изменяющаяся переменная x. Так как p(x)  x с точностью до бесконечно малых высшего порядка по сравнению с x дает вероятность того, что случайная величина
примет какое-нибудь значение из интервала (x, x + x ), то ясно также, что p(x)dx и pi играют одинаковую роль. Так же устанавливается полная аналогия определений дисперсии
непрерывной и прерывной случайных величин.
Пример 1. Минутная стрелка электрических часов передвигается скачками поминутно. Вы бросили взгляд на часы. Они показывают a минут. Тогда для Вас истинное
время в данный момент будет случайная величина. Найти ее функцию распределения.
Решение
Функция распределения истинного времени равна 0 для всех x  a и единице для x >
a + 1. Время течет равномерно. Поэтому вероятность того, что истинное время меньше a +
0.5 мин, равна 0.5, так как одинаково вероятно, прошло ли после a менее или более полминуты. Вероятность того, что истинное время - меньше a+0.25 мин, равна 0.25 (вероятность этого времени втрое меньше вероятности того, что истинное время больше a + 0.25
251

мин, а сумма их равна единице, как сумма вероятностей противоположных событий).
Аналогично рассуждая, найдем, что вероятность того, что истинное время меньше a + 0.6
мин, равна 0.6. В общем случае вероятность того, что истинное время меньше a   мин
(0    1) , равна  . Следовательно, функция распределения истинного времени имеет такое выражение:
 0 для
x  a;

F (x )   для x  a   (0    1);
 1 для
x  a 1

Она непрерывна всюду, а производная ее непрерывна во всех точках за исключением
двух: x = a и x = a + 1.
Программа
Program Function_Continuous1;
uses WinCrt;
var
a
: integer;
x, alfa : real;
{---------------------------------------------------------------------------------------}
Function Fx(a : integer; x, alfa : real) : real;
begin
if x < a
then Fx := 0
else if x = a + alfa
then Fx := alfa
else Fx := 1
end;
{---------------------------------------------------------------------------------------}
begin
write('Введите число минут, которое показывает минутная стрелка ');
readln(a);
write('Введите значение аргумента функции распределения '); readln(x);
if (x - a < 1) and (x - a > 0) then alfa := x - a
else alfa := 0;
write('Значение функции распределения равно ', Fx(a, x, alfa):4:6)
end.
Пример 2. Случайная величина X равномерно распределена. Ее плотность вероятности p(x) = A, если a  x  b и p(x) = 0, если x < a и x > b. Определить коэффициент A.
Решение
По формуле (3') получаем:
b
b
a
a
 p(x )dx  1, тогда  Adx  1, отсюда находим A:
Ax
b
a
 1, A 
1
.
b a
252 
Программа
Program Problem2;
uses WinCrt;
var
AA, a, b : real;
begin
write('Введите левую границу интервала '); readln(a);
write('Введите правую границу интервала '); readln(b);
AA := 1/(b - a);
writeln('Значение коэффициента A равно ', AA:6:6)
end.
10. Нормальное распределение
Случайная величина X распределена по нормальному закону, если ее плотность вероятности равна
p(x ) 
1
 2
e

( x  a) 2
2 2
.
(1)
Для нормального закона распределения:
M (X )  a, D(X )   2 ,  x   .
Функция распределения нормально распределенной случайной величины
F (x ) 
1
 2
x
e

( t  a) 2
2 2
dx t.
(2)

2
x

t2
2
 e dt равенством
2 0
Следует вспомнить из предыдущего раздела рекуррентную функцию вычисления
функции Лапласа и используя ее составить функцию вычисления нормально распределенной случайной величины:
{ Рекуррентная функция вычисления интеграла вероятностей }
{ Пределы интегрирования от 0 до x. Функция Муавра-Лапласа }
Function FF(x : real) : real;
var
n : integer;
u, I : real;
begin
if x > 5
then FF := 1
else if x < -5
then FF := -1
else
begin
u := x; n := 0; I := 0;
repeat
I := I + u; n := n + 1;
u := -u*(x*x*(2*n - 1)/(2*n*(2*n + 1)))
until abs(u) < 0.00001;
FF := 2*I/sqrt(2*Pi)
end
end;
Функция F(x) связана с функцией Лапласа (x ) 
253

1  x  a 1
(3)
F (x )  
 .
2    2
Для нормальной распределенной случайной величины X верны формулы
1     a
   a 
(4)
P (  X   )  
   
   
2   
вероятность того, что X примет значения от  до  ;

P (| X  a|   )     
вероятность отклонения X от a по модулю меньше, чем на  ;
P (| X  a|  3 )  (3)  0.9973 правило "трех сигм".
Примеры
(5)
(6)
1. Автомат штампует детали. Контролируется длина детали X, которая распределена
нормально с математическим ожиданием (проектная длина), равным 50 мм. Известно, что
средняя квадратическая ошибка равна 3.6 мм. Найти вероятность того, что длина наудачу
взятой детали находится в границах а) от 55 мм до 68 мм; б) от 32 мм до 40 мм.
Математическое решение задачи
По условию a  50,   3.6. По формуле (4) получаем:
а) P (  X   ) 
P (55  X  68) 
1     a
   a 

 ;
  

   
2   
1   68  50 
 55  50   1

. ) .
  
  (5)  (138

 3.6   2
2   3.6 
1   40  50 
 32  50   1

  
    (2.77)  (5).

 3.6   2
2   3.6 
Для составления программы достаточно использовать функцию Муавра-Лапласа.
б) P (32  X  40) 
Программа
Program Normal1;
uses WinCrt;
var
a, a1, b, c, PP : real;
{----------------------------------------------------------------------------------------}
{ Функция Муавра-Лапласа }
Function FF(x : real) : real;
var
n : integer; u, I : real;
begin
if x >= 5
then FF := 1
else if x <= -5
then FF := -1
else
begin
254 
u := x; n := 0; I := 0;
repeat
I := I + u; n := n + 1;
u := -u*(x*x*(2*n - 1)/(2*n*(2*n + 1)))
until abs(u) < 0.00001;
FF := 2*I/sqrt(2*Pi)
end
end;
{----------------------------------------------------------------------------------------}
begin
write('Введите математическое ожидание (проектную длину) a ');
readln(a);
write('Введите левую границу интервала '); readln(a1);
write('Введите правую границу интервала '); readln(b);
write('Введите среднюю квадратическую ошибку '); readln(c);
pp := 0.5*(FF((b - a)/c)-FF((a1 - a)/c));
write('Вероятность того, что деталь находится в ');
writeln('заданных границах равна ', pp:1:6)
end.
2. Автомат изготовляет шарики для подшипников. Шарик считаем принятым, если
отклонение X диаметра шарика от заданного размера по абсолютной величине меньше 0.7
мм. Считается, что X распределена нормально со средним квадратическим отклонением
 = 0.4 мм. Найти, сколько будет годных шариков среди 50 изготовленных.
Решение
По условию задачи отклонение X шарика от заданного размера a есть случайная величина. Следовательно, M(X) = 0. Допустимая ошибка отклонения   0.7 мм, а средняя
квадратическая ошибка 0.4 мм. Найдем вероятность того, что наугад рассмотренный шарик будет принят, т.е. для него X не превзойдет по абсолютной величине   0.7 , по формуле (5).

 0.7
P (| X |  0.7)       .
 
 0.4 
Тогда из 50 шариков в среднем будет принято 50  P(|X| < 0.7).
Программа
Program Normal2;
uses WinCrt;
var
e, c : real;
n : integer;
{----------------------------------------------------------------------------------------}
{ Функция Муавра-Лапласа }
Function FF(x : real) : real;
var
n : integer;
u, I : real;
begin
255

if x >= 5
then FF := 1
else if x <= -5
then FF := -1
else
begin
u := x; n := 0; I := 0;
repeat
I := I + u;
n := n + 1;
u := -u*(x*x*(2*n - 1)/(2*n*(2*n + 1)))
until abs(u) < 0.00001;
FF := 2*I/sqrt(2*Pi)
end
end;
{----------------------------------------------------------------------------------------}
begin
writeln('Введите отклонение X диаметра шарика');
write('от заданного размера по абсолютной величине '); readln(e);
write('Введите среднее квадратическое отклонение '); readln(c);
write('Введите число изготовленных шариков '); readln(n);
n := Round(FF(e/c)*n);
writeln('Число годных шариков равно ', n)
end.
3. Случайная величина X распределена нормально со средним квадратическим отклонением  = 5 мм. Найти длину интервала, симметричного относительно M(X), в который с вероятностью 0.990 попадает X в результате испытания.
Решение
В условии задачи дано, что  = 5 мм, а P(|X - a| <  ) = 0.990. Необходимо найти  .

Тогда 2 - длина интервала. По формуле (5) получаем    0.990.
 
Теперь остается найти аргумент функции Муавра-Лапласа. Для этого достаточно составить следующую небольшую процедуру:
{ Процедура нахождения аргумента функции Муавра-Лапласа }
Procedure Argument(PP : real; var x : real);
begin
x := 0;
repeat
x := x + 0.0001
until FF(x) >= PP
end;
Процедуре организована с помощью цикла с последующим условием repeat ... until
... , в котором заведомо установлен шаг - 0.0001 для поиска аргумента. Однако этот шаг
можно изменить или вводить в процедуру по усмотрению пользователя.
Тогда процедуру можно построить так:
256 
{ Процедура нахождения аргумента функции Муавра-Лапласа }
Procedure Argument(PP, eps : real; var x : real);
begin
x := 0;
repeat
x := x + eps
until FF(x) >= PP
end;
Задание 15
1. Самостоятельно составьте программу решения задачи 3.
2. Средний диаметр детали 6 см и дисперсия равна 0.0004 см2 . Определить максимальное отклонение размера диаметра наудачу взятой детали от среднего размера, которое можно гарантировать с вероятностью не менее чем 0.9973.
3. Случайная величина X - ошибка измерительного прибора - распределена по нормальному закону с дисперсией 16 мк2 . Систематическая ошибка отсутствует. Найти вероятность того, что в пяти независимых измерениях ошибка X а) превзойдет по модулю 6 мк
не более 3-х раз; б) хотя бы один раз окажется в интервале от 0.5 мк до 3.5 мк.
Указание
p  P (| X |  6),
а) Вычислить
а затем при
Найти
n  5, p, q  1  p.
P  P0.5  P1.5  P2.5  P3.5 . б) Найти p  P (0.5  X  3.5), а затем P  1  P0.5 ; при найденном p P0.5 находится по формуле Бернулли.
Упражнения
128. Значение измеряемого теодолитом угла X имеет нормальное распределение со
средним квадратическим отклонением, равным 8''. Найти вероятность того, что ошибка
измерения угла не превзойдет по абсолютной величине 10''.
129. Станок автомат изготавливает валики. Контролируется их диаметр X. Считается, что X - нормально распределенная случайная величина со средним значением a = 10
мм. Какова средняя квадратическая ошибка, если с вероятностью 0.990 диаметр заключен
в интервале (9.7; 10.3)?
130. В каких границах следует ожидать величину диаметра валика в предыдущей задаче с вероятностью 0.9973?
131. Случайная величина распределена по нормальному закону, Известно, что математическое ожидание ее равно 10 и среднее квадратическое отклонение равно 5. Определить вероятность того, что случайная величина примет значения, принадлежащие интервалу (7; 12).
132. Случайная величина распределена по нормальному закону. Ее математическое
ожидание равно 10 и среднее квадратическое отклонение составляет 5. Определить вероятность того, что отклонение значений случайной величины от математического ожидания не превзойдет по абсолютной величине  =2.
133. Известно, что вес некоторых плодов, выращиваемых в совхозе, подчиняется
нормальному закону с математическим ожиданием 175 г. и  = 25. Определить вероятность того, что вес наудачу взятого плода будет: а) заключен в пределах от 125 до 250 г; б)
не менее 250 г; в) не более 300 г.
134. Длина детали - случайная величина, распределенная по нормальному закону, со
средним значением 20 см и дисперсией, равной 0.2 см2 . Определить вероятность того, что
длина наудачу взятой детали будет заключена в пределах от 19.7 до 20.3 см.

257
135. При измерении расстояний до удаленных предметов ошибка подчинена нормальному закону со средним значением, равным 20 м и средним квадратическим отклонением 40 м. Определить вероятность того, что измеренное расстояние отклоняется от действительного в ту или иную сторону не более чем на 30 м.
136. Изготовленные цехом детали по размерам диаметра распределяются по нормальному закону с математическим ожиданием 4.9 см и средним квадратическим отклонением 0.5 см. Определить вероятность того, что диаметр взятой наудачу детали отклонится от математического ожидания менее чем на 1 см.
137. Изделия, выпускаемые цехом, по своим линейным размерам распределяются по
нормальному закону с математическим ожиданием равным 5 см. Известна вероятность,
равная 0.9758, что наудачу взятое одно изделие будет иметь размеры в границах от 4.95 см
до 5.05 см. Найти дисперсию этой случайной величины.
138. Длина изготовляемой автоматом детали, представляет собой случайную величину, распределенную по нормальному закону с параметрами a = 15 см и  =0.2 см. Найти
вероятность брака, если допустимые размеры детали должны быть 15  0.3 см. Какую точность длины изготовленной автоматом детали можно гарантировать с вероятностью 0.95?
139. На автомате изготовляют заклепки. Диаметр их головок представляет собой
случайную величину, распределенную по нормальному закону и имеет среднее значение,
равное 2 мм, и дисперсию, равную 0.01 мм2 . Какие размеры диаметра головок заклепки
можно гарантировать с вероятностью 0.95?
140. Случайная величина, распределенная по нормальному закону, имеет математическое ожидание 5 м и дисперсию, равную 16 м2 . Найти вероятность того, что случайная
величина примет значение не менее 6 м и не более 8 м.
141. Ведется артиллерийская стрельба по цели из орудия. Средняя дальность полета
снаряда 1200 м. Определить, какой процент выпускаемых снарядов дает перелет от 0 до
60 м, если среднее квадратическое отклонение равно 40 м.
142. Размер диаметра втулки, изготовляемой цехом, можно считать нормально распределенной случайной величиной с математическим ожиданием a = 2.5 см и дисперсией
 2 = 0.0001 см2. В каких границах можно практически гарантировать размер диаметра
втулки, если за вероятность практической достоверности принимается 0.9973?
143. В условиях предыдущей задачи диаметры трех проверенных втулок отклонились от a = 2.5 см более чем на 0.6 см. Согласуется ли этот факт с предположением о нормальном распределении диаметра втулки с параметрами a=2.5 см и  2= 0.0001?
258 
10. Метод статистических испытаний
Статистические испытания предполагают многократное повторение однотипных испытаний. Результат любого отдельного испытания случаен и сам по себе какого-либо интереса не представляет. В то же время совокупность большого числа подобных результатов оказывается весьма полезной. Она обнаруживает определенную устойчивость (ее
называют статистической устойчивостью), которая позволяет количественно описать явление, исследуемое в данных испытаниях. Рассмотрим специальный метод исследования
случайных процессов, основанный на статистических испытаниях. Его так и называют метод статистических испытаний. Другое название этого метода, которое используется
чаще, - метод Монте-Карло.
Прежде, чем рассмотреть непосредственное применение этого метода надо познакомится с понятием геометрической вероятности.
10.1. Геометрические вероятности "геометрическая схема" испытания
"Классическая схема", основанная на понятии равновозможности конечного числа
исходов испытания, при изучении большинства явлений реального мира является недостаточной. На практике часто встречаются такие испытания, исходы которых, как правило, являются или неравновозможными, или их число бесконечно.
Так, если испытание состоит в том, что сигнальщик в течение часа должен принять
мгновенный световой сигнал, то его возможными исходами можно считать появление
сигнала в любой момент времени в течение этого часа. Если испытание состоит в том, что
разведчик должен нарушить линию связи длиной 2 км, то возможными исходами этого
испытания можно считать разрыв линии связи в любой точке.
Множество исходов таких и аналогичных им испытаний бесконечно. Оно может
быть иллюстрировано геометрически в виде совокупности точек отрезка прямой, плоской
фигуры или пространственного тела. В связи с этим такую схему испытания принято
называть геометрической схемой.
Вероятности, вычисляемые как отношения мер. Пусть в результате испытания
наудачу выбирается точка в области S. Требуется найти вероятность того, что эта точка
окажется в области s, являющейся частью области S.
Как указывалось в первом пункте, мы будем рассматривать области одного, двух и
трех измерений. Так как число возможных исходов таких испытаний и число исходов,
благоприятствующих рассматриваемым событиям, бесконечно, то формулу для непосредственного подсчета вероятностей применять нельзя.
Введем следующее допущение. Пусть исходы испытания распределены равномерно.
Это значит, что если разделить некоторую область S на конечное число равновеликих частей si, (i= 1, 2, 3, ..., n), то событие Ei, означающее попадание наудачу выбранной точки из
области S в любую область si ее часть, равновозможны, т.е. можно считать, что вероятность попадания наудачу выбранной точки из области S в какую-либо часть s этой области пропорциональна мере это части и не зависит от расположения и формы.
m( s)
P(E ) 
.
Следовательно,
n( s)
где P ( E ) - вероятность того, что наудачу выбранная точка из области S окажутся в области s, а m(s) и n(s) есть меры соответствующих областей, выраженных в единицах длины,
площади или объема.
Прежде, чем перейти к рассмотрению примеров с использованием понятия геометрической вероятности рассмотрим стандартную функцию и процедуру, которые используются в Турбо Паскале.
259

10.2. Функция random и процедура randomize
Функция random генерирует случайное вещественное число из промежутка [0; 1].
Значения функции random имеют тип real.
Возникает естественный вопрос, а как выработать случайное вещественное число из
произвольного промежутка [a; b]?
Для этого надо умножить случайное число из промежутка [0; 1], т.е. значение функции random, разность b - a и прибавить левую границу промежутка - a.
Случайное вещественное число из промежутка [a; b] получается от умножения значения функции random на разность b-a и прибавления к результату левой границы промежутка - числа a: random*(b - a) + a
Например, для получения случайного вещественного числа из промежутка [6; 15],
надо длину промежутка 15-(-6)=21 умножить на значение функции random и прибавить -6:
random*21-6,
а для получения случайного вещественного числа из промежутка [0; 100] надо значение
random умножить на 100:
random*100.
Функция random(x), где x - целое число (тип: integer), выдает случайное целое число
из промежутка [0; x). Значения функции random(x) имеют тип integer.
Например, значением функции random(6) является случайное целое число из промежутка [0; 6) или из [0; 5].
Как с помощью этой функции получить случайное целое число из промежутка [a; b],
где a и b целые числа? Это можно сделать с помощью функции:
random(b  a  1)  a.
Например, случайное целое число из промежутка [15; 18] задается функцией:
random(4)+15.
Есть одна особенность в использовании функций случайных чисел или, как еще их
называют, генераторов случайных чисел. При повторном обращении к ним, они могут повторять предыдущие значения. Чтобы избежать этого неприятного явления, перед их применением надо использовать процедуру инициализации этого генератора случайных чисел. Такая процедура есть. Ее имя randomize.
Процедура randomize инициализирует датчик случайных чисел random.
Итак, перед использованием в программе датчика псевдослучайных чисел random в
программу надо включать процедуру randomize, которая инициализирует датчик случайных чисел.
Пример 1. На стержне AB, длина которого равна 36 см, нанесена наудачу тонкая
риска. Какова вероятность того, что эта риска окажется не далее a от конца A или не далее
b от середины стержня: 1) a = 6 см, b = 2 см; 2) a = 12 см, b = 10 см?
Алгоритм
Числовую ось OX расположим так, что ее начало совпадает с левым концом отрезка
- точкой A. Тогда нанесение риски на стержень будет означать случайный выбор значения
X из промежутка [0; 36] и задаваться следующим равенством:
x := random*36.
260 
Риска должна быть не далее a от начала отрезка, т. е. значения x должно удовлетворять неравенству (см. рис. 30): x  a.
Не далее b от середины отрезка означает, что |18  x |  b.
Надо подсчитать количество значений x, удовлетворяющих неравенствам:
x  a и | 18  x | b.
Пусть их число равно m, а общее число "брошенных" на отрезок точек - n. Тогда искомая вероятность будет равна: p = m/n.
Рис. 30
Для определения точности вычисления вероятности, которая равна частости появления события (m/k), а отсюда и числа испытаний, можно воспользоваться способом, который уже применялся при изучении интегральной формулы Муавра-Лапласа.
В зависимости от гарантированной вероятности и точности вычисления можно установить необходимое число испытаний - n, а затем, по числу испытаний рассчитать вероятность.
Возможность применения формулы Муавра-Лапласа к решению геометрической задачи методом Монте-Карло дает следующие обстоятельства.
Испытания, т.е. "бросание" точек, независимы и равновозможны. Вероятность
наступления события в каждом испытании постоянна и отлична от нуля и единицы, а число испытаний может быть достаточно велико.
Таким образом, все условия для применения формулы Муавра-Лапласа выполнены.
А теперь вспомним пример, в котором находится число испытаний в зависимости от заданной вероятности и точности вычисления.
Для этого можно использовать процедуры и функции из раздела "Интегральная
формула Муавра-Лапласа" (в частности, в примере 6).
Вероятность некоторого события хотят установить статистически. Для этого проводят некоторое количество испытаний, и частость появления события принимают за его вероятность. Сколько надо произвести испытаний, чтобы с вероятностью 0.97 можно гарантировать, что вероятность события в одном испытании будет отличаться от частости полученной из опыта, не более, чем на 0.01?
Одна из идей, которыми можно воспользоваться и реализовать программными средствами, состоит в том, чтобы непосредственным подбором числа n найти его искомое значение.
Для этого достаточно организовать цикл, завершающим условием которого является: FF (x )  PP, где PP - гарантированная вероятность, FF(x) - значение функции Муавра-Лапласа.
Чтобы найти x нужно воспользоваться соотношением: x := 2*e*sqrt(n).
В результате можно составить следующую процедуру:
{ Процедура вычисления числа испытаний при заданной гарантиро- }
{ ванной вероятности и заданной точности частости }
Procedure NumberExperiment(e, PP : real; var n : longint);
var
x : real;
begin
261

n := 0;
repeat
n := n + 1;
x := 2*e*sqrt(n)
until FF(x) >= PP
end;
Основываясь на этой процедуре составим программу.
{ Применение интегральной формулы Муавра-Лапласа }
Program Problem6;
uses WinCrt;
var
n
: longint;
e, pp : real;
{-------------------------------------------------------------------------------------------}
{ Рекуррентная функция вычисления интеграла вероятностей }
{ Пределы интегрирования от 0 до x. Функция Муавра-Лапласа }
Function FF(x : real) : real;
var
n : integer;
u, I : real;
begin
if x >= 5
then FF := 1
else if x <= -5
then FF := -1
else
begin
u := x; n := 0; I := 0;
repeat
I := I + u;
n := n + 1;
u := -u*(x*x*(2*n - 1)/(2*n*(2*n + 1)))
until abs(u) < 0.00001;
FF := 2*I/sqrt(2*Pi)
end
end;
{-------------------------------------------------------------------------------------------}
{ Процедура вычисления числа испытаний при заданной гарантиро- }
{ ванной вероятности и заданной точности частости
}
Procedure NumberExperiment(e, PP : real; var n : longint);
var
x : real;
begin
n := 0;
repeat
n := n + 1;
x := 2*e*sqrt(n)
until FF(x) >= PP
end;
{-------------------------------------------------------------------------------------------}
262 
{ Основная программа }
begin
write('Введите гарантированную вероятность '); readln(PP);
write('Введите точность вычисления частости '); readln(e);
NumberExperiment(e, PP, n);
writeln('Число испытаний равно ', n );
writeln('С точностью до ', e:1:8)
end.
Используя процедуры из предыдущей программы, составим программу решения
геометрической задачи. Надо сразу заметить, что точность вычисления будет невысокой.
При увеличении точности даже с гарантированной вероятностью 0.97, не говоря уже о вероятности 0.99, резко возрастает число испытаний и программа становится трудоемкой
для выполнения.
Программа
Program Problem1;
uses WinCrt;
var
x, a, b, p, e, pp : real;
i, n, m
: longint;
{----------------------------------------------------------------------------------------}
{ Интегральная функция Муавра-Лапласа }
Function FF(x : real) : real;
var
n : integer;
u, I : real;
begin
if x >= 5
then FF := 1
else if x <= -5
then FF := -1
else
begin
u := x; n := 0; I := 0;
repeat
I := I + u;
n := n + 1;
u := -u*(x*x*(2*n - 1)/(2*n*(2*n + 1)))
until abs(u) < 0.00001;
FF := 2*I/sqrt(2*Pi)
end
end;
{----------------------------------------------------------------------------------------}
{ Процедура вычисления числа испытаний при заданной гарантиро- }
{ ванной вероятности и заданной точности частости
}
Procedure NumberExperiment(e, PP : real; var n : longint);
var
x : real;
begin
n := 0;
repeat
n := n + 1;
263

x := 2*e*sqrt(n)
until FF(x) >= PP
end;
{----------------------------------------------------------------------------------------}
begin
randomize;
write('Введите расстояние a от конца стержня '); readln(a);
write('Введите расстояние b от середины стержня '); readln(b);
write('Введите гарантированную вероятность '); readln(PP);
write('Введите точность вычисления '); readln(e);
NumberExperiment(e, PP, n);
m := 0;
for i := 1 to n do
begin
x := random*36;
if (x <= a) or (abs(18 - x) <= b) then m := m + 1;
end;
p := m/n;
writeln('Вероятн. появления риски в заданном месте ',p:6:4);
writeln('С точностью до ', e:1:6);
writeln('С гарантированной вероятностью ', PP:1:4);
writeln('При числе испытаний ', n)
end.
Пример 2. На отрезке AB длины l независимо друг от друга выбираются наудачу две
точки M и N. Какова вероятность того, что точка M окажется ближе к точке A, чем точка
N?
Алгоритм
Пусть |AM| = x, |AN| = y. Рассматриваемому событию будут благоприятствовать
лишь те точки, которые удовлетворяют условию y>x. Множество всех возможных исходов испытания можно изобразить в виде квадрата, сторона которого равна l (см. рис. 31).
Рис. 31
Множество исходов испытания, благоприятствующих рассматриваемому событию,
геометрически изображается точками заштрихованного треугольника. Координаты всех
точек этого треугольника удовлетворяют неравенству: y>x.
264 
Программа
Program Problem2;
uses WinCrt;
var
x, y, p, e, pp : real;
i, n, m
: longint;
{--------------------------------------------------------------------------------------}
{ Рекуррентная функция вычисления интеграла вероятностей }
{ Пределы интегрирования от 0 до x. Функция Муавра-Лапласа }
Function FF(x : real) : real;
var
n : integer; u, I : real;
begin
if x >= 5
then FF := 1
else if x <= -5
then FF := -1
else
begin
u := x; n := 0; I := 0;
repeat
I := I + u; n := n + 1;
u := -u*(x*x*(2*n - 1)/(2*n*(2*n + 1)))
until abs(u) < 0.00001;
FF := 2*I/sqrt(2*Pi)
end
end;
{----------------------------------------------------------------------------------------}
{ Процедура вычисления числа испытаний при заданной гарантиро- }
{ ванной вероятности и заданной точности частости
}
Procedure NumberExperiment(e, PP : real; var n : longint);
var
x : real;
begin
n := 0;
repeat
n := n + 1;
x := 2*e*sqrt(n)
until FF(x) >= PP
end;
{----------------------------------------------------------------------------------------}
begin
randomize;
write('Введите гарантированную вероятность '); readln(PP);
write('Введите точность вычисления '); readln(e);
NumberExperiment(e, PP, n);
m := 0;
for i := 1 to n do
begin
x := random;
y := random;
if y > x then m := m + 1
265

end;
p := m/n;
writeln('Искомая вероятность равна ', p:6:4);
writeln('С точностью до ', e:1:6);
writeln('С гарантированной вероятностью ', PP:1:4);
writeln('При числе испытаний ', n)
end.
Задание 16
Составьте программы решения задач.
1. На отрезке AB длины a наудачу независимо друг от друга выбираются две точки
M и N. Какова вероятность того, что эти точки окажутся не дальше чем на расстоянии b от
точки A (b  a)?
2. В трапеции, размеры которой даны на рисунке, выбирается наудачу точка M. Какова вероятность того, что она окажется в одном из треугольников? (Рис. 32).
Рис. 32
Пример 3. В круг, радиус которого равен R, вписан правильный треугольник. Какова
вероятность того, что наудачу взятая точка круга окажется внутри треугольника? (См. рисунок 33).
Математическое решение задачи
Пусть событие E состоит в том, что наудачу выбранная точка окажется внутри треугольника. Так как точка выбирается наудачу, можно допустить, что все исходы испытания распределены равномерно. Следовательно,
P(E ) 
S1
,
S
где S1 - площадь треугольника, а S - площадь круга.
Рис. 33
266 
Но площадь круга равна R 2 , а площадь треугольника
3 3 R2
4
3 3  R2 3 3

.
Отсюда: P( E ) 
4   R 2
4
Алгоритм решения по методу Монте-Карло
Так как величина радиуса окружности значения не имеет, то примем его равным
единице, - это упростит наши рассуждения.
Опишем около окружности квадрат и будем "бросать" точки в этот квадрат.
Координаты точек будут задаваться функциями:
x := random*2 - 1 и y := random*2 - 1.
Пусть число таких точек n.
Подсчитаем число точек, попавших в круг. Для этого их координаты должны удовлетворять неравенству: x  x  y  y 1 . Пусть число попавших в круг точек равно k.
Точки, попавшие в треугольник должны удовлетворять следующим неравенствам:
1) они должны быть в круге, значит должны удовлетворять неравенству:
x  x  y  y  1;
2) уравнения боковых сторон этого треугольника: y  1  x  3 и y  1  x  3; уравнение основания треугольника: y = -1/2; значит координаты точек попавших в треугольник должны удовлетворять еще и следующим неравенствам:
1
y  1  x  3, y  1  x  3
и y .
2
Пусть число таких точек равно m. Тогда искомая вероятность будет равна:
m
p .
k
В этом примере, в отличие от предыдущих, значение общего числа испытаний будет
равно не n, так как n - число точек, попавших в квадрат, а k - числу точек, попавших в
круг. Поэтому, надо организовать цикл, до тех пор, пока n - число испытаний, зависящее
от гарантированной вероятности и точности, не станет равным k. Это легко можно сделать
с помощью цикла repeat ... until ... .
Программа
Program Problem3;
uses WinCrt;
var
x, y, p, e, pp : real;
n, k, m
: longint;
{----------------------------------------------------------------------------------------}
{ Рекуррентная функция вычисления интеграла вероятностей }
{ Пределы интегрирования от 0 до x. Функция Муавра-Лапласа }
Function FF(x : real) : real;
var
n : integer;
u, I : real;
begin
if x >= 5
then FF := 1
else if x <= -5
267

then FF := -1
else
begin
u := x; n := 0; I := 0;
repeat
I := I + u; n := n + 1;
u := -u*(x*x*(2*n - 1)/(2*n*(2*n + 1)))
until abs(u) < 0.00001;
FF := 2*I/sqrt(2*Pi)
end
end;
{----------------------------------------------------------------------------------------}
{ Процедура вычисления числа испытаний при заданной гарантиро- }
{ ванной вероятности и заданной точности частости
}
Procedure NumberExperiment(e, PP : real; var n : longint);
var
x : real;
begin
n := 0;
repeat
n := n + 1;
x := 2*e*sqrt(n)
until FF(x) >= PP
end;
{----------------------------------------------------------------------------------------}
{ Основная программа }
begin
randomize;
write('Введите гарантированную вероятность '); readln(PP);
write('Введите точность вычисления '); readln(e);
NumberExperiment(e, PP, n);
m := 0; k := 0;
repeat
x := random*2 - 1;
y := random*2 - 1;
if x*x + y*y <1 then k := k + 1;
if (x*x + y*y<1) and (y <( 1 - x*sqrt(3)))
and (y < (1 + x*sqrt(3))) and (y > -1/2)
then m := m + 1
until n = k;
p := m/k;
writeln;
writeln('Вероятность, что точка окажется в треугольнике ', p:1:6);
writeln('С точностью до ', e:1:6);
writeln('С гарантированной вероятностью ', PP:1:4);
writeln('При числе испытаний ', n)
end.
268 
Задание 17
Составить программы решения следующих задач.
1. Внутри прямоугольного параллелепипеда, измерения которого равны 4, 6, 10 см,
наудачу выбирается точка M. Какова вероятность того, что она окажется внутри данного
куба, ребро которого 3 см.?
2. Два действительных числа x и y выбираются наугад независимо друг от друга так,
что |x| < 3, а |y| < 5. Какова вероятность того, что эти числа окажутся положительными?
11. Задача о встрече
Пример 4. Два лица A и B условились встретиться в определенном месте между 11 и
12 ч. Пришедший первым ждет другого в течение 20 мин, после чего уходит. Какова вероятность встречи этих лиц, если каждый в течение часа приходит к этому месту наудачу, а
моменты прихода независимы друг от друга? (См. рис. 34).
Алгоритм решения
На прямой отложим отрезок, равный единицы длины, принимая за единицу масштаба 1 ч. Моменты случайного прихода лиц A и B можно изобразить точками на этом отрезке. Таким образом, нам необходимо выбрать наудачу две точки на данном отрезке. Обозначим моменты прихода лица A через x, а лица B - через y. Тогда множество всех возможных исходов испытания можно изобразить точками квадрата, сторона которого равна
единице.
Рис. 34
Встреча произойдет лишь в том случае, если разность моментов прихода лиц A и B
по абсолютной величине не будет превосходить 1/3 (20 мин), т.е. если произойдет событие, удовлетворяющее неравенству |x - y| < 1/3. Запишем это неравенство в виде системы
y  x  1 / 3
неравенств: 
y  x  1 / 3
Эта система неравенств задает область, заштрихованную на рисунке.
Программа
Program Problem4;
uses WinCrt;
var
x, y, p, e, pp : real;
i, n, m
: longint;
{----------------------------------------------------------------------------------------}
{ Рекуррентная функция вычисления интеграла вероятностей }
{ Пределы интегрирования от 0 до x. Функция Муавра-Лапласа }
Function FF(x : real) : real;
var
269

n : integer;
u, I : real;
begin
if x >= 5
then FF := 1
else if x <= -5
then FF := -1
else
begin
u := x; n := 0; I := 0;
repeat
I := I + u;
n := n + 1;
u := -u*(x*x*(2*n - 1)/(2*n*(2*n + 1)))
until abs(u) < 0.00001;
FF := 2*I/sqrt(2*Pi)
end
end;
{----------------------------------------------------------------------------------------}
{ Процедура вычисления числа испытаний при заданной гарантиро- }
{ ванной вероятности и заданной точности частости
}
Procedure NumberExperiment(e, PP : real; var n : longint);
var
x : real;
begin
n := 0;
repeat
n := n + 1;
x := 2*e*sqrt(n)
until FF(x) >= PP
end;
{----------------------------------------------------------------------------------------}
begin
randomize;
write('Введите гарантированную вероятность '); readln(PP);
write('Введите точность вычисления '); readln(e);
NumberExperiment(e, PP, n);
m := 0;
for i := 1 to n do
begin
x := random;
y := random;
if (y > x - 1/3) and (y < x + 1/3) then m := m + 1
end;
p := m/n;
writeln('Искомая вероятность равна ', p:6:4);
writeln('С точностью до ', e:1:6);
writeln('С гарантированной вероятностью ', PP:1:4);
writeln('При числе испытаний ', n)
end.
270 
Задание 18
Составьте программы решения задач.
1. В соответствии с заданием на полет экипажам двух самолетов необходимо передать одно донесение по радио в любое время от 10 ч до 10 ч 15 мин. Для передачи донесения требуется 3 мин. Какова вероятность того, что радист одного самолета начнет передачу донесения тогда, когда радист другого самолета передачу своего донесения не закончит?
2. В течение 20 мин после 9 ч ученик A в случайный момент времени звонит по телефону ученику B и ждет 2 мин, после чего кладет трубку. В течение тех же 20 мин ученик B заходит в квартиру в случайный момент и остается дома в течение 5 мин. Какова
вероятность того, что разговор между учениками состоится?
12. Задача Бюффона
Пример 5. На большой лист клетчатой бумаги со стороной клетки 1 случайно бросают точку. Какова вероятность, что она будет находиться на расстоянии меньше 1/2 от
центра некоторой клетки?
Математическая схема решения
Достаточно рассмотреть одну клетку. Точки, находящиеся на расстоянии не более
1/2 от ее центра, заполняют круг площади  /4. Это и есть ответ: искомая вероятность (отношение площади круга к площади клетки) равна  /4.
Эту задачу можно использовать для вычисления числа  .
Для этого задачу можно перефразировать так:
"На большой лист клетчатой бумаги со стороной клетки 1 случайно бросают
точки. Вычислить значение числа  ".
Для решения и этой задачи достаточно рассмотреть одну клетку.
Впишем в эту клетку окружность, радиус которой будет равен 1/2. Построим систему координат с началом в центре, вписанной в клетку окружности (см. рис. 35). Тогда
1 
площадь круга равна S 1    r 2     .
4 4
Площадь квадрата равна S2 = 1.
Рис. 35
Как мы уже выяснили из предыдущей задачи вероятность того, что точка попадет в
S1 
круг равна отношению площади круга к площади квадрата: P 
 . С помощью комS2 4
пьютера эту вероятность можно определить следующим способом.
271

Мы можем "заставить" компьютер "бросать" в квадрат точки и подсчитать число
всех точек и тех, которые попадут в круг.
Тогда вероятность определить просто, - надо будет найти отношение числа точек,
попавших в круг к общему числу "брошенных" точек. Это значение и даст нам искомую
вероятность.
Будем "бросать" в этот квадрат точки. Их координаты должны быть заключены в
промежутке от -1/2 до 1/2 и могут задаваться функциями случайных чисел:
x := random - 1/2 и y := random - 1/2.
Координаты точек, которые попадают в круг должны удовлетворять неравенству:
1
x 2  y2  .
4
Пусть общее число "брошенных" точек - n, а число точек попавших в круг - m, тогда,
вероятность попадания точек в круг будет равна отношению числа точек, попавших в него, к общему числу брошенных точек: p := m/n.
m
Отсюда получаем, что S1/S2= m/n или   4 .
n
Таким образом, мы получаем способ для вычисления числа  .
Программа
Program Problem5;
uses WinCrt;
var
x, y, p, e, pp : real;
i, n, m
: longint;
{----------------------------------------------------------------------------------------}
{ Интегральная функция Муавра-Лапласа }
Function FF(x : real) : real;
var
n : integer;
u, I : real;
begin
if x >= 5
then FF := 1
else if x <= -5
then FF := -1
else
begin
u := x; n := 0; I := 0;
repeat
I := I + u;
n := n + 1;
u := -u*(x*x*(2*n - 1)/(2*n*(2*n + 1)))
until abs(u) < 0.00001;
FF := 2*I/sqrt(2*Pi)
end
end;
{----------------------------------------------------------------------------------------}
{ Процедура вычисления числа испытаний при заданной гарантиро- }
{ ванной вероятности и заданной точности частости
}
Procedure NumberExperiment(e, PP : real; var n : longint);
var
272 
x : real;
begin
n := 0;
repeat
n := n + 1;
x := 2*e*sqrt(n)
until FF(x) >= PP
end;
{----------------------------------------------------------------------------------------}
begin
randomize;
write('Введите гарантированную вероятность '); readln(PP);
write('Введите точность вычисления '); readln(e);
NumberExperiment(e, PP, n);
m := 0;
for i := 1 to n do
begin
x := random - 1/2; y := random - 1/2;
if x*x + y*y <= 1/4 then m := m + 1
end;
p := 4*m/n;
writeln('Значение числа Pi равно ', p:8:6);
writeln('С точностью до ', e:1:6);
writeln('С гарантированной вероятностью ', PP:1:4);
writeln('При числе испытаний ', n)
end.
Пример 6. (задача Бюффона об игле). Плоскость разлинована на полосы шириной 1.
На нее бросают иглу (отрезок) длиной 1. Какова вероятность, что игла пересечет одну из
линий? (См. рисунки 36, 37 и 38).
Решение
У этой задачи удивительный ответ:
2

. Откуда же берется  , если в условии нет ре-
чи ни об окружностях, ни о расстояниях?
Наметим коротко одно из решений. Положение иглы (если не говорить о смещении ее
вдоль линий, очевидно, не играющем роли) определяется двумя параметрами: расстояние
y конца иглы от верхнего края полосы, в которую он попал 0  y  1, и углом  иглы с
прямой, перпендикулярной линиям.
Рис. 36
Можно считать, по соображениям симметрии, что  <  /2. Условие, при котором
игла пересекает край полосы: y < cos  . Итак, среди точек (  , y) в прямоугольнике
0     , 0  y  1 мы должны выбрать лежащие ниже линии y = cos  и найти отноше-
273

ние площади S1 полученной фигуры к площади S2 прямоугольника (S 2   / 2). Для тех,
кто знаком с понятием интеграла, найти площадь фигуры под кривой нетрудно: S1=1.
Рис. 37
И тогда, вероятность того, что игла пересечет одну из линий будет равна:
P
S1 1 2
  .
S2  
2
С другой стороны, вероятность пересечения иглой одной из линий будет равна отношению числа пересечений к общему числу "бросаний" иглы: p = m/n. Приравнивая зна2 m
чения вычисленных вероятностей по первому и по второму способам, получим:
 ,
 n
n
отсюда   2  .
m
Выясним случайные координаты иглы, - угла  и ординаты y. Для ординаты случайные значения уже известны: 0 < y < 1.
Как определить величину угла  ?
Для этого расположим систему координат так, чтобы ее начало совпадало с концом
иглы, ось OX была параллельна, проведенным прямым. Возьмем на игле две произвольные точки A и B, их координаты соответственно равны (x1, y1) и (x 2 , y2 ), ясно, они являются случайными числами из промежутка (0, 1), т.е. 0  x 1  1, 0  y1  1, 0  x 2  1,
x1  x 2
.
0  y2  1, тогда легко найти, что tg 
y1  y2
 x1  x 2 
Отсюда, значение угла  :   arctg
.
 y1  y2 
Чтобы игла пересекала хотя бы одну линию надо, чтобы y удовлетворял условию:

 x1  x 2 
.
y  cos или y  cos arctg
 y1  y 2  

Рис. 38
274 
Программа
Program Problem6;
uses WinCrt;
var
x1, x2, y1, y2, y, p, e, pp : real;
i, n, m
: longint;
{----------------------------------------------------------------------------------------}
{ Интегральная функция Муавра-Лапласа }
Function FF(x : real) : real;
var
n
: integer;
u, I : real;
begin
if x >= 5
then FF := 1
else if x <= -5
then FF := -1
else
begin
u := x; n := 0; I := 0;
repeat
I := I + u;
n := n + 1;
u := -u*(x*x*(2*n - 1)/(2*n*(2*n + 1)))
until abs(u) < 0.00001;
FF := 2*I/sqrt(2*Pi)
end
end;
{----------------------------------------------------------------------------------------}
{ Процедура вычисления числа испытаний при заданной гарантиро- }
{ ванной вероятности и заданной точности частости
}
Procedure NumberExperiment(e, PP : real; var n : longint);
var
x : real;
begin
n := 0;
repeat
n := n + 1;
x := 2*e*sqrt(n)
until FF(x) >= PP
end;
{----------------------------------------------------------------------------------------}
begin
randomize;
write('Введите гарантированную вероятность '); readln(PP);
write('Введите точность вычисления '); readln(e);
NumberExperiment(e, PP, n);
m := 0;
for i := 1 to n do
begin
x1 := random; x2 := random;
y1 := random; y2 := random; y := random;
275

if y < cos(arctan((x1 - x2)/(y1 - y2))) then m := m + 1
end;
p := 2*n/m;
writeln('Значение числа Pi равно ', p:8:6);
writeln('С точностью до ', e:1:6);
writeln('С гарантированной вероятностью ', PP:1:4);
writeln('При числе испытаний ', n)
end.
Задание 19
Отрезок разделён на три равные части. Какова вероятность, что три точки, случайно
брошенные на отрезок, попадут в три разные кусочка? Составьте программу.
13. Применение метода Монте-Карло для вычисления площадей
фигур
Рассмотрим применение метода Монте-Карло для определения площадей фигур,
ограниченных линиями.
Пример 7. Вычислить площадь фигуры, ограниченной линиями
y  x 2 , y  0, x  1 и x  2.
Решение
Прежде необходимо установить ту фигуру, площадь которой требуется найти. Эта
фигура заключена между осью OX, - уравнение y = 0; параболой с вершиной в точке (0; 0)
и двумя прямыми, параллельными оси OY и проходящими через точки 1 и 2 на оси OX.
Установим, внутри какой простой фигуры (квадрата, прямоугольника и т.п.) может
быть заключена заданная сложная фигура (см. рис. 39).
Рис. 39
По рисунку легко установить, что такой фигурой является прямоугольник с вершинами в точках (1; 0), (2; 0), (2; 4) и (1; 4). Площадь этого прямоугольника равна: Sпр = 4.
M
Значит площадь искомой фигуры будет равна: S  4 
, где 4 - площадь прямоN
угольника, M - число точек, попавших в фигуру, N - число всех "брошенных" точек.
Дальнейший ход решения такой же, как и в предыдущем примере.
276 
"Бросаются" точки в прямоугольник. Их случайные координаты задаются так: x :=
random + 1, y := random*4.
Какие точки попадут в фигуру, площадь которой надо найти? Координаты точек,
попадающих в фигуру, должны удовлетворять неравенствам: 1  x  2 и 0  y  x 2 . Но
условие для x выполняется заведомо, так как у любой случайно "брошенной" точки координата по x удовлетворяет неравенству 1  x  2 (ибо уже задано, что x := random + 1, а
для координаты по y выполнена лишь левая часть неравенства, значит чтобы точка попала
в данную фигуру достаточно потребовать, чтобы y  x 2 .
На основе этих соображений составляем программу
Program Problem7;
uses WinCrt;
var
x, y, s, e, pp : real;
i, n, m
: longint;
{----------------------------------------------------------------------------------------}
{ Рекуррентная функция вычисления интеграла вероятностей }
{ Пределы интегрирования от 0 до x. Функция Муавра-Лапласа }
Function FF(x : real) : real;
var
n : integer;
u, I : real;
begin
if x >= 5
then FF := 1
else if x <= -5
then FF := -1
else
begin
u := x; n := 0; I := 0;
repeat
I := I + u;
n := n + 1;
u := -u*(x*x*(2*n - 1)/(2*n*(2*n + 1)))
until abs(u) < 0.00001;
FF := 2*I/sqrt(2*Pi)
end
end;
{----------------------------------------------------------------------------------------}
{ Процедура вычисления числа испытаний при заданной гарантиро- }
{ ванной вероятности и заданной точности частости
}
Procedure NumberExperiment(e, PP : real; var n : longint);
var
x : real;
begin
n := 0;
repeat
n := n + 1;
x := 2*e*sqrt(n)
until FF(x) >= PP
end;
{----------------------------------------------------------------------------------------}
277

begin
randomize;
write('Введите гарантированную вероятность '); readln(PP);
write('Введите точность вычисления '); readln(e);
NumberExperiment(e, PP, n);
m := 0;
for i := 1 to n do
begin
x := random + 1; y := random*4;
if y < x*x then m := m + 1
end;
s := 4*m/n;
writeln('Площадь фигуры равна ', s:1:6);
writeln('С точностью до ', e:1:6);
writeln('С гарантированной вероятностью ', PP:1:4);
writeln('При числе испытаний ', n)
end.
Пример 8. Вычислить площадь фигуры, ограниченной линиями
y 1 x
и
y  3  2x  x .
2
Начертим заданную фигуру. Графиком функции y = 3 - 2x - x2 является парабола,
ветви которой направлены вниз, а вершина находится в точке (-1; 4). В самом деле, выделим квадрат двучлена, получим:
y = -(x2 + 2x + 1 - 1 - 3) = -(x + 1)2 + 4.
Графиком функции y = 1 - x является прямая, проходящая через точки (1; 0) и (0; 1).
Необходимо найти точки пересечения этих графиков. Для этого надо решить систему из уравнений, описывающих заданные функции:
y  1  x

2
 y  3  2x  x
Решая находим, 1 - x =3 - 2x - x2, отсюда получаем: x1 = -2, x2 = 1. Значит координаты
точек пересечения будут: (-2; 3) и (1; 0).
Полученную фигуру можно заключить в прямоугольник с вершинами (-2; 0), (-2; 4),
(1; 4) и (1; 0) (см. рис. 40).
Рис. 40
Площадь этого прямоугольника равна S пр  3  4  12. Тогда площадь искомой фигуры равна: S  12 
M
.
N
278 
Чтобы "бросить" точку в этот прямоугольник, надо указать следующие случайные
координаты этих точек: x := random*3 - 2 и y := random*4.
Точки, попавшие в заданную фигуру должны лежать "выше" прямой y  1  x и
"ниже" параболы y  3  2x  x 2 , значит их координаты должны удовлетворять неравенствам: y  3  2x  x 2 и y  1  x .
Программа
Program Problem8;
uses WinCrt;
var
x, y, s, e, pp : real;
i, n, m
: longint;
{----------------------------------------------------------------------------------------}
{ Рекуррентная функция вычисления интеграла вероятностей }
{ Пределы интегрирования от 0 до x. Функция Муавра-Лапласа }
Function FF(x : real) : real;
var
n : integer;
u, I : real;
begin
if x >= 5
then FF := 1
else if x <= -5
then FF := -1
else
begin
u := x; n := 0; I := 0;
repeat
I := I + u;
n := n + 1;
u := -u*(x*x*(2*n - 1)/(2*n*(2*n + 1)))
until abs(u) < 0.00001;
FF := 2*I/sqrt(2*Pi)
end
end;
{----------------------------------------------------------------------------------------}
{ Процедура вычисления числа испытаний при заданной гарантиро- }
{ ванной вероятности и заданной точности частости
}
Procedure NumberExperiment(e, PP : real; var n : longint);
var
x : real;
begin
n := 0;
repeat
n := n + 1;
x := 2*e*sqrt(n)
until FF(x) >= PP
end;
{----------------------------------------------------------------------------------------}
begin
randomize;
279

write('Введите гарантированную вероятность '); readln(PP);
write('Введите точность вычисления '); readln(e);
NumberExperiment(e, PP, n);
m := 0;
for i := 1 to n do
begin
x := random*3 - 2; y := random*4;
if (y <= 3 - 2*x - x*x) and (y >= 1 - x) then m := m + 1
end;
s := 12*m/n;
writeln('Площадь фигуры равна ', s:1:6);
writeln('С точностью до ', e:1:6);
writeln('С гарантированной вероятностью ', PP:1:4);
writeln('При числе испытаний ', n)
end.
Задание 20
Вычислить площади фигур, ограниченных линиями:
1) y = 0, x = 0, x = 2, y = 1/(x + 1)2 +1;
2) y = cosx, y = 0, x = 0, x =  /2.
Библиотека часто встречающихся процедур и функций
31. Процедура вычисления вероятности биномиального закона распределения.
{ Рекуррентная процедура вычисления вероятности }
{биномиального закона распределения }
Procedure Recurro_binomial(n, m : integer; p : real; var pp : real);
var
i : integer;
begin
Extent(1 - p, n, pp);
for i := 1 to m do pp := (pp*(n - i + 1)*p)/(i*(1 - p))
end;
32. Функция вычисления вероятностей по формуле Пуассона.
{ Функция вычисления вероятности распределения Пуассона }
Function PS(m : integer; a : real) : real;
var
i : integer;
pp : real;
begin
pp := exp(-a);
if m = 0 then pp := exp(-a)
else for i := 1 to m do pp := pp*a/i;
PS := pp
end;
280 
33. Функция вычисления значений функции Гаусса:
{ Функция Гаусса }
Function G(x : real) : real;
begin
G := exp(-sqr(x)/2)/sqrt(2*Pi)
end;
34. Процедура вычисления вероятности по локальной формуле Муавра-Лапласа.
{ Процедура нахожд. вероятн. по локальной форм. Муавра-Лапласа }
Procedure Local_Laplace(n, m : longint; p : real; var pp : real);
var
x : real;
begin
x := (m - n*p)/sqrt(n*p*(1 - p));
pp := G(x)/sqrt(n*p*(1 - p))
end;
35. Функция вычисления интегральной функции Муавра-Лаплапса.
{ Рекуррентная функция вычисления интеграла вероятностей }
{ Пределы интегрирования от 0 до x. Функция Муавра-Лапласа }
Function FF(x : real) : real;
var
n : integer;
u, I : real;
begin
if x >= 5
then FF := 1
else if x <= -5
then FF := -1
else
begin
u := x; n := 0; I := 0;
repeat
I := I + u;
n := n + 1;
u := -u*(x*x*(2*n - 1)/(2*n*(2*n + 1)))
until abs(u) < 0.00001;
FF := 2*I/sqrt(2*Pi)
end
end;
36. Процедура вычисления вероятности появления события из заданного интервала
[m1; m2].
{ Процедура вычисл. вероятн. наст. событ. из промеж. [m1; m2] }
Procedure Interval(n, m1, m2 : longint; p : real; var PP : real);
var
x1, x2 : real;
begin
281

x1 := (m1 - n*p)/sqrt(n*p*(1 - p));
x2 := (m2 - n*p)/sqrt(n*p*(1 - p));
PP := (FF(x2) - FF(x1))/2
end;
37. Процедура вычисления вероятности отклонения частоты m от заданного произведения np.
{ Процедура вычисления вероятности частоты наступления событий }
{ при заданной точности e - отклонении частоты от np }
Procedure Probability(n : longint; p, e : real; var PP : real);
var
x : real;
begin
x := e/sqrt(n*p*(1 - p));
PP := FF(x)
end;
38. Процедура вычисления вероятности отклонения частости от вероятности в одном испытании (по абсолютной величине).
Procedure ProbabilityLap(n : longint; p, e : real; var PP : real);
var
x : real;
begin
x := e*sqrt(n/(p*(1 - p)));
PP := FF(x)
end;
39. Процедура вычисления числа испытаний при заданной гарантированной вероятности и заданной точности частости.
Procedure NumberExperiment(e, PP : real; var n : longint);
var
x : real;
begin
n := 0;
repeat
n := n + 1;
x := 2*e*sqrt(n)
until FF(x) >= PP
end;
Второй способ нахождения значения n. Он основывается на следующей процедуре:
{ Процедура вычисления числа испытаний при заданной гарантиро- }
{ ванной вероятности и заданной точности частости }
Procedure Number2(e, PP : real; var n : longint);
var
x : real;
begin
x := 0;
repeat
282 
x := x + 0.0001
until FF(x) >= PP;
n := trunc(sqr(x/(2*e)))
end;
40. Процедура нахождения аргумента функции Муавра-Лапласа
Procedure Argument(PP : real; var x : real);
begin
x := 0;
repeat
x := x + 0.0001
until FF(x) >= PP
end;
Второй способ
{ Процедура нахождения аргумента функции Муавра-Лапласа }
Procedure Argument(PP, eps : real; var x : real);
begin
x := 0;
repeat
x := x + eps
until FF(x) >= PP
end;
Упражнения
144. Вероятность солнечной погоды в некоторой местности для каждого дня равна
0,4. Какова вероятность того, что в течение трех дней хотя бы один день будет солнечным?
145. Минное заграждение поставлено в одну линию с интервалами между минами в
100 м. Какова вероятность того, что корабль шириной 20 м, пересекая это заграждение
под прямым углом, подорвется на мине? (Размерами мины можно пренебречь.)
146. На окружности радиуса R наудачу выбирается точка. Найти вероятность того,
что выбранная точка будет находиться от точки A, фиксированной на данной окружности,
на расстоянии, не превышающем R.
147. Из фиксированной вершины квадрата произвольным радиусом, меньшим его
диагонали, проведена окружность. Какова вероятность того, что дуга пересечет стороны
квадрата, имеющие эту вершину одним из своих концов?
148. В круг радиуса R вписан правильный шестиугольник. Какова вероятность того,
что наудачу выбранная точка внутри круга окажется внутри шестиугольника?
149. Шар радиуса r = 2 см наудачу бросают в круг радиуса R=25 см, в котором вырезано квадратное отверстие со стороной a = 14 см. Какова вероятность того, что шар пройдет через это отверстие, не задев его края, если он непременно попадет в круг?
150. В 25 см от центра шара, радиус которого равен 15 см, находится точечный источник света. Какова вероятность того, что наудачу взятая точка на поверхности шара
окажется освещенной?
151. На отрезке AB длины a наудачу выбирается точка M, а на отрезке CD длины b точка N. Какова вероятность того, что точки M и N делят отрезки AB и CD так, что отно-
283

| AM |
| CN |
 1 , а отношение
 1 , если точки M и N выбираются независимо друг
| MB|
| DN |
от друга?
152. Точка A наудачу выбирается на окружности, радиус которой равен R, а точка B
- на отрезке CD длины a. Найти вероятность того, что точка A окажется на дуге, длина которой равна R, а точка B окажется расположенной от конца C отрезка CD не далее чем на
0,4а.
153. Какова вероятность того, что две наудачу выбранные точки внутри круга радиуса R окажутся внутри вписанного в этот круг квадрата, если они выбираются независимо
друг от друга?
154. Два действительных числа x и y выбираются наугад независимо друг от друга
так, что сумма их квадратов меньше 64. Какова вероятность того, что сумма положительных x и y окажется меньше восьми?
шение
14. Дополнительные задания
Пример 9. Задача об остроугольном треугольнике. На окружности случайно выбираются три точки. Какова вероятность того, что треугольник с вершинами в этих точках остроугольный? (См. рис. 41).
Решение
Ясно, что при любом повороте окружности вероятности событий и условие "остроугольности" сохраняются; так что мы можем считать, что одна из трех выбираемых вершин A, B, C - скажем, C - фиксирована, а две другие уже выбираются случайно. Будем задавать их положения величинами дуг CA = a, CB = b, отсчитываемых против часовой
стрелки. Будем измерять дуги в радианах, тогда пара (a, b) - это точка в квадрате 0 < a <
2Pi, 0 < b < 2Pi. По теореме о том, что величина вписанного угла измеряется половиной
дуги между его сторонами, углы треугольника ABC равны Pi-b/2, a/2 и (b-a)/2 (мы считаем, что b>a; случай a>b совершенно аналогичен - a и b меняются ролями). Точки (a, b) в
треугольнике a<b<Pi, для которых все три угла A, B, C меньше Pi/2, т.е. b>Pi, a<Pi и ba<Pi, заполняют внутренность меньшего треугольника, образуемого средними линиями
большего. Ситуация в нижнем треугольнике b<a<Pi симметрична относительно диагонали
a=b квадрата. Поэтому искомая вероятность равна
Рис. 41
284 
Program Problem9;
uses WinCrt;
var
x, y, p, e, pp : real;
i, n, m
: longint;
{-------------------------------------------------------------------------------------------}
{ Рекуррентная функция вычисления интеграла вероятностей }
{ Пределы интегрирования от 0 до x. Функция Муавра-Лапласа }
Function FF(x : real) : real;
var
n
: integer;
u, I : real;
begin
if x >= 5
then FF := 1
else if x <= -5
then FF := -1
else
begin
u := x; n := 0; I := 0;
repeat
I := I + u;
n := n + 1;
u := -u*(x*x*(2*n - 1)/(2*n*(2*n + 1)))
until abs(u) < 0.00001;
FF := 2*I/sqrt(2*Pi)
end
end;
{-------------------------------------------------------------------------------------------}
{ Процедура вычисления числа испытаний при заданной гарантиро- }
{ ванной вероятности и заданной точности частости
}
Procedure NumberExperiment(e, PP : real; var n : longint);
var
x : real;
begin
n := 0;
repeat
n := n + 1;
x := 2*e*sqrt(n)
until FF(x) >= PP
end;
{-------------------------------------------------------------------------------------------}
begin
randomize;
write('Введите гарантированную вероятность '); readln(PP);
write('Введите точность вычисления '); readln(e);
NumberExperiment(e, PP, n);
m := 0;
for i := 1 to n do
begin
x := random*2*pi; y := random*2*pi;
if ((y > pi) and (y < x + pi) and (x < pi)) or
285

((y < pi) and (y > x - pi) and (x > pi))
then m := m + 1
end;
p := m/n;
writeln('Искомая вероятность равна ', p:6:4);
writeln('С точностью до ', e:1:6);
writeln('С гарантированной вероятностью ', PP:1:4);
writeln('При числе испытаний ', n)
end.
155. На отрезке [0; 1] случайно выбираются три числа. Какова вероятность того, что
а) выбранное последним число наибольшее? б) числа идут в порядке возрастания?
Пример 10. Какова вероятность того, что при двух бросаниях кубика выпадут а) два
числа с суммой не меньше 10? б) два числа, из которых первое делится на второе?
Идея решения задачи проста. Каждое из двух бросаний мы смоделируем, как получение двух случайных чисел из промежутка [1; 6]. (Число очков на игральном кубике следующее: 1, 2, 3, 4, 5, 6).
Для получения таких чисел можно использовать функции:
x := random(6) + 1 и y := random(6) + 1.
"Бросать" кубик будем не два раза, а количество бросаний предоставим устанавливать пользователю. Из "выпавших" чисел x и y будем подсчитывать число случаев, когда:
а) x + y > +10; б) x mod y = 0.
Это число случаев разделим на общее число бросаний и получим искомую вероятность (фактически мы получим частоту появления событий о чём речь шла выше).
Программы
Program Problem10a;
uses WinCrt;
var
x, y, p, e, pp : real;
i, n, m
: longint;
{-------------------------------------------------------------------------------------------}
{ Рекуррентная функция вычисления интеграла вероятностей }
{ Пределы интегрирования от 0 до x. Функция Муавра-Лапласа }
Function FF(x : real) : real;
var
n
: integer;
u, I : real;
begin
if x >= 5
then FF := 1
else if x <= -5
then FF := -1
else
begin
u := x; n := 0; I := 0;
repeat
I := I + u;
n := n + 1;
286 
u := -u*(x*x*(2*n - 1)/(2*n*(2*n + 1)))
until abs(u) < 0.00001;
FF := 2*I/sqrt(2*Pi)
end
end;
{-------------------------------------------------------------------------------------------}
{ Процедура вычисления числа испытаний при заданной гарантиро- }
{ ванной вероятности и заданной точности частости
}
Procedure NumberExperiment(e, PP : real; var n : longint);
var
x : real;
begin
n := 0;
repeat
n := n + 1;
x := 2*e*sqrt(n)
until FF(x) >= PP
end;
{-------------------------------------------------------------------------------------------}
begin
randomize;
write('Введите гарантированную вероятность '); readln(PP);
write('Введите точность вычисления '); readln(e);
NumberExperiment(e, PP, n);
m := 0;
for i := 1 to n do
begin
x := random(6) + 1; y := random(6) + 1;
if (x + y >= 10) then m := m + 1
end;
p := m/n;
writeln('Искомая вероятность равна ', p:6:4);
writeln('С точностью до ', e:1:6);
writeln('С гарантированной вероятностью ', PP:1:4);
writeln('При числе испытаний ', n)
end.
Program Problem10b;
uses WinCrt;
var
p, e, pp
: real;
x, y, i, n, m : longint;
{----------------------------------------------------------------------------------------}
{ Функция Муавра-Лапласа }
Function FF(x : real) : real;
var
n : integer;
u, I : real;
begin
if x >= 5
then FF := 1
else if x <= -5
287

then FF := -1
else
begin
u := x; n := 0; I := 0;
repeat
I := I + u;
n := n + 1;
u := -u*(x*x*(2*n - 1)/(2*n*(2*n + 1)))
until abs(u) < 0.00001;
FF := 2*I/sqrt(2*Pi)
end
end;
{----------------------------------------------------------------------------------------}
{ Процедура вычисления числа испытаний при заданной гарантиро- }
{ ванной вероятности и заданной точности частости
}
Procedure NumberExperiment(e, PP : real; var n : longint);
var
x : real;
begin
n := 0;
repeat
n := n + 1;
x := 2*e*sqrt(n)
until FF(x) >= PP
end;
{----------------------------------------------------------------------------------------}
begin
randomize;
write('Введите гарантированную вероятность '); readln(PP);
write('Введите точность вычисления '); readln(e);
NumberExperiment(e, PP, n);
m := 0;
for i := 1 to n do
begin
x := random(6) + 1; y := random(6) + 1;
if x mod y = 0 then m := m + 1
end;
p := m/n;
writeln('Искомая вероятность равна ', p:6:4);
writeln('С точностью до ', e:1:6);
writeln('С гарантированной вероятностью ', PP:1:4);
writeln('При числе испытаний ', n)
end.
156. Какова вероятность, что при первом бросании выпадет не меньше 5 очков, а при
втором - не меньше 4?
157. Какова вероятность, что хотя бы при одном из двух бросаний кубика выпадет не
менее 5 очков?
158. Какова вероятность, что количество очков, выпавших при двух бросаниях, отличаются не более чем на 1?
159. (Случайные числа и точки: равномерное распределение). Найдите вероятность
того, что сумма x + y, где x, y - случайные числа на отрезке [0; 1], больше данного числа a.
288 
160. На отрезке [0; 1] случайно выбираются три числа. Какова вероятность того, что
а) выбранное последним число наибольшее? б) числа идут в порядке возрастания?
161. На окружности случайно выбраны четыре точки A, B, C, D. Какова вероятность
того, что отрезки AC и BD пересекаются?
162. а) В окружности проведен диаметр. На нём случайно выбирается точка и через
нее проводится хорда, перпендикулярная диаметру. Какова вероятность, что длина хорды
больше радиуса окружности?
б) На окружности случайно выбираются две точки. Какова вероятность, что длина
соединяющей их хорды больше радиуса?
в) В круге случайно выбрана точка. Какова вероятность, что хорды с серединой в
этой точке больше радиуса?
г) Решите аналогичные задачи про хорду длины r 3 , где r - радиус.
Замечание. Задачи а), б), в) как бы три варианта одной и той же: проведем случайную прямую, пересекающую окружность: какова вероятность, что длина высекаемой хорды больше радиуса? Но ответ в них разный (парадокс Бертрана)!
163. На окружности случайно выбраны три точки. Какова вероятность, что у треугольника с вершинами в этих точках: а) есть угол больше 30 градусов? б) все углы больше 30 градусов? в) все углы меньше 120 градусов?
164. На отрезке случайно выбраны две точки. Какова вероятность, что из отрезков,
на которые он разбит, можно составить треугольник?
165. Плоскость разбита сеткой прямых на а) квадраты; б) правильные треугольники
со стороной 1. Какова вероятность, что монета диаметра 1, случайно брошенная на плоскость, закроет одну из вершин сетки?
166. Найдите вероятность того, что а) выпуклый n-угольник с вершинами в случайных точках окружности содержит ее центр?
б) Докажите, что вероятность того, что n случайно выбранных точек на сфере лежат
на одной полусфере (по одну сторону от некоторого большого круга) равна (n2 - n + 2)/2n.
Ответы
К заданию 2
Так как общее число карточек равно 7, то их можно упорядочить 7! способами. Поскольку обе буквы Т и обе буквы Р можно менять местами, не изменяя слова, то слово
ТРАКТОР получится
2 ! 2 !
2!.2! раза. Искомая вероятность равна:
7!
Иначе тот же результат можно было бы получить, заметив, что в результате извлечения карточек мы получаем перестановку с повторениями состава (2, 2, 1, 1, 1), причем все
такие перестановки имеют одну и ту же вероятность. Так как число перестановок равно
P(2, 2, 1, 1, 1), то вероятность каждой из перестановок
2 ! 2 !
равна P(2, 2, 1, 1, 1) 
.
7!
Program problem2;
uses WinCrt;
var
p
: real;
k1, k : integer;
{----------------------------------------------------------------------------------------}
Procedure fakt(n : integer; var f : integer);
289

var
i : integer;
begin
f := 1;
if n = 0 then f := 1
else for i := 1 to n do f := f*i
end;
{----------------------------------------------------------------------------------------}
begin
fakt(7, k); fakt(2, k1);
p := (k1*k1)/k;
writeln('Вероятность получ. слова "трактор" равна ', p:10:8)
end.
К заданию 3
Приведем лишь математическое решение задачи. Последующее составление программы достаточно простое.
Вычислить: P4(3) и P6(4).
По формуле Бернулли
4
4
2
P4 (3)  C 43  0,4 4  0,6 3 ; P6 ( 4 )  C 6  0,4  0,6 .
Далее необходимо сравнить полученные результаты и сделать вывод.
К заданию 4 (пример 1)
{ Биномиальный закон распределения вероятностей }
Program Problem4_1;
uses WinCrt;
var
p, pp : real;
n, i : integer;
{----------------------------------------------------------------------------------------}
{ Процедура возведения в степень }
Procedure Extent(a : real; n : integer; var e : real);
var
i : integer;
begin
e := 1;
if n = 0 then e := 1
else for i := 1 to n do e := e*a
end;
{----------------------------------------------------------------------------------------}
{ Рекуррентная процедура вычисления биномиального закона }
{ распределения }
Procedure Recurro_binomial(n, k : integer; p : real; var pp : real);
var
i : integer;
begin
290 
Extent(1 - p, n, pp);
for i := 1 to k do pp := (pp*(n - i + 1)*p)/(i*(1 - p))
end;
{----------------------------------------------------------------------------------------}
{ Основная программа }
begin
write('Введите общее число рождений '); readln(n);
write('Введите вероятность рождения мальчика '); readln(p);
writeln('Биномиальный закон распределения вероятностей');
writeln;
for i := 0 to n do write(i:6, ' '); writeln; writeln;
for i := 0 to n do
begin
Recurro_binomial(n, i, p, pp); write(pp:1:4, ' ')
end;
writeln; writeln;
Recurro_binomial(10, 6, p, pp);
writeln('Вероятность того, что из 10 наугад выбранных');
writeln('рождений будет 6 мальчиков, равна ', pp:1:6)
end.
К заданию 7
{ Распределение Пуассона }
Program Problem7;
uses WinCrt;
var
n, m : longint;
p, a : real;
{----------------------------------------------------------------------------------------}
{ Процедура вычисления вероятности распределения Пуассона }
Function PS(m : integer; a : real) : real;
var
i : integer;
pp : real;
begin
pp := exp(-a);
if m = 0 then pp := exp(-a)
else for i := 1 to m do pp := pp*a/i;
PS := pp
end;
{----------------------------------------------------------------------------------------}
{ Основная программа }
begin
write('Введите общее число изделий '); readln(n);
write('Введите вероятность изделия быть бракованным ');
readln(p);
writeln('Введите число бракованных изделий, вероятность ');
write('появления которых Вы находите '); readln(m);
a := n*p;
writeln('Вероятность ', m, ' бракованных изделий в ');
writeln('партии из ',n, ' изделий равна ', PS(m, a):1:6)
end.
291

К заданию 9
{ Применение интегральной формулы Муавра-Лапласа }
Program Problem1;
uses WinCrt;
var
n, m1, m2 : longint;
p, PP : real;
{----------------------------------------------------------------------------------------}
{ Рекуррентная функция вычисления интеграла вероятностей }
{ Пределы интегрирования от 0 до x. Функция Муавра-Лапласа }
Function FF(x : real) : real;
var
n : integer;
u, I : real;
begin
if x >= 5
then FF := 1
else if x <= -5
then FF := -1 else
begin
u := x; n := 0; I := 0;
repeat
I := I + u; n := n + 1;
u := -u*(x*x*(2*n - 1)/(2*n*(2*n + 1)))
until abs(u) < 0.00001;
FF := 2*I/sqrt(2*Pi)
end
end;
{----------------------------------------------------------------------------------------}
{ Процедура вычисл. вероятн. наст. событ. из промеж. [m1; m2] }
Procedure Interval(n, m1, m2 : longint; p : real; var PP : real);
var
x1, x2 : real;
begin
x1 := (m1 - n*p)/sqrt(n*p*(1 - p));
x2 := (m2 - n*p)/sqrt(n*p*(1 - p));
PP := (FF(x2) - FF(x1))/2
end;
{----------------------------------------------------------------------------------------}
{ Основная программа. Число бракованных изделий из промежутка }
begin
write('Введите общее число изделий '); readln(n);
write('Введите вероятность наступление одного события ');
readln(p);
write('Введите левую границу промежутка '); readln(m1);
write('Введите правую границу промежутка '); readln(m2);
Interval(n, m1, m2, p, PP);
writeln('Вероятность того, что число бракованных изделий');
write('находится в промежутке [',m1, '; ', m2, '] равна ');
writeln(PP:1:8)
end.
292 
{ Применение интегральной формулы Муавра-Лапласа }
Program Problem2;
uses WinCrt;
var
n, m1, m2 : longint;
p, q, PP : real;
{----------------------------------------------------------------------------------------}
{ Рекуррентная функция вычисления интеграла вероятностей }
{ Пределы интегрирования от 0 до x. Функция Муавра-Лапласа }
Function FF(x : real) : real;
var
n : integer;
u, I : real;
begin
if x >= 5
then FF := 1
else if x <= -5
then FF := -1
else
begin
u := x; n := 0; I := 0;
repeat
I := I + u; n := n + 1;
u := -u*(x*x*(2*n - 1)/(2*n*(2*n + 1)))
until abs(u) < 0.00001;
FF := 2*I/sqrt(2*Pi)
end
end;
{----------------------------------------------------------------------------------------}
{ Процедура вычисл. вероятн. наст. событ. из промеж. [m1; m2] }
Procedure Interval(n, m1, m2 : longint; p : real; var PP : real);
var
x1, x2 : real;
begin
x1 := (m1 - n*p)/sqrt(n*p*(1 - p));
x2 := (m2 - n*p)/sqrt(n*p*(1 - p));
PP := (FF(x2) - FF(x1))/2
end;
{----------------------------------------------------------------------------------------}
begin
write('Введите общее число изделий '); readln(n);
write('Введите вероятность брака в одном изделии '); readln(q);
write('Введите левую границу промежутка '); readln(m1);
write('Введите правую границу промежутка '); readln(m2);
p := 1 - q;
Interval(n, m1, m2, p, PP);
writeln('Вероятность того, что число пригодных изделий');
write('находится в промежутке [',m1, '; ', m2, '] равна ');
writeln(PP:1:8)
end.
293

К заданию 10
{ Процедура нахождения числа испытаний n, чтобы обеспечить }
{ заданную вероятность отклонения частоты от np }
Procedure Number(p, e, PP : real; var n : longint);
var
x : real;
begin
x := 0;
repeat
x := x + 0.01
until FF(x) >= PP;
n := round(e/(x*sqrt(p*(1 - p))) + 0.5);
n := sqr(n)
end;
{ Применение интегральной формулы Муавра-Лапласа }
Program Task10;
uses WinCrt;
var
n
: longint;
e, q, PP : real;
{----------------------------------------------------------------------------------------}
{ Рекуррентная функция вычисления интеграла вероятностей }
{ Пределы интегрирования от 0 до x. Функция Муавра-Лапласа }
Function FF(x : real) : real;
var
n : integer;
u, I : real;
begin
if x >= 5
then FF := 1
else if x <= -5
then FF := -1
else
begin
u := x; n := 0; I := 0;
repeat
I := I + u;
n := n + 1;
u := -u*(x*x*(2*n - 1)/(2*n*(2*n + 1)))
until abs(u) < 0.00001;
FF := 2*I/sqrt(2*Pi)
end
end;
{----------------------------------------------------------------------------------------}
{ Процедура нахождения числа испытаний n }
Procedure Number(p, e, PP : real; var n : longint);
var
x : real;
begin
x := 0;
294 
repeat
x := x + 0.01
until FF(x) >= PP;
n := round(e/(x*sqrt(p*(1 - p))) + 0.5);
n := sqr(n)
end;
{----------------------------------------------------------------------------------------}
begin
write('Введите вероятность отклонения клемм от принято');
write('го стандарта '); readln(q);
write('Введите число стандартных клемм отличающихся ');
write('от np (по модулю) '); readln(e);
write('Укажите вероятность этого отклонения '); readln(PP);
Number(q, e, PP, n);
writeln('Искомое число взятых наудачу клемм равно ', n)
end.
К заданию 11
{ Процедура определение границы отклонения (ReIection) частости}
{ от заданной вероятности наступления одного события }
Procedure ReIection(n : longint; p, PP, eps : real; var e : real);
var
x : real;
begin
x := 0;
repeat
x := x + eps
until FF(x) >= PP;
e := x*sqrt(p*(1 - p)/n)
end;
{ Применение интегральной формулы Муавра-Лапласа }
Program Task3;
uses WinCrt;
var
n
: longint;
e, eps, p, pp : real;
{----------------------------------------------------------------------------------------}
{ Рекуррентная функция вычисления интеграла вероятностей }
{ Пределы интегрирования от 0 до x. Функция Муавра-Лапласа }
Function FF(x : real) : real;
var
n : integer;
u, I : real;
begin
if x >= 5
then FF := 1
else if x <= -5
then FF := -1
else
begin
295

u := x;
n := 0;
I := 0;
repeat
I := I + u;
n := n + 1;
u := -u*(x*x*(2*n - 1)/(2*n*(2*n + 1)))
until abs(u) < 0.00001;
FF := 2*I/sqrt(2*Pi)
end
end;
{----------------------------------------------------------------------------------------}
{ Процедура определение границы отклонения (ReIection) частости}
{ от заданной вероятности наступления одного события }
Procedure ReIection(n : longint; p, PP, eps : real; var e : real);
var
x : real;
begin
x := 0;
repeat
x := x + eps
until FF(x) >= PP;
e := x*sqrt(p*(1 - p)/n)
end;
{----------------------------------------------------------------------------------------}
{ Основная программа }
begin
write('Введите вероятность события в каждом испытании '); readln(p);
write('Введите общее число произведенных испытаний '); readln(n);
write('Укажите гарантированную вероятность '); readln(PP);
write('Укажите точность вычисления искомой величины '); readln(eps);
ReIection(n, p, PP, eps, e);
writeln('Искомая граница отклонения частости от вероят-');
write('ности будет находиться в промежутке ');
writeln('[', p-e:1:4, '; ', p+e:1:4, ']')
end.
К заданию 12
{ Применение интегральной формулы Муавра-Лапласа }
Program Problem12;
uses WinCrt;
var
n
: longint;
e, p, PP : real;
{----------------------------------------------------------------------------------------}
{ Рекуррентная функция вычисления интеграла вероятностей }
{ Пределы интегрирования от 0 до x. Функция Муавра-Лапласа }
Function FF(x : real) : real;
var
n : integer;
u, I : real;
296 
begin
if x >= 5
then FF := 1
else if x <= -5
then FF := -1
else
begin
u := x; n := 0; I := 0;
repeat
I := I + u;
n := n + 1;
u := -u*(x*x*(2*n - 1)/(2*n*(2*n + 1)))
until abs(u) < 0.00001;
FF := 2*I/sqrt(2*Pi)
end
end;
{----------------------------------------------------------------------------------------}
{ Процедура нахождения числа испытаний n, чтобы обеспечить }
{ заданную вероятность отклонения частности от заданного числа }
Procedure Number3(p, e, PP : real; var n : longint);
var
x : real;
begin
x := 0;
repeat
x := x + 0.01
until FF(x) >= PP;
n := round((x*sqrt(p*(1 - p))/e) + 0.5);
n := sqr(n)
end;
{----------------------------------------------------------------------------------------}
{ Основная программа }
begin
write('Введите постоянную для каждого испытания ');
write('вероятность '); readln(p);
writeln('Введите число, от которого по абсолютной ');
write('величине должна отличаться частость '); readln(e);
write('Укажите гарантированную вероятность '); readln(PP);
writeln;
Number3(p, e, PP, n);
writeln('Число испытаний должно быть больше или равно ', n)
end.
К заданию 15
Program Normal1;
uses WinCrt;
var
PP, x, l, c : real;
{-----------------------------------------------------------------------------------------}
{ Функция Муавра-Лапласа }
Function FF(x : real) : real;
297

var
n : integer;
u, I : real;
begin
if x >= 5
then FF := 1
else if x <= -5
then FF := -1
else
begin
u := x; n := 0; I := 0;
repeat
I := I + u;
n := n + 1;
u := -u*(x*x*(2*n - 1)/(2*n*(2*n + 1)))
until abs(u) < 0.00001;
FF := 2*I/sqrt(2*Pi)
end
end;
{----------------------------------------------------------------------------------------}
{ Процедура нахождения аргумента x }
Procedure Argument(PP : real; var x : real);
begin
x := 0;
repeat
x := x + 0.0001
until FF(x) >= PP
end;
{----------------------------------------------------------------------------------------}
begin
write('Введите среднее квадратическое отклонение '); readln(c);
write('Введите вероятность попадания в интервал, симметричн. M(X) ');
readln(PP);
Argument(PP, x);
l := 2*c*x;
writeln('Длина искомого интервала равна ', L:4:6)
end.
Ответ к задаче 2 задания
По формуле (6) находим   3 .
Указание
Ответ
0.06.
Program Exercise_Normal2;
uses WinCrt;
var
PP, x, a, d, e, c : real;
{----------------------------------------------------------------------------------------}
{ Функция Муавра-Лапласа }
Function FF(x : real) : real;
var
298 
n : integer;
u, I : real;
begin
if x >= 5
then FF := 1
else if x <= -5
then FF := -1
else
begin
u := x; n := 0; I := 0;
repeat
I := I + u;
n := n + 1;
u := -u*(x*x*(2*n - 1)/(2*n*(2*n + 1)))
until abs(u) < 0.00001;
FF := 2*I/sqrt(2*Pi)
end
end;
{----------------------------------------------------------------------------------------}
{ Процедура нахождения аргумента x }
Procedure Argument(PP : real; var x : real);
begin
x := 0;
repeat
x := x + 0.0001
until FF(x) >= PP
end;
{----------------------------------------------------------------------------------------}
begin
write('Введите среднее значение ');
writeln('нормально распределенной случайной величины a = M(X) ');
write('т.е. средний диаметр детали '); readln(a);
write('Введите дисперсию '); readln(d);
writeln('Введите гарантированную вероятность');
write('отклонения детали от среднего размера '); readln(PP);
Argument(PP, x);
c := sqrt(d);
e := c*x;
writeln('Максимальное отклонение диаметра от среднего равно ', e:2:6)
end.
Ответ к задаче 3 задания
а) 0.9986; б) 0.7823.
Program Exercise_Normal13a;
uses WinCrt;
var
e, c, d, pp, p1, sum : real;
n, m, i
: integer;
{----------------------------------------------------------------------------------------}
{ Функция Муавра-Лапласа }
Function FF(x : real) : real;
var
299

n : integer;
u, I : real;
begin
if x >= 5
then FF := 1
else if x <= -5
then FF := -1
else
begin
u := x; n := 0; I := 0;
repeat
I := I + u;
n := n + 1;
u := -u*(x*x*(2*n - 1)/(2*n*(2*n + 1)))
until abs(u) < 0.00001;
FF := 2*I/sqrt(2*Pi)
end
end;
{----------------------------------------------------------------------------------------}
{ Процедура возведения в степень }
Procedure Extent(a : real; n : integer; var e : real);
var
i : integer;
begin
e := 1;
if n = 0 then e := 1 else for i := 1 to n do e := e*a
end;
{--------------------------------------------------------------------------------------}
{ Рекуррентная процедура вычисления вероятности }
{ биномиального закона распределения }
Procedure Recurro_binomial(n, m : integer; p : real; var p1 : real);
var
i : integer;
begin
Extent(1 - p, n, p1);
for i := 1 to m do p1 := (p1*(n - i + 1)*p)/(i*(1 - p))
end;
{----------------------------------------------------------------------------------------}
begin
write('Введите дисперсию '); readln(d); c := sqrt(d);
write('Введите отклонение детали от заданного размера '); readln(e);
write('Введите число измерений '); readln(n);
write('Введите допускаемое число появления ощибок '); readln(m);
pp := 1 - FF(e/c);
sum := 0;
for i := 0 to m do
begin
Recurro_binomial(n, i, pp, p1);
sum := sum + p1
end;
writeln('Вероятность брака равна ', sum:1:6)
end.
300 
К заданию 16
Program Task16_1;
uses WinCrt;
var
x, y, p, e, pp : real;
i, n, m, a, b : longint;
{----------------------------------------------------------------------------------------}
{ Рекуррентная функция вычисления интеграла вероятностей }
{ Пределы интегрирования от 0 до x. Функция Муавра-Лапласа }
Function FF(x : real) : real;
var
n : integer;
u, I : real;
begin
if x >= 5
then FF := 1
else if x <= -5
then FF := -1
else
begin
u := x; n := 0; I := 0;
repeat
I := I + u; n := n + 1;
u := -u*(x*x*(2*n - 1)/(2*n*(2*n + 1)))
until abs(u) < 0.00001;
FF := 2*I/sqrt(2*Pi)
end
end;
{----------------------------------------------------------------------------------------}
{ Процедура вычисления числа испытаний при заданной гарантиро- }
{ ванной вероятности и заданной точности частости
}
Procedure NumberExperiment(e, PP : real; var n : longint);
var
x : real;
begin
n := 0;
repeat
n := n + 1; x := 2*e*sqrt(n)
until FF(x) >= PP
end;
{----------------------------------------------------------------------------------------}
begin
randomize;
write('Введите длину отрезка - a = '); readln(a);
write('Введите расстояние b от точки A '); readln(b);
write('Введите гарантированную вероятность '); readln(PP);
write('Введите точность вычисления '); readln(e);
NumberExperiment(e, PP, n);
m := 0;
for i := 1 to n do
begin
301

x := random*a; y := random*a;
if (x <= b) and (y <= b) then m := m + 1
end;
p := m/n;
writeln('Искомая вероятность равна ', p:6:4);
writeln('С точностью до ', e:1:6);
writeln('С гарантированной вероятностью ', PP:1:4);
writeln('При числе испытаний ', n)
end.
Program Task16_2;
uses WinCrt;
var
x, y, p, a, q, k1, h, e, pp : real;
i, n, k, m
: longint;
{----------------------------------------------------------------------------------------}
{ Рекуррентная функция вычисления интеграла вероятностей }
{ Пределы интегрирования от 0 до x. Функция Муавра-Лапласа }
Function FF(x : real) : real;
var
n : integer;
u, I : real;
begin
if x >= 5
then FF := 1
else if x <= -5
then FF := -1
else
begin
u := x; n := 0; I := 0;
repeat
I := I + u; n := n + 1;
u := -u*(x*x*(2*n - 1)/(2*n*(2*n + 1)))
until abs(u) < 0.00001;
FF := 2*I/sqrt(2*Pi)
end
end;
{----------------------------------------------------------------------------------------}
{ Процедура вычисления числа испытаний при заданной гарантиро- }
{ ванной вероятности и заданной точности частости
}
Procedure NumberExperiment(e, PP : real; var n : longint);
var
x : real;
begin
n := 0;
repeat
n := n + 1; x := 2*e*sqrt(n)
until FF(x) >= PP
end;
{----------------------------------------------------------------------------------------}
begin
randomize;
302 
write('Введите длину стороны BC '); readln(a);
write('Введите высоту трапеции '); readln(h);
write('Введите величину угла BAE < Pi/2 в рад '); readln(q);
write('Введите гарантированную вероятность '); readln(PP);
write('Введите точность вычисления '); readln(e);
NumberExperiment(e, PP, n);
k := 0; m := 0; k1 := sin(q)/cos(q);
for i := 1 to n do
begin
x := random*(2*h/k1 + a); y := random*h;
if (y < k1*x) and (y < -k1*x + k1*(2*h/k1 + a)) then k := k + 1;
if ((x < h/k1) and (y < k1*x)) or ((x > a + h/k1) and
(y < -k1*x + k1*(2*h/k1 + a))) then m := m + 1
end;
p := m/k;
writeln('Искомая вероятность равна ', p:6:4);
writeln('С точностью до ', e:1:6);
writeln('С гарантированной вероятностью ', PP:1:4);
writeln('При числе испытаний ', n)
end.
К заданию 17
Пусть событие E - точка оказалась внутри куба с ребром, равным 3 см. Будем считать, что исходы испытания распределены равномерно. Тогда вероятность наступления
события E пропорциональна мере этого куба и равна:
V
P( E )  1 , где V1 - объем куба,
V2
V2 - объем параллелепипеда.
Program Task17;
uses WinCrt;
var
x, y, z, p, e, pp : real;
i, n, s
: longint;
{----------------------------------------------------------------------------------------}
{ Рекуррентная функция вычисления интеграла вероятностей }
{ Пределы интегрирования от 0 до x. Функция Муавра-Лапласа }
Function FF(x : real) : real;
var
n : integer;
u, I : real;
begin
if x >= 5
then FF := 1
else if x <= -5
then FF := -1
else
begin
u := x; n := 0; I := 0;
repeat
I := I + u;
303

n := n + 1;
u := -u*(x*x*(2*n - 1)/(2*n*(2*n + 1)))
until abs(u) < 0.00001;
FF := 2*I/sqrt(2*Pi)
end
end;
{----------------------------------------------------------------------------------------}
{ Процедура вычисления числа испытаний при заданной гарантиро- }
{ ванной вероятности и заданной точности частости
}
Procedure NumberExperiment(e, PP : real; var n : longint);
var
x : real;
begin
n := 0;
repeat
n := n + 1;
x := 2*e*sqrt(n)
until FF(x) >= PP
end;
{----------------------------------------------------------------------------------------}
begin
randomize;
write('Введите гарантированную вероятность '); readln(PP);
write('Введите точность вычисления '); readln(e);
NumberExperiment(e, PP, n);
s := 0;
for i := 1 to n do
begin
x := random*4; y := random*6; z := random*10;
if (x < 3) and (y < 3) and (z < 3) then s := s + 1
end;
p := s/n;
writeln('Вероятность появление точки внутри куба ', p:6:4);
writeln('С точностью до ', e:1:6);
writeln('С гарантированной вероятностью ', PP:1:4);
writeln('При числе испытаний ', n)
end.
К заданию 18
Program Task18_1;
uses WinCrt;
var
x, y, p, e, pp : real;
i, n, m : longint;
{----------------------------------------------------------------------------------------}
{ Рекуррентная функция вычисления интеграла вероятностей }
{ Пределы интегрирования от 0 до x. Функция Муавра-Лапласа }
Function FF(x : real) : real;
var
n : integer;
u, I : real;
304 
begin
if x >= 5
then FF := 1
else if x <= -5
then FF := -1
else
begin
u := x; n := 0; I := 0;
repeat
I := I + u;
n := n + 1;
u := -u*(x*x*(2*n - 1)/(2*n*(2*n + 1)))
until abs(u) < 0.00001;
FF := 2*I/sqrt(2*Pi)
end
end;
{----------------------------------------------------------------------------------------}
{ Процедура вычисления числа испытаний при заданной гарантиро- }
{ ванной вероятности и заданной точности частости
}
Procedure NumberExperiment(e, PP : real; var n : longint);
var
x : real;
begin
n := 0;
repeat
n := n + 1;
x := 2*e*sqrt(n)
until FF(x) >= PP
end;
{----------------------------------------------------------------------------------------}
begin
randomize;
write('Введите гарантированную вероятность '); readln(PP);
write('Введите точность вычисления '); readln(e);
NumberExperiment(e, PP, n);
m := 0;
for i := 1 to n do
begin
x := random*12;
y := random*12;
if (y > x - 3) and (y < x + 3) then m := m + 1
end;
p := m/n;
writeln('Искомая вероятность равна ', p:6:4);
writeln('С точностью до ', e:1:6);
writeln('С гарантированной вероятностью ', PP:1:4);
writeln('При числе испытаний ', n)
end.
305

Program Task18_2;
uses WinCrt;
var
x, y, p, e, pp : real;
i, n, m
: longint;
{----------------------------------------------------------------------------------------}
{ Рекуррентная функция вычисления интеграла вероятностей }
{ Пределы интегрирования от 0 до x. Функция Муавра-Лапласа }
Function FF(x : real) : real;
var
n : integer;
u, I : real;
begin
if x >= 5
then FF := 1
else if x <= -5
then FF := -1
else
begin
u := x; n := 0; I := 0;
repeat
I := I + u;
n := n + 1;
u := -u*(x*x*(2*n - 1)/(2*n*(2*n + 1)))
until abs(u) < 0.00001;
FF := 2*I/sqrt(2*Pi)
end
end;
{----------------------------------------------------------------------------------------}
{ Процедура вычисления числа испытаний при заданной гарантиро- }
{ ванной вероятности и заданной точности частости
}
Procedure NumberExperiment(e, PP : real; var n : longint);
var
x : real;
begin
n := 0;
repeat
n := n + 1;
x := 2*e*sqrt(n)
until FF(x) >= PP
end;
{----------------------------------------------------------------------------------------}
begin
randomize;
write('Введите гарантированную вероятность '); readln(PP);
write('Введите точность вычисления '); readln(e);
NumberExperiment(e, PP, n);
m := 0;
for i := 1 to n do
begin
x := random*20;
y := random*20;
306 
if (y > x - 5) and (y < x + 5) and (y > x - 2) and (y < x + 2)
then m := m + 1
end;
p := (2*m)/n;
writeln('Искомая вероятность равна ', p:6:4);
writeln('С точностью до ', e:1:6);
writeln('С гарантированной вероятностью ', PP:1:4);
writeln('При числе испытаний ', n)
end.
К заданию 19
Program Task19;
uses WinCrt;
var
p, x, y, z, e, pp : real;
i, n, m
: longint;
{----------------------------------------------------------------------------------------}
{ Рекуррентная функция вычисления интеграла вероятностей }
{ Пределы интегрирования от 0 до x. Функция Муавра-Лапласа }
Function FF(x : real) : real;
var
n : integer;
u, I : real;
begin
if x >= 5
then FF := 1
else if x <= -5
then FF := -1
else
begin
u := x; n := 0; I := 0;
repeat
I := I + u;
n := n + 1;
u := -u*(x*x*(2*n - 1)/(2*n*(2*n + 1)))
until abs(u) < 0.00001;
FF := 2*I/sqrt(2*Pi)
end
end;
{----------------------------------------------------------------------------------------}
{ Процедура вычисления числа испытаний при заданной гарантиро- }
{ ванной вероятности и заданной точности частости
}
Procedure NumberExperiment(e, PP : real; var n : longint);
var
x : real;
begin
n := 0;
repeat
n := n + 1;
x := 2*e*sqrt(n)
until FF(x) >= PP
end;
307

{----------------------------------------------------------------------------------------}
begin
randomize;
write('Введите гарантированную вероятность '); readln(PP);
write('Введите точность вычисления '); readln(e);
NumberExperiment(e, PP, n);
m := 0;
for i := 1 to n do
begin
x := random; y := random; z := random;
if ((x < 1/3) and (y > 1/3) and (y < 2/3) and (z > 2/3)) or
((y < 1/3) and (x > 1/3) and (x < 2/3) and (z > 2/3)) or
((y < 1/3) and (z > 1/3) and (z < 2/3) and (x > 2/3)) or
((z < 1/3) and (x > 1/3) and (x < 2/3) and (y > 2/3)) or
((z < 1/3) and (y > 1/3) and (y < 2/3) and (x > 2/3)) or
((x < 1/3) and (z > 1/3) and (z < 2/3) and (y > 2/3))
then m := m + 1
end;
p := m/n;
writeln('Искомая вероятность равна ', p:6:4);
writeln('С точностью до ', e:1:6);
writeln('С гарантированной вероятностью ', PP:1:4);
writeln('При числе испытаний ', n)
end.
308 
Глава 10. Числовые последовательности
Начнем с определения последовательности. Определений числовой последовательности дается много, причем самых разных и достаточно понятных, но, по моим соображениям, самое лучшее с точки зрения и математической строгости и доступности дается в
книге: "Курс дифференциального и интегрального исчисления", т. 1 Г.М. Фихтенгольца. Я
привожу его с незначительными изменениями.
Представим себе натуральный ряд:
1, 2, 3, ..., n, ..., n', ...,
в котором числа расположены в порядке возрастания, так что большее число n' следует за меньшим числом n (или меньшее n предшествует большему числу n'). Если
теперь заменить в этом ряде, по какому-нибудь закону каждое натуральное число n
некоторым вещественным числом xn , то получится числовая последовательность:
x1, x2, x3, ..., xn, ..., xn', ...,
члены или элементы которой xn занумерованы всеми натуральными числами и расположены в порядке возрастания номеров. При n'>n, член xn' следует за членом xn (xn
предшествует xn' ), независимо от того, будет ли само число xn' больше, меньше или
даже равно числу xn.
В школьном курсе математики вы уже знакомились с последовательностями вида
a, a  d, a  2d, ..., a  ( n  1)d, ... - арифметическая прогрессия;
1
2
3
n
или вида
a, aq, aq 2 , ..., aq n1 , ... - геометрическая прогрессия.
1
2
3
n
В связи с определением длины окружности обычно рассматривается переменный
периметр правильного вписанного в окружность многоугольника, получаемого из шестиугольника последовательным удвоением числа сторон; таким образом, получается следующая последовательность:
p6  6R , p12  12R 2 3 , p24  24R 2 2 3 , p48 , ...
1
2
3
4
Упомянем еще о десятичном приближении (скажем, по недостатку) к
возрастающей точностью; оно принимает последовательность значений:
14
, ; 141
, ; 1414
, ; 14142
,
; ...
1
2
3
2 , со всё
4
Иногда последовательность задается тем, что указывается непосредственно выражение для xn; так, в случае арифметической или геометрической прогрессии имеем, соответственно, x n  a  d(n  1) или x n  aq n1 . Пользуясь этим выражением, можно сразу
вычислять любое значение элемента последовательности по заданному его номеру, не вычисляя предыдущих значений.
В других случаях нам может быть неизвестно выражение для общего члена x n последовательности.
Тем не менее, последовательность считается заданной, если мы владеем правилом, по которому может быть вычислен любой ее член, лишь только известен его
номер.
Поэтому-то, зная правило для приближенного вычисления корней, мы можем считать заданной всю последовательность десятичных приближений к 2 , хотя выражения
для его общего члена мы не знаем. Можно сказать, что в этом случае последовательность
задается "словесным описанием".

309
Если последовательность - в указанном смысле - задана, то этим не только охарактеризовано все множество принимаемых ею значений в целом, но и определен порядок, в
котором эти значения принимаются; каждому номеру отвечает свое значение элемента
последовательности, и из двух значений то считается следующим, номер которого больше.
Еще подчеркнем, что значения элементов последовательности не должны быть обязательно различными. Например, если задать последовательность одной из формул:
1  (1) n
x n  1; x n  (1) n1 ; x n 
,
n
то соответствующие последовательности будут:
элементы: 1, 1, 1, 1, 1, 1, . ..
их номера: 1, 2, 3, 4, 5, 6, . ..
элементы: 1, -1, 1, -1, 1, -1, . ..
их номера: 1, 2, 3, 4, 5, 6, . ..
1
1
элементы: 0, 1, 0,
, 0,
, . ..
2
3
их номера: 1, 2, 3, 4, 5, 6, . ..
В первом случае мы имеем просто постоянную величину, всё "множество" принимаемых ею значений сводится к одному.
Во втором - это множество состоит из двух значений, 1 или -1, принимаемых поочередно. Наконец, в третьем случае множество значений бесконечно, но это не мешает
значениям элементов через одно равняться 0; и мы считаем, что значение 0 на пятом месте
следует не только за 1 на втором месте, но и за значением 0 на первом месте.
Еще один способ задания последовательности - это рекуррентная формула. Вспомним, что это такое.
Формулу, выражающую любой член последовательности, начиная с некоторого, через предыдущие (один или несколько), называют рекуррентной (от латинского слова
recurro - возвращаться).
Подводя итог вышеизложенного можно назвать три основных способа задания последовательности.
1. Аналитический - последовательность задается формулой общего (или n-го) члена.
2. Рекуррентный - любой член последовательности, начиная с некоторого, выражается через предшествующие члены. При этом способе задания последовательности указывают ее первый член или несколько начальных членов и формулу, позволяющую определить любой член последовательности по известным предшествующим членам.
3. Словесный - задание последовательности описанием.
Надо сразу заметить, что для составления программ чаще нам придется использовать
рекуррентное соотношение. Покажем это на примере.
Пример 1. Составить программу вывода на экран членов последовательности, за10 n
данной следующей формулой: an 
.
n!
Для составления программы необходимо перейти от формулы n-го члена, которым
задана последовательность к рекуррентному соотношению, связывающему предыдущий
член с последующим и указать начальное значение для первого или "нулевого" элемента.
Как это сделать? Оказывается очень просто!
310 
1. Запишем, чему будет равен член последовательности предыдущий к n - му, т. е. n10 n1
1 - й элемент последовательности: an1 
.
(n  1)!
2. Теперь разделим n - й элемент на n-1 - й, получим:
10 n
an
10 n  (n  1)! 10
n!


 .
an1
n
10 n1
10 n1  n !
(n  1)!
10
10
3. Отсюда выразим, чему будет равен n-й член: an  an1  , an   an1 .
n
n
10 0 1
  1, a0  1.
4. Найдем начальное значение a0 : a0 
0! 1
Процедуру можно построить из одного цикла с параметром, в котором каждый раз
при выполнении цикла предыдущее значение будет умножаться на 10 и делится на значение переменной цикла, которая обозначена n.
Procedure Create_succession(k : integer);
var
n : integer;
a : real;
begin
a := 1;
writeln('Искомая последовательность');
for n := 1 to k do
begin
a := a*10/n;
write(a:6:6, ' ')
end;
writeln
end;
Программа
Program Problem1; {Вывод членов последовательности}
uses WinCrt;
var
k : integer;
{---------------------------------------------------------------------------------------}
Procedure Create_succession(k : integer);
var
n : integer;
a : real;
begin
a := 1;
writeln('Искомая последовательность');
for n := 1 to k do
begin
a := a*10/n;
write(a:6:6, ' ')
end;
311

writeln
end;
{---------------------------------------------------------------------------------------}
begin
write('Введите число элементов '); readln(k);
Create_succession(k);
end.
Пример 2. Составим программу вывода на экран членов последовательности, описываемой словесно, в частности, десятичных приближений числа 2 с недостатком.
Вот здесь дело обстоит сложнее. Закон, по которому строится последовательность
указан словесно. Надо от словесного задания правила перейти к рекуррентной формуле.
А есть ли формула для вычисления квадратных корней? Оказывается есть и достаточно простая.
Рассмотрим бесконечную последовательность x1, x2, x3, ..., образованную по следующему закону:
u 1
1 
u 
x1 
, x i    x i 1 
 , i  2, 3, ...
2
2 
x i 1 
Оказывается, что члены этой последовательности с увеличением номера i всё меньше и меньше отличается от u (этот факт был известен Герону Александрийскому в 1 веке н. э.). Пусть, например, u = 2. Вычисление первых членов последовательности x1, x2, x3,
... дает нам
2 1
x1 
 15
. ,
2
1 
2
x 2   15
.    14166666
.
,
2 
15
. 
1 
2

 14166666
.

.
,
  14142156

2 
14166666
.
1 
2

x 4   14142156
.

.
.
  14142135

2 
14142156
.
x3 
Напомним, что 2 = 1.4142135...
Мы можем, используя данное рекуррентное соотношение, составить процедуру и
программу вычисления квадратных корней для любого действительного подкоренного
выражения, а не только 2.
Program Problem2;
uses WinCrt;
var
n : integer;
u : real;
{----------------------------------------------------------------------------------------}
Procedure Square_root(n : integer; u : real);
var
i : integer;
x : real;
begin
writeln('Десятичные приближ. с недост. кв. корня из ', u);
x := (u + 1)/2;
312 
for i := 1 to n do
begin
x := (1/2)*(x + u/x);
write(x:3:i, ' ')
end;
writeln
end;
{---------------------------------------------------------------------------------------}
begin
write('Введите подкоренное выражение '); readln(u);
write('Введите число членов последовательн. '); readln(n);
Square_root(n, u);
end.
Вычислим приближенное значение квадратного корня из заданного числа с указанной точностью eps. Теперь нам не надо выводить на экран все члены последовательности,
а выдать только одно значение удовлетворяющее указанной точности.
Например, поставлена задача получить квадратный корень из 2 с точностью до 0.01.
На экран должно быть выдано значение этого корня (причем совсем не обязательно, чтобы в его записи было два знака после запятой, их может быть больше, но мы будем заведомо знать, что знаки после сотых долей не являются точными).
Такие программы можно составить двумя способами.
Способ первый состоит в том, что цикл будет продолжаться до тех пор, пока разность между квадратом получаемого результата и подкоренным выражением по абсолютной величине не станет меньше или равна указанной точности eps. Тогда цикл заканчивается и выдается результат.
1-й способ
Program Problem2a;
uses WinCrt;
var
u
: longint;
x, eps : real;
{----------------------------------------------------------------------------------------}
Procedure Square_root1(eps, u : real; var x : real);
begin
x := (u + 1)/2;
repeat
x := (1/2)*(x + u/x)
until abs(x*x - u) <= eps
end;
{---------------------------------------------------------------------------------------}
begin
write('Введите подкоренное выражение '); readln(u);
write('Задайте точность вычисления '); readln(eps);
Square_root1(eps, u, x);
writeln('Квадратный корень из ', u, ' равен ', x:12:12);
writeln(' с точностью до ', eps:3:12)
end.
313

Во втором способе вычисляются два члена последовательности и их разность по абсолютной величине сравнивается с заданной точностью. Как только эта разность станет
равна или меньше указанной точности eps цикл заканчивается.
2-й способ
Program Problem2b;
uses WinCrt;
var
u
: longint;
x, eps : real;
{----------------------------------------------------------------------------------------}
Procedure Square_root2(eps, u : real; var x : real);
var
x1, x2 : real;
begin
x1 := 1;
repeat
x1 := (1/2)*(x1 + u/x1);
x2 := (1/2)*(x1 + u/x1)
until abs(x2 - x1) <= eps;
x := x2
end;
{---------------------------------------------------------------------------------------}
begin
write('Введите подкоренное выражение '); readln(u);
write('Задайте точность вычисления '); readln(eps);
Square_root2(eps, u , x );
writeln('Квадратный корень из ', u, ' равен ', x:12:12);
writeln('с точностью до ', eps:3:12)
end.
Разберите содержание этих программ и выполните их на компьютере. В чем отличие
этих двух способов? Какой из них вы считаете более рациональным и почему?
Измените каждую из этих программ так, чтобы на экран выдавались последовательно десятичные приближения корней с недостатком? С избытком?
Если вы внимательно разобрались в составлении и работе предыдущих программ, то
могли заметить, что в программе примера 2, несмотря на то, что математически последовательность задана формулой n-го члена, используется рекуррентное соотношение. Указывается начальное значение a := 1, а затем каждый цикл предыдущее значение умножает10
ся на постоянный множитель:
.
n
Таким образом, при составлении программ чаще всего будет использоваться рекуррентное соотношение. Возникает закономерный вопрос. Как перейти от задания последовательности формулой n-го члена к рекуррентному соотношению?
Разберем этот процесс на частном примере.
Пример.. Пусть задана последовательность с помощью формулы n-го члена, напри2n  1
мер: an  n . Находим с ее помощью (n - 1)-й член:
2
2(n  1)  1 2n  3
an1 
 n1 .
2 n1
2
314 
Разделим n-й член на (n-1)-й, получим:
2n  1
an
2n  1
2n


.
an1 2n  3 4n  6
2 n1
2n  1
.
4n  6
Одной формулы недостаточно, еще необходимо задать некоторые начальные значения, первые члены последовательности, желательно нулевой член.
Получаем:
2  0 1 1
2n  1
a0 

 1 и an  an1 
.
0
1
4n  6
2
Итак, если последовательность задана формулой n-го члена, тогда, чтобы задать ее
рекуррентной формулой, необходимо найти частное от деления n-го члена на (n - 1)-й, а
затем умножить (n - 1)-й член на частное. Это произведение будет равно n-му члену и мы
получаем нужную формулу. К ней необходимо добавить значение некоторых первых членов и, таким образом, последовательность будет задана. Коротко этот процесс можно записать так:
an
 k , an  an1  k , a0  c.
an1
Отсюда легко получить рекуррентную формулу: an  an1 
После выполнения программы вы, конечно, обратили внимание на то, что независимо от того какую точность вы указываете значение результата будут выдаваться с 12-ю
знаками после запятой (такой формат задан в программе). И нам трудно определить
сколько десятичных знаков являются верными.
Было бы очень удобно, указав точность, получать в результате только требуемое количество десятичных знаков, например, указав 0.001, мы получали бы в результате 3 знака
после запятой и не более.
Это можно сделать с помощью следующей функции:
{ Функция вычисления порядка - кол-во знаков после запятой }
Function t(eps : real) : integer;
var
k : integer;
begin
k := -1;
repeat
eps := eps*10;
k := k + 1
until eps > 1;
t := k
end;
Ее работа проста. Введенное значение точности (eps) последовательно умножается
на 10 до тех пор, пока ее значение не станет больше 1.
Например, для значения eps = 0.001 процесс определения порядка будет проходить
так: 0.001  10, 0.01  10, 01
.  10, 1  10.
Переменная k подсчитывает число выполняемых циклов. Но число циклов будет на
1 больше, чем количество знаков после запятой. Почему? Да потому, что цикл выполняется до тех пор пока, пока значение eps станет больше 1. Это сделано из тех соображений,
что значение eps никогда не станет точно равно 1, ибо для этой переменной установлен
315

вещественный тип real, а это значит, что eps не будет равно целому числу, хотя в примере
кажется, что 01
.  10  1, но это не так. Фактическое значение в этом случае может выражаться числом 0.99999999... . Чтобы устранить неудобства, первоначальному значению k
задано значение -1, а останов цикла выполняется после eps > 1.
Добавляя эту функцию в программу, легко использовать ее для вывода результата с
требуемым числом десятичных знаков.
Тогда, две вышеприведенные программы могут быть построены так:
Program Problem2a;
uses WinCrt;
var
u
: longint;
x, eps : real;
{----------------------------------------------------------------------------------------}
{ Функция вычисления порядка - кол-во знаков после запятой }
Function t(eps : real) : integer;
var
k : integer;
begin
k := -1;
repeat
eps := eps*10;
k := k + 1
until eps > 1;
t := k
end;
{---------------------------------------------------------------------------------------}
Procedure Square_root(eps, u : real; var x : real);
begin
x := (u + 1)/2;
repeat
x := (1/2)*(x + u/x)
until abs(x*x - u) <= eps
end;
{---------------------------------------------------------------------------------------}
begin
write('Введите подкоренное выражение '); readln(u);
write('Задайте точность вычисления '); readln(eps);
Square_root(eps, u, x);
writeln('Квадратный корень из ', u, ' равен ', x:6:t(eps));
writeln('С точностью до ', eps:1:t(eps))
end.
Program Problem2b;
uses WinCrt;
var
u
: longint;
x, eps : real;
{----------------------------------------------------------------------------------------}
{ Функция вычисления порядка - кол-во знаков после запятой }
Function t(eps : real) : integer;
var
316 
k : integer;
begin
k := -1;
repeat
eps := eps*10;
k := k + 1
until eps > 1;
t := k
end;
{---------------------------------------------------------------------------------------}
Procedure Square_root(eps, u : real; var x : real);
var
x1, x2 : real;
begin
x1 := 1;
repeat
x1 := (1/2)*(x1 + u/x1);
x2 := (1/2)*(x1 + u/x1)
until abs(x2 - x1) <= eps;
x := x2
end;
{----------------------------------------------------------------------------------------}
{ Основная программа }
begin
write('Введите подкоренное выражение '); readln(u);
write('Задайте точность вычисления '); readln(eps);
Square_root(eps, u, x);
writeln('Квадратный корень из ', u, ' равен ', x:6:t(eps));
writeln('С точностью до ', eps:1:t(eps))
end.
Задание 1
1. Составьте программы вывода на экран членов последовательности, задаваемых
следующими способами:
n!
1
1) an  n ; 2) a0  1; an  nan1  ;
n
n
3) последовательность состоит из десятичных приближений с избытком частного
22
.
7
Пример 3. Рассмотрим бесконечную последовательность x1, x2,..., образованную по
следующему закону:
u  n 1
x1 
,,
2
1 
u 
x i    (n  1)  x i 1  n1  , (i  2, 3, ... ),
n 
x i 1 
где u - данное неотрицательное действительное число, n - натуральное число.
317

Эта последовательность позволяет получить сколь угодно точные приближения
числа n u . По аналогии с программой для u составить программу для приближённого
вычисления n u и проверьте ее для а) 3 u , б) 4 u .
{ Вычисление корня с любым натур. показат. действит. числа }
Program Problem3;
uses WinCrt;
var
u, n, eps, x : real;
{----------------------------------------------------------------------------------------}
{ Функция вычисления порядка - кол-во знаков после запятой }
Function t(eps : real) : integer;
var
k : integer;
begin
k := -1;
repeat
eps := eps*10;
k := k + 1
until eps > 1;
t := k
end;
{----------------------------------------------------------------------------------------}
Procedure Root(u, n, eps : real; var x : real);
var
x1, x2, xn : real;
i
: integer;
begin
x1 := (u + n - 1)/2;
repeat
xn := 1;
for i := 1 to trunc(n) - 1 do xn := xn*x1;
x1 := ((n - 1)*x1 + u/xn)/n;
x2 := ((n - 1)*x1 + u/xn)/n
until abs(x1 - x2) <= eps;
x := x2
end;
{--------------------------------------------------------------------------------------}
begin
write('Введите подкоренное выражение '); readln(u);
write('Введите показатель корня '); readln(n);
write('Введите точность вычисления '); readln(eps);
Root(u, n, eps, x);
writeln('Значение корня равно ', x:8:t(eps));
writeln('С точностью до ', eps:1:t(eps))
end.
Рассмотрим несколько последовательностей, заданных формулами n-го члена:
xn
(1) n1  x 2n1
1) un 
; 2) un 
;
n!
(2n  1)!
318 
(1) n  x 2n
, все три последовательности имеют место при любом значении x;
(2n)!
m( m  1)... ( m  n  1) n
4) un 
 x , где m - вещественное число, отличное от 0 и от
n!
всех натуральных чисел при x  1;
3) un 
(1) n1  x n
(1) n1  x 2n1
, при |x| < 1 и x = 1; 6) un 
, при |x|  1.
n
2n  1
Нам еще придется на следующем занятии иметь дело с этими последовательностями,
но уже при постановке несколько иной задаче. А теперь составим программы вычисления
членов последовательности, причем вычисления вести до того члена, который по абсолютной величине станет равным или меньше заданной точности. Выполним это задание
для последовательностей 2-й и 4-й.
5) un 
Пример 4. Последовательность задана формулой
( 1) n1  x 2 n1
un 
, | x |  1.
(2n  1)!
Вывести на экран члены последовательности до члена, меньшего заданного положительного числа eps. Желательно принять 0 < eps < 1.
Самое важное - это перейти от формулы n-го члена к рекурретному соотношению,
которое впоследствии надо использовать при составлении программы.
(1) n 2  x 2n 3
Запишем формулу n-1 -го члена: un1 
.
(2n  3)!
Разделим un на un-1, получим:
un
( 1) n1  x 2 n1  (2n  3)!
( 1)  x 2  (2n  3)!
 x2



.
un1 ( 1) n2  x 2 n3  (2n  1)! (2n  3)! (2n  2)  (2n  1) (2n  2)(2n  1)
тогда
x2
un   un1
.
(2n  2)(2n  1)
Надо заметить, что первый член равен: u1 = x.
После этого нетрудно составить программу. Организуем цикл с предусловием "пока", пока |u| > eps. Почему для этой задачи удобно устроить именно такой цикл?
В нашем примере, в качестве начального значения берется первый элемент последовательности. Может случиться, что пользователь задал такое значение eps, что уже первый член меньше этого числа. И тогда вычислений выполнять не следует, т.е цикл не выполняется, а значит необходимо сразу проверить условие. Такое делается в цикле с предусловием. Цикл repeat ... until будет обязательно выполняться хотя бы один раз, а этого
нам не нужно.
Программа
Program Problem4;
uses WinCrt;
var
x, eps : real;
{----------------------------------------------------------------------------------------}
{ Функция вычисления порядка - кол-во знаков после запятой }
Function t(eps : real) : integer;
319

var
k : integer;
begin
k := -1;
repeat
eps := eps*10;
k := k + 1
until eps > 1;
t := k
end;
{----------------------------------------------------------------------------------------}
Procedure Create_succession(x, eps : real);
var
u : real;
n : integer;
begin
u := x;
n := 1;
while abs(u) > eps do
begin
n := n + 1;
write(u:6:t(eps), '; ');
u := (-1)*u*x*x/((2*n - 2)*(2*n - 1))
end;
writeln
end;
{----------------------------------------------------------------------------------------}
begin
write('Введите значения |x| <= 1 '); readln(x);
write('Задайте положит. число eps '); readln(eps);
writeln('Члены последовательности');
Create_succession(x, eps);
end.
Пример 5. Последовательность задана формулой:
m( m  1)... ( m  n  1) n
un 
x ,
n!
где m - вещественное число, отличное от 0 и от всех натуральных чисел, при | x |  1.
Вывести на экран члены последовательности до члена, меньшего наперед заданного
положительного числа eps, 0 < eps < 1.
Из формулы n-го члена составьте рекуррентную формулу, установите каким должно
быть первоначальное значение, составьте программу и сравните ее с приведенной ниже
программой.
Program Problem5;
uses WinCrt;
var
x, m, eps : real;
{----------------------------------------------------------------------------------------}
{ Функция вычисления порядка - кол-во знаков после запятой }
Function t(eps : real) : integer;
320 
var
k : integer;
begin
k := -1;
repeat
eps := eps*10;
k := k + 1
until eps > 1;
t := k
end;
{----------------------------------------------------------------------------------------}
Procedure Create_succession(x, m, eps : real);
var
n : integer;
u : real;
begin
u := 1;
n := 1;
repeat
u := u*(m - n + 1)*x/n;
write(u:3:t(eps), ' ');
n := n + 1
until abs(u) <= eps;
writeln
end;
{----------------------------------------------------------------------------------------}
{ Основная программа }
begin
write('Введите значения x, |x| < 1 '); readln(x);
writeln('Введите вещественное положительное m, отличное от');
write('натуральных чисел '); readln(m);
write('Задайте положительное число eps '); readln(eps);
writeln('Члены последовательности');
Create_succession(x, m, eps)
end.
Задание 2
Составьте программы вывода на экран членов последовательности до члена, меньшего заданного положительного числа eps, 0 < eps < 1. Возьмите для задания примеры 1,
3, 6:
xn
1) un 
; где x - любое действительное число,
n!
(1) n  x 2n
3) un 
, где x - любое действительное число,
(2n)!
(1) n1  x 2n1
6) un 
, при | x |  1.
2n  1
321

Усложним задачи и разберем следующий пример.
Пример 6. Дано положительное число eps. Последовательность a1, a2, a3,... образована по следующему закону:
1 
 1  1 
ai  1   1  ...1 
.
 2  3  i  1
Найти первый член an последовательности, для которого выполнено условие:
an  an1  eps.
Составить программу выполнения этого задания.
Алгритм
1. Начало.
а) Переменные и их типы. Переменная i принимает целые значения:
1, 2, 3, 4, ... Переменные ap, an и eps принимают вещественные значения.
2. Основная часть.
а) Ввод значения eps.
б) Установить первоначальные значения переменных i, ap и an:
i := 1, ap := 1, an := 1 - 1/2.
в) Цикл "пока" с условием: abs(an - ap) >= eps.
Команды в цикле. Значения i каждый раз в цикле должны увеличиваться на единицу;
значения ap := 1 - 1/i; значения an := ap*(1 - 1/(i + 1)).
г) После завершения работы цикла, вывод значения an на экран. Можно вывести и
номер i этого члена последовательности.
3. Конец.
Составим процедуру и программу, используя алгоритм.
Программа
Program Problem6;
uses WinCrt;
var
i
: integer;
a, eps : real;
{----------------------------------------------------------------------------------------}
{ Функция вычисления порядка - кол-во знаков после запятой }
Function t(eps : real) : integer;
var
k : integer;
begin
k := -1;
repeat
eps := eps*10;
k := k + 1
until eps > 1;
t := k
end;
{----------------------------------------------------------------------------------------}
Procedure Create_succession(eps : real; var i : integer; var a : real);
var
i : integer;
322 
an, ap : real;
begin
i := 1; ap := 1; an := 1 - 1/2;
while abs(an - ap) >= eps do
begin
i := i + 1;
ap := ap*(1 - 1/i);
an := ap*(1 - 1/(i + 1))
end;
a := an
end;
{---------------------------------------------------------------------------------------}
{ Основная программа }
begin
write('Введите любое положительное число eps '); readln(eps);
Create_succession(eps, i, a);
writeln('Искомый член последовательности ', a:6:t(eps));
writeln('Находится на ', i, '-ом месте в последовательности')
end.
Задание 3
(1) n
Последовательность задана формулой: y n  2 
. Составьте программу, покаn
зывающую, что для любого положительного числа eps, найдется член последовательности
yN, для которого будет выполняться неравенство y N  2  eps.
Если Вы составили программу и выполнили ее несколько раз, то смогли убедиться в
том, что для любого положительного числа eps найдется член последовательности yN, такой, что модуль разности (yN- 2) меньше eps.
Дополним программу так, чтобы она показывала, что неравенство y n  2  eps выполняется для членов этой последовательности с номерами n  N .
Но перед этим, вспомним определение предела последовательности.
Определение предела последовательности
Число A называется пределом последовательности xn, если для любого положительного числа  найдется такой номер последовательности N, что для всех номеров n > N,
будет выполняться неравенство x n  A   .
Последнее неравенство равносильно следующему:
   x n  A   или A    x n  .
Если изобразить числа A, A  , A   и значения последовательности xn на числовой оси, то получится наглядное геометрическое истолкование предела последовательности:
Рис. 42
323

Какой бы малый отрезок (длиной 2   ) с центром в точке A (см. рис. 42) ни взять,
все точки xn, начиная с некоторой из них, должны попасть внутрь этого отрезка (так что
вне его может остаться разве лишь конечное число точек). Точка, изображающая предел
A, является как бы средоточением сгустка точек, изображающих значения членов последовательности.
Возвращаясь к примеру 5, можно сказать, что по сути дела мы показывали, что чис(1) n
ло 2 является пределом последовательности y n  2 
.
n
Если эту программу немного изменить, то она станет такой.
Пример 7. Программа,
(1) n
является число 2.
yn  2 
n
показывающая,
что
пределом
последовательности
Program Problem7;
uses WinCrt;
var
i, n, k
: longint;
eps, yn, yp : real;
{----------------------------------------------------------------------------------------}
{ Функция вычисления порядка - кол-во знаков после запятой }
Function t(eps : real) : integer;
var
k : integer;
begin
k := -1;
repeat
eps := eps*10;
k := k + 1
until eps > 1;
t := k
end;
{----------------------------------------------------------------------------------------}
{ Основная программа }
begin
writeln('Введите произвольное положительное число, ');
write('можно даже очень малое '); readln(eps);
i := 1; k := -1; yn := 1;
while abs(yn - 2) >= eps do
begin
i := i + 1; k := k*(-1);
yn := 2 + k/i
end;
writeln('Условию abs(yn-2)<', eps:1:t(eps), ' удовлетворяет');
writeln('член последовательности yn = ', yn:6:t(eps), ',');
writeln('находящийся под номером ', i); writeln;
write('Введите номер члена последовательности больше ',i,' ');
readln(n);
if n mod 2 = 0 then yn := 2 + 1/n else yn := 2 - 1/n;
if abs(2 - yn) < eps
then
324 
begin
write('Неравенство abs(2 - ', yn:6:t(eps), ') < ', eps:1:t(eps));
writeln( ' выполняется ')
end
else
begin
write('Неравенство abs(2 - ', yn:6:t(eps), ') < ', eps:1:t(eps));
writeln(' не выполняется')
end
end.
Задание 4
Составьте программу, показывающую, что число 1 является пределом последова2n  1
тельности y n  n
.
2 1
Продолжим составление программ на последовательности и немного усложним задачу. Если в двух предыдущих примерах заведомо было известно число, которое является
пределом последовательности, то в следующем примере надо будет определить существует ли вообще предел и если существует, тогда найти его и показать, что оно действительно является пределом заданной последовательности.
Таким образом, задача имеет две части:
1) установить существование предела и,
2) если таковой существует, то показать чему он равен.
Перед выполнением такого задания обратимся к курсу математического анализа, в
котором есть теорема, которая принадлежит чешскому математику Больцано и французскому математику Коши, ее часто называют принципом сходимости. Она выражает общий
Признак существования конечного предела последовательности
Пусть задана последовательность xn, пробегающая значения x1, x2, ..., xn, ..., xm, ...
Для того, чтобы последовательность xn имела конечный предел, необходимо и достаточно,
чтобы для каждого числа   0 существовал такой номер N, чтобы неравенство
x n  x m   выполнялось, лишь только n  N и m  N . Как видите, суть дела здесь в
том, чтобы значения переменной xn и xm между собой безгранично сближались по мере
возрастания их номеров.
Этот признак допускает простую геометрическую иллюстрацию (рисунок 43).
Рис. 43
Пример 8. Выяснить имеет ли предел последовательность, заданная формулой:
n
 1
x n  1   . Если имеет, то найти его.

n
Алгоритм решения основывается на признаке существования предела последовательности. Нам необходимо установить, что члены последовательности по мере увеличения номера сближаются друг с другом. Перекладывая это на язык математики, нам надо
325

задать положительное число eps, которое может быть сколь угодно малым и найти такие
два члена последовательности, разность между которыми по абсолютной величине будет
меньше этого наперед заданного, может быть даже, очень малого числа eps.
Идея становится понятной. Остается продумать, как находить члены последовательности в зависимости от их номеров?
Конечно, можно составить рекуррентное соотношение, но это будет немного трудным делом чисто в математическом отношении.
Возникает другая мысль. Составить подпрограмму возведения в степень и из основной программы каждый раз обращаться к ней для вычисления степени с изменением номера n. Тем более, что опыт составления подпрограмм у нас уже есть. Мы достаточно
много составляли на прошедших занятиях подпрограмм в форме процедур и функций.
Основная программа. Вначале попросим пользователя задать точность вычисления
(так мы назвали число eps).
Затем задается начальное значение переменной n (n := 1). Организуется цикл с последующим условием (repeat ... until...), в котором переменной x - члену последовательности присваивается значение, вычисляющее значение функции x  s( n, (1  1 / n)) для
данного значения n. Далее значение n увеличивается на 1 (n :  n 1) и вычисляется следующий член последовательности x1, который также будет равен значению функции
x1  s( n, (1  1 / n)) , - помните, что значение n уже увеличилось на 1.
Проверяется условие abs(x1 - x) < eps. Как только условие выполнится, цикл закончится и в качестве значения предела последовательности мы можем брать любое из значений x или x1 и оно укажет нам значение предела последовательности с заданной точностью eps.
Если кто-нибудь из вас раньше встречался с такой последовательностью, то он сразу
был уверен, что ее предел существует и равен числу e - основанию натурального логарифма.
Проверьте это, выполнив программу
Program Problem8;
uses WinCrt;
var
n : integer; x, x1, eps : real;
{----------------------------------------------------------------------------------------}
{ Функция вычисления порядка - кол-во знаков после запятой }
Function t(eps : real) : integer;
var
k : integer;
begin
k := -1;
repeat
eps := eps*10;
k := k + 1
until eps > 1;
t := k
end;
{----------------------------------------------------------------------------------------}
Function s(k: integer; p : real) : real;
var
i : integer; z : real;
begin
z := 1;
for i := 1 to k do z := z*p;
326 
s := z
end;
{----------------------------------------------------------------------------------------}
begin
write('Задайте точность '); readln(eps);
n := 1;
repeat
x := s(n, (1 + 1/n));
n := n + 1;
x1 := s(n, (1 + 1/n))
until abs(x1 - x) < eps;
writeln('Предел последовательности равен ', x1:6:t(eps));
writeln('С точностью до ', eps:1:t(eps))
end.
Задание 5
Последовательность un принимает значения
1
1 1
1
1
1
u1  , u2   , un  1
 2
... n
4
4 10
3 1 3 1
3 1
Показать, что un стремится к некоторому пределу при n   .
(При составлении программы использовать в качестве подпрограммы функцию вычисления степени числа 3 с показателем n).
Библиотека часто встречающихся процедур и функций
41. Функция вычисляющая количество знаков после запятой.
Function t(eps : real) : integer;
var
k : integer;
begin
k := -1;
repeat
eps := eps*10;
k := k + 1
until eps > 1;
t := k
end;
42. Процедуры вычисления квадратного корня с заданной степенью точности.
1-й способ
Procedure square_root(u, eps : real; var x : real);
begin
x := (u + 1)/2;
repeat
x := (1/2)*(x + u/x)
until abs(x*x - u) <= eps;
end;
327

2-й способ
Procedure square_root(u, eps : real; var x : real);
var
x1, x2 : real;
begin
x1 := 1;
repeat
x1 := (1/2)*(x1 + u/x1);
x2 := (1/2)*(x1 + u/x1)
until abs(x2 - x1) <= eps;
x := x2
end;
Упражнения
167. Дано действительное число b  0. Последовательность a1, a2, ... образована по
следующему закону: a1  1, ai  ai21  1 (i  2, 3, ... ).
Требуется получить все a1, a2, ..., меньшие или равные b.
168. Дано действительное b  0. Последовательность a1, a2,... образована по следую1
, i  2, 3, ... .
щему закону: a1  b, ai  ai 1 
i
Найти первый отрицательный член последовательности a1, a2, ... .
169. Составить программу вычисления и вывода на экран n членов последовательности, заданной формулой n-го члена. (Предварительно составить рекуррентную формулу).
n2
2n  1
2 n1
3n
( n  2)!
a

;
a

;
а) an 
б)
в)
)
д)
a

;
;
a

;
n
n
n
n
3n
n  2n
3 n1
3 n  n!
3n
xn
2n
n2
е) an  ; ж) an  4 ; з) an 
, где x - заданное действительное число, x  1;
n!
n!
n
3
n1 n
и) an  (1)
.
2n
170. Составить программу, подсчитывающую сумму n первых членов последовательности, заданной формулой n-го члена. (Предварительно составить рекуррентную
формулу).
n
xn
n
n
n 1 x
а) an  10  x , б) an  ( 1) 
г) an  n ! x n ,
, в) an 
n1 ,
n
n  10
2 n1
x
д) an  2 n1  x 2( n1) , е) an  (1) n1
, ж) an  (n  1)  3 n1  x n1 ,
(2n  1)  (2n  1)!
n
n
x
(nx )
ln(n  1) n1
з) an 
, к) an 
, и) an 
 x , x - заданное действительное
n!
n(n  1)
n 1
число.
171. Дано действительное b  0. Последовательность r , a2, ... образована по следуюa i 1  1
щему закону:
, i  2, 3, ... .
a1  b, ai 
i  sin 2 i
Найти первый неотрицательный член последовательности.
1 
1 
1

172. Дано натуральное n. Вычислить: 1  2  1  2 ...1  2  .
 1  2   n 
173. Для чисел Фибоначчи u0, u1, ... справедлива формула Бине:
328 
k
k
 1  1  5 
 1  1  5 
    
 , где k
uk     
 5  2 
 5  2 
Так как
 0, 1, ... .
1 5
 1, то для больших k выполнено приближенное равенство
2
k
 1  1  5 
 .
uk     
 5  2 
Вычислить и округлить до ближайшего целого все числа
k
(k
k
 1  1  5 
 (k  0, 1, ..., 15),
  
 5  2 
а также вычислить u0, u1, ..., u15 по формулам u0  0; u1  1; uk  uk 1  uk 2
 2, 3, ...) и сравнить результаты.
174. Вычислить и вывести на экран положительные значения функции
 n
y  sin(nx )  cos  пр и n  1, 2, ..., 50.
x
xk
175. Вычислить значения функции z  2 , большие заданного числа a, если
k
 1, 2, 3, ... .
x2
x3
xn
, 
, ..., (1) n 
, ..., модуль которых
2!
3!
n!
больше заданного числа a, 0 < a < 1, x - любое действительное число.
177. В окружность радиусом r вписан многоугольник со стороной an. Сторона многоугольника с удвоенным числом сторон определяется по формуле
176. Вычислить члены ряда
a2 n 
2 r 2  2 r r 2  an2 / 4
Определить a128, если известны r и а4.
178. Вычислить и вывести на печать значения членов ряда
x  h x  2h x  3h
x  nh
x  20h
,
, ...,
, ...,
.
,
5
7
2n  1
41
3
15
 n  i
179. Вычислить значения функции z   
.
i 
i 1 
180. Последовательность an принимает значения
a1  0,9; a2  0,99; a3  0,999; ..., an  0,999...9; ... .
Чему равен предел an при n   ? Каково должно быть n, для того чтобы абсолютная
величина разности между an и ее пределом была больше 0,0001?
181. Установите, имеет ли следующая последовательность un предел?
1
1
1
u1  1, u2  , u3  , ..., un  2 , ... .
4
9
n
4n2  1
182. Показать, что последовательность xn  2
при неограниченном возраста3n  1
4
нии n стремится к пределу, равному .
3
183. Установить имеет ли последовательность, заданная формулой n-го члена преcn
c
;
дел: а) x n 
(c  0), x n1  x n 
n!
n 1
329

б) x1 
c , x2 
c  c , ..., xn 
c  c... c .
Таким образом, xn+1 получается из xn по формуле xn 1  c  xn ;
c
c x n2
в) x 1  , x n1  
, пр и 0  c  1.
2
2 2
Ответы
К заданию 3
Program Task3;
uses WinCrt;
var
n
: integer;
y, eps : real;
{----------------------------------------------------------------------------------------}
Function t(eps : real) : integer;
var
k : integer;
begin
k := -1;
repeat
eps := eps*10;
k := k + 1
until eps > 1;
t := k
end;
{----------------------------------------------------------------------------------------}
Procedure Element_succession(eps : real; var n : integer; var y : real);
var
k : integer;
begin
n := 1;
y := 1;
k := -1;
while abs(y - 2) >= eps do
begin
n := n + 1;
k := k*(-1);
y := 2 + k/n
end
end;
{----------------------------------------------------------------------------------------}
{ Основная программа }
begin
writeln('Введите любое положительное число');
write('Можно даже очень малое '); readln(eps);
Element_succession(eps, n, y);
writeln('Искомый член последовательности ', y:6:t(eps));
writeln('Находится на ', n , '-ом месте')
end.
330 
К заданию 4
Program Task4;
uses WinCrt;
var
i, j, n
: integer;
k, k1
: longint;
yn, ym, eps : real;
{----------------------------------------------------------------------------------------}
Function t(eps : real) : integer;
var
k : integer;
begin
k := -1;
repeat
eps := eps*10;
k := k + 1
until eps > 1;
t := k
end;
{----------------------------------------------------------------------------------------}
begin
writeln('Введите любое положительное число ');
write('Можно даже очень малое '); readln(eps);
i := 1;
yn := 1/3;
k := 2;
while abs(yn - 1) >= eps do
begin
i := i + 1;
k := k*2;
yn := (k - 1)/(k + 1)
end;
writeln('Условию |yn - 1| < ', eps:1:t(eps), ' удовлетворяет');
writeln('член последовательности yn = ', yn:6:t(eps), ',');
writeln('находящийся под номером ', i); writeln;
write('Введите номер члена последовательности ');
write('больше ', i, ' '); readln(n);
j := i; ym := yn;
k1 := k;
while j <= n do
begin
j := j + 1;
k1 := k1*2;
ym := (k1 - 1)/(k1 + 1);
end;
if abs(ym - 1) < eps
then
begin
write('Неравенство abs(1 - ',ym:6:t(eps),') <', eps:1:t(eps));
writeln(' выполняется')
end
else
331

begin
write('Неравенство abs(1-', ym:6:t(eps),') <', eps:1:t(eps));
writeln(' не выполняется')
end
end.
К заданию 5
Program Task5;
uses WinCrt;
var
n
: longint;
u, u1, eps : real;
{----------------------------------------------------------------------------------------}
Function s(k : integer) : longint;
var
i, z : longint;
begin
z := 1;
for i := 1 to k do z := 3*z;
s := z
end;
{----------------------------------------------------------------------------------------}
Function t(eps : real) : integer;
var
k : integer;
begin
k := -1;
repeat
eps := eps*10;
k := k + 1
until eps > 1;
t := k
end;
{----------------------------------------------------------------------------------------}
{ Основная программа }
begin
writeln('Задайте положительное число eps');
write('Можно даже очень малое '); readln(eps);
u := 0;
n := 1;
repeat
u := u + 1/(s(n) + 1);
n := n + 1;
u1 := u + 1/(s(n) + 1);
until abs(u1 - u) < eps;
writeln('Предел последовательности равен ', u1:6:t(eps));
writeln('С точностью до ', eps:1:t(eps))
end.
332 
Глава 11. Приближенное вычисление корней уравнений
оператор выбора case...of... . Численное дифференцирование и интегрирование
1. Классические методы нахождения изолированного корня
На этом занятии мы рассмотрим задачу нахождения корней уравнения
f(x) = 0.
(1)
"Изолированным" мы будем называть корень c уравнения (1), если найден, содержащий его промежуток [a, b]: a < c < b, на котором других корней нет.
Для решения задачи уточнения корня, потребуем, чтобы функция удовлетворяла
следующим условиям:
1) f(x), f'(x) и f''(x) непрерывны на промежутке [a, b]; 2) значения функции на концах
промежутка [a, b] имеют разные знаки: f (a)  f (b)  0, т. е. функция заведомо имеет корень на этом промежутке;
3) обе производные f'(x) и f''(x) сохраняют каждая определенные знаки на всем промежутке [a, b], это значит, что функция строго монотонна (возрастает или убывает) на
этом промежутке. Требование сохранение знака второй производной f''(x) геометрически
означает, что график функции вогнутостью обращен всегда в одну сторону и не имеет перегибов.
Столь жесткие требования к поведению функции на промежутке казалось бы сильно
сужают круг рассматриваемых функций, но это не так.
Для алгебраических функций всегда можно найти промежуток (если вообще вещественные корни алгебраического уравнения существуют), на котором все три перечисленных условия выполняются.
Что касается трансцендентных уравнений, то на практике в большинстве случаев перечисленные условия выполняются и для них.
Во всяком случае, круг уравнений достаточно широк, чтобы заняться рассмотрением
ниже приводимых приемов решения, тем более что эти способы являются классическими
и полезны будут даже из соображений общего развития читателей.
Рис. 44
На рисунке 44 изображены четыре возможные случая, отвечающие различным комбинациям знаков f'(x) и f''(x).

333
1-й случай, когда f'(x)>0 - функция возрастает на промежутке, f''(x) > 0 - график вогнутостью направлен вверх.
2-й случай: f'(x)<0 - функция убывает, f''(x)>0 - вогнутость вверх.
3-й случай: f'(x) > 0 - функция возрастает, f''(x) < 0 - вогнутость направлена вниз.
4-й случай: f'(x) < 0 - функция убывает, f''(x) < 0 - вогнутость вниз.
1.1. Метод хорд (правило пропорциональных частей)
Пусть c - корень уравнения f(x) = 0 на промежутке [a, b], тогда c - абсцисса точки пересечения кривой с осью ox. Конечная задача - найти эту точку или как можно близкое
значение абсциссы к этой точки.
Рассмотрим случаи 1-й и 3-й, когда хорда находится слева от кривой и пересекает
ось x между точками a и c (см. рис. 45).
Рис. 45
Заменим кривую AcB хордой AB. Мы сможем написать уравнение этой хорды, а
значит найти ее точку пересечения с осью x.
Уравнение хорды - это уравнение прямой, проходящей через две точки (a, f(a)) и (b,
f(b)).
Общий вид уравнения прямой, проходящей через две точки такой:
x  x1
y  y1

.
x2  x1 y2  y1
Подставляя в эту формулу значения, получим уравнение хорды AB:
f (b)  f (a)
xa
y  f (a )

отсюда y  ( x  a) 
 f (a).
b a
b  a f (b )  f ( a )
Пусть x1 - точка пересечения хорды с осью x, так как y = 0, то
(b  a)  f (a)
x1  a 
.
f (b)  f (a)
x1 может считаться приближенным значением корня. Для более точного его определения
рассмотрим промежуток [x1, b]. И на этом промежутке заменим кривую хордой A1B и
найдем новое приближение к корню - x2:
(b  x 1 )  f ( x 1 )
и так далее.
x 2  x1 
f (b)  f ( x 1 )
334 
Для n + 1 - го приближения получим:
(b  x n )  f ( x n )
.
f (b)  f ( x n )
Этот процесс можно продолжать сколь угодно долго и построить возрастающую последовательность приближенных значений корня:
a < x1 < x2 < ... < xn < xn+1 < ... < c.
В математическом анализе доказывается, что переменная x n с ростом n стремится к
c, т.е. c является пределом этой последовательности.
Для случаев 2-го и 3-го, когда хорда располагается справа от кривой (см. рис. 46), и
пересекает ось ox между точками с и b, значения приближенных значений корней будут
следующими:
x n1  x n 
Рис. 46
(b  a) f (b)
x1  b 
,
f (b)  f (a)
( x 1  a) f ( x 1 )
x 2  x1 
,
f ( x 1 )  f (a)
....................................,
( x n  a) f ( x n )
(1)
x n1  x n 
.
f ( x n )  f (a)
В результате получим убывающую последовательность, которая также сходится к c:
b > x1 > x2 > ... > xn > xn+1 > ... > c
Во всех случаях можно найти корень с любой степенью точности.
Как оценивается точность приближенного значения xn?
По формуле Лагранжа (формуле конечных приращений) для разности f (x n )  f (c)
получим: f ( x n )  f (c)  ( x n  c) f '( e) , где c  e  x n или x n  e  c.
f ( xn )
.
Так как f(c) = 0, то получим: xn  c 
f ' ( e)
Если обозначить через m наименьшее значение |f'(x)| на промежутке [a, b], которое
можно определить заранее, то получим формулу для оценки точности вычисления корня:
| f ( x n )|
| f ( x n )|
или
| x n  c| 
 eps,
m
m
где eps - заданная точность вычисления. Пользуясь рекуррентной формулой (1) и формулой для оценки точности вычисления, нетрудно составить процедуру уточнения корня
методом хорд:
{ Процедура уточнения корня методом хорд }
Procedure chord(a, b, eps, min : real; var x : real);
var
x1 : real;
335

begin
x1 := a;
repeat
x := x1 - ((b - x1)*fx(x1))/(fx(b) - fx(x1));
x1 := x
until abs(fx(x))/min < eps
end;
Для оценки точности вычисления корня необходимо вычислять наименьшее значение производной f'(x) на промежутке [a, b], поэтому возникает необходимость в нахождении значения производной в точке и здесь мы приходим к задаче численного дифференцирования.
1.2. Вычисление производных (численное дифференцирование)
При вычислении производной функции, будем иметь в виду, что один из способов
найти производную f ' (x 0 ) - это взять достаточно малые значения справа и слева на равном расстоянии от x 0 - точке, в которой мы хотим найти производную.
f (xo  dx / 2)  f (xo  dx / 2)
f ' (xo ) 
.
dx
Таким образом, вычисляется производная в середине промежутка.
По значениям f' можно таким же способом найти производную от f', т.е. f''. Можно
выразить f'' непосредственно через f(x):
f ( xo  dx )  f ( xo ) f ( xo )  f ( xo  dx )

f ' ( xo  dx / 2 )  f ' ( xo  dx / 2 )
dx
dx
f ' ' (x ) 


dx
dx
f (xo  dx )  2 f (xo )  f (xo  dx )

.
dx 2
Для производной третьего порядка можно использовать следующую формулу:
f ( x o  2dx )  2 f ( x o  dx )  2 f ( x o  dx )  f ( x o  2dx )
f ' ' ' (x ) 
.
2dx 3
Возникают естественные вопросы, откуда происходят эти формулы и как оценивать
точность вычисления производных по этим формулам?
Формулы являются результатом дифференцирования интерполяционных многочленов Ньютона и других. Сущность которых состоит в том, что заданная функция f(x) представляется в виде многочлена, который значительно проще дифференцировать, чем какиелибо другие функции, особенно трансцендентные или представляющие собой сложные
выражения. Как получаются такие многочлены, мы узнаем позже - этому вопросу будет
посвящена полностью глава, а сейчас ограничимся лишь результатами, которые нам необходимы в этой главе.
Оценка погрешности и точности вычисления не менее серьезный и сложный процесс, чем само приближенное вычисление.
Так для оценки погрешности дифференцирования могут быть применены следующие формулы:
n
n dx
(2)
rn ( x )  ( 1)
f ( n1) (),
n 1
где предполагается, что функция f(x) дифференцируемая n + 1 раз, а точка  - некоторое
промежуточное значение между x0 - точкой, в которой находится производная и точками
(x0 - 2dx), (x0 - dx), (x0 + dx), (x0 + 2dx), ... из заданного промежутка [a, b].
336 
На практике f (n+1)(c) оценивать непросто, поэтому при малых dx приближенно полагают:
f ( n1) () 
и тогда получается следующая формула
( n1) y 0
dx n1
( 1) n n1 y0
(3)
rn ( x 0 ) 
dx ( n  1)
Мы будем пользоваться формулой (2), а впоследствии и формулой (3), в зависимости от конкретной задачи и тех сложностей, которые могут возникнуть при составлении
программ.
Используя эти формулы, составим функцию для вычисления первой производной.
Точность вычисления eps задается пользователем, а первоначальная величина промежутка
dx устанавливается 1, а затем, для уточнения вычисления - делится на 2. Впрочем, читатель может предложить другие способы изменения промежутка dx, когда значительно
быстрее достигается вычисление производной с заданной степенью точности.
{ Вычисление 1-й производной и опред. точности ее вычислен.}
{ derivative - производная }
Function derivat1(x0, eps : real) : real;
var
dx, dy, dy2 : real;
begin
dx := 1;
repeat
dx := dx/2;
dy := fx(x0 + dx/2) - fx(x0 - dx/2);
dy2 := fx(5*x0/4 + dx) - 2*fx(5*x0/4);
dy2 := dy2 + fx(5*x0/4 - dx)
until abs(dy2/(2*dx)) < eps;
derivat1 := dy/dx
end;
Здесь, для определения точности вычисления, используется вторая производная в
точке c  5 
x0
; dy2 := fx(5*x0/4 + dx) - 2*fx(5*x0/4) + fx(5*x0/4 - dx);
4
Запись ее вычисления выполнена в две строки только из-за лучшей наглядности
написания программы.
Возможен и другой вариант написания функции с использованием формулы (3) для
оценки точности вычисления. Тогда функция запишется так:
{ Вычисление 1-й производной и опред. точности ее вычислен.}
{ derivative - производная }
Function derivat1(x0, eps : real) : real;
var
dx, dy, dy2 : real;
begin
dx := 1;
repeat
dx := dx/2;
dy := fx(x0 + dx/2) - fx(x0 - dx/2);
337

dy2 := fx(5*x0/4 + dx) - 2*fx(5*x0/4);
dy2 := dy2 + fx(5*x0/4 - dx)
until abs((dy2*dy2*fx(x0))/(2*dx)) < eps;
derivat1 := dy/dx
end;
Задание 1
Составьте самостоятельно функции для вычисления второй производной и проверьте ее работу в программах для вычисления второй производной функций:
1) x 3  2x 2  4 x  7 x 0  3, 2.3, 4;
2)
3)
4)
5)
6)
7)
x 2 sin x
e
x 2
1
1 x2
1
x
x 2 cos 2x  1
1
cos 2 x
x0

0.5;
x0

1.5;
x0

0.5;
x0

1.5;
x0

0.6;
x0

0.8.
Однако вернемся к задаче решения уравнения методом хорд. Имея возможность вычислить значение производной, можно составить процедуру определения модуля ее
наименьшего значения на промежутке [a, b].
Для этого достаточно сравнить модуль значения производной на концах промежутка
и выбрать среди этих двух значений меньшее (такое право дает нам сделать тот факт, что
по условию, функция на промежутке строго монотонна вместе со своими производными
первого и второго порядков). Процедура получится простой:
{ Процедура определения наименьшего значения производной }
Procedure minimum(a, b, eps : real; var min : real);
begin
min := abs(derivat1(a, eps));
if min > abs(derivat1(b, eps))
then min := abs(derivat1(b, eps))
end;
Но и построенная таким образом процедура имеет очень существенный недостаток!
А если в точке a или b производная будет равна нулю? Тогда деление на нуль станет невозможным и в программе будет получена ошибка. Чтобы избежать этого, изменим процедуру так, чтобы в случае равенства нулю производной в одной и точек a или b находилось бы ее значение в ближайшей окрестности этой точки. Но, для точки a брать значение
слева нельзя, оно выйдет за пределы промежутка [a, b], также, как и справа от точки b.
Поэтому следует брать значение очень близкое к a, но справа от нее, аналогично для точки b - брать близкое значение слева от b.
Процедуру можно построить так:
{ Процедура определения наименьшего значения производной }
{ на заданном промежутке }
Procedure minimum(a, b, eps : real; var min : real);
var
d : real;
338 
begin
a := a - eps;
b := b + eps;
repeat
a := a + eps;
b := b - eps;
min := abs(derivat1(a, eps));
d := abs(derivat1(b, eps));
if min > d then min := d
until min <> 0
end;
Объединяя полученные функции и процедуры в одну программу, мы получим программу вычисления корня уравнения на изолированном промежутке методом хорд.
{ Решение уравнений методом хорд. method - метод, chord - хорда }
Program Method_Chord;
uses WinCrt;
var
a, b, x, min, eps : real;
{--------------------------------------------------------------------------------------}
{ Заданная функция }
Function fx(x : real) : real;
begin
fx := x*x*x - 2*x*x - 4*x - 7
end;
{--------------------------------------------------------------------------------------}
{ Вычисление 1-й производной }
{ derivative - производная }
Function derivat1(x0, eps : real) : real;
var
dx, dy, dy2 : real;
begin
dx := 1;
repeat
dx := dx/2;
dy := fx(x0 + dx/2) - fx(x0 - dx/2);
dy2 := fx(5*x0/4 + dx) - 2*fx(5*x0/4);
dy2 := dy2 + fx(5*x0/4 - dx)
until abs(dy2/(2*dx)) < eps;
derivat1 := dy/dx
end;
{----------------------------------------------------------------------------------------}
{ Процедура определения наименьшего значения производной }
{ на заданном промежутке }
Procedure minimum(a, b, eps : real; var min : real);
var
d : real;
begin
a := a - eps;
b := b + eps;
repeat
339

a := a + eps;
b := b - eps;
min := abs(derivat1(a, eps));
d := abs(derivat1(b, eps));
if min > d then min := d
until min <> 0
end;
{----------------------------------------------------------------------------------------}
{ Процедура уточнения корня методом хорд }
Procedure chord(a, b, eps, min : real; var x : real);
var
x1 : real;
begin
x1 := a;
repeat
x := x1 - ((b - x1)*fx(x1))/(fx(b) - fx(x1));
x1 := x
until abs(fx(x))/min < eps
end;
{----------------------------------------------------------------------------------------}
{ Основная программа }
begin
write('Введите левый конец промежутка a = '); readln(a);
write('Введите правый конец промежутка b = '); readln(b);
write('Введите точность вычисления корня eps = ');
readln(eps);
minimum(a, b, eps, min);
chord(a, b, eps, min, x);
writeln('Корень уравнения равен x = ', x:12:12);
writeln('С точностью до eps = ', eps:1:12)
end.
И в этих программах будем применять уже известную нам функцию для указания
точности вычисления.
{ Функция вычисления порядка - кол-во знаков после запятой }
Function t(eps : real) : integer;
var
k : integer;
begin
k := -1;
repeat
eps := eps*10;
k := k + 1
until eps > 1;
t := k
end;
Добавим эту функцию в программу.
{ Решение уравнений методом хорд. method - метод, chord - хорда}
{ Правило пропорциональных частей }
Program Method_Chord;
340 
uses WinCrt;
var
a, b, x, min, eps : real;
{----------------------------------------------------------------------------------------}
{ Заданная функция }
Function fx(x : real) : real;
begin
fx := x*x*x - 2*x*x - 4*x - 7
end;
{----------------------------------------------------------------------------------------}
{ Вычисление 1-й производной }
{ derivative - производная }
Function derivat1(x0, eps : real) : real;
var
dx, dy, dy2 : real;
begin
dx := 1;
repeat
dx := dx/2;
dy := fx(x0 + dx/2) - fx(x0 - dx/2);
dy2 := fx(5*x0/4 + dx) - 2*fx(5*x0/4);
dy2 := dy2 + fx(5*x0/4 - dx)
until abs(dy2/(2*dx)) < eps;
derivat1 := dy/dx
end;
{----------------------------------------------------------------------------------------}
{ Функция вычисления порядка - кол-во знаков после запятой }
Function t(eps : real) : integer;
var
k : integer;
begin
k := -1;
repeat
eps := eps*10;
k := k + 1
until eps > 1;
t := k
end;
{----------------------------------------------------------------------------------------}
{ Процедура определения наименьшего значения производной }
{ на заданном промежутке }
Procedure minimum(a, b, eps : real; var min : real);
var
d : real;
begin
a := a - eps;
b := b + eps;
repeat
a := a + eps;
b := b - eps;
min := abs(derivat1(a, eps));
d := abs(derivat1(b, eps));
341

if min > d then min := d
until min <> 0
end;
{----------------------------------------------------------------------------------------}
{ Процедура уточнения корня методом хорд }
Procedure chord(a, b, eps, min : real; var x : real);
var
x1 : real;
begin
x1 := a;
repeat
x := x1 - ((b - x1)*fx(x1))/(fx(b) - fx(x1));
x1 := x
until abs(fx(x))/min < eps
end;
{----------------------------------------------------------------------------------------}
{ Основная программа }
begin
write('Введите левый конец промежутка a = '); readln(a);
write('Введите правый конец промежутка b = '); readln(b);
write('Введите точность вычисления корня eps = ');
readln(eps);
minimum(a, b, eps, min);
chord(a, b, eps, min, x);
writeln('Корень уравнения равен x = ', x:6:t(eps));
writeln('С точностью до eps = ', eps:1:t(eps))
end.
342 
1.3. Правило Ньютона (метод касательных)
Будем по прежнему считать, что функция f(x) удовлетворяет всем перечисленным
ранее требованиям и искомый корень c изолирован на промежутке [a, b], т. е. a < c < b.
Если в предыдущем примере была предпринята замена кривой, - графика функции,
хордой, то возникает естественная идея, а почему бы не заменить ее касательной, проведенной первоначально из точек A или B.
Этот метод носит название правило Ньютона или метод касательных.
Также возможны четыре случая, которые представлены на рисунке 47.
Рис. 47
Рассмотрим уравнение касательной, проведенной в точке B с абсциссой b. Уравнение касательной в этой точке составить нетрудно, оно будет таким:
y  f ' (b)(x  b)  f (b),
зная, что в точке пересечения с осью ox y = 0, найдем из уравнения значение x, получим:
f ( b)
f ( b)
0  f © (b)( x  b)  f (b), x  b  
, x b
.
f © ( b)
f © ( b)
Таким образом, мы получаем приближенное значение корня
f (b )
.
(4)
f ' (b )
Возникает вопрос, где лежит точка x1, полученная по формуле (3). Ведь из рисунка
следует, что в случаях 2 и 3 она может лежать вообще за пределами промежутка.
В математическом анализе доказывается, что если значение f(b) одного знака с f''(x) это случаи 1 и 4, то x1 лежит между корнем c и точкой b.
Аналогично, если исходить из точки a, и касательную к кривой провести в точке A,
то получим следующую формулу для приближенного значения корня
x1  b 
x1  a 
f (a )
.
f ' (a )
343

Также и здесь доказывается, что если f(a) и f''(a) одного знака, то x1 лежит между a и
c, a < x1 < c (на рисунке это соответствует случаям 2 и 3).
Как и для случая метода хорд можно построить для 1-го и 4-го случаев убывающую
последовательность значений xn сходящейся к c:
b > x1 > x2 > ... > xn > xn+1 > ... > c,
а для случаев 2 и 3 возрастающую последовательность значений также сходящихся к c:
a < x1 < x2 < ... < xn < xn+1 < ... < c.
Вычисление значений членов последовательности производится по следующей реf (xn )
куррентной формуле:
xn 1  xn 
.
f ' (xn )
Надо иметь ввиду, что для выбора первоначального значения x (x = a или x = b), надо
установить, где знак функции f(x) совпадает со знаком f''(x).
Оценка точности приближения происходит также, как и для случая метода хорд по
| f (xn )|
значению отношения
 eps, где eps - заданная точность, а m - наименьшее значеm
ние |f'(x)| на промежутке [a, b].
Исходя из высказанных соображений составим процедуру уточнения корня методом
касательных.
{ Процедура уточнения корня методом касательных }
Procedure tangent(a, b, eps, min, dy : real; var x : real);
var
x1 : real;
begin
x1 := a;
repeat
x := x1 - fx(x1)/derivat1(x1);
x1 := x
until abs(fx(x))/min < eps
end;
Для установления первоначального значения x (конца промежутка, от которого
начнется уточнения корня) нам нужна будет вторая производная. Функцию, которая ее
вычисляет вы должны были составить самостоятельно, а сейчас проверьте себя:
{ Функция вычисления второй производной }
Function derivat2(x0, eps : real) : real;
var
dx, dy, dy3 : real;
begin
dx := 1;
repeat
dx := dx/2;
dy := fx(x0 + dx) - 2*fx(x0) + fx(x0 - dx);
dy3 := fx(5*x0/4 + 2*dx) - 2*fx(5*x0/4 + dx);
dy3 := dy3 - fx(5*x0/4 - 2*dx) + 2*fx(5*x0/4 - dx)
until abs(dy3/(6*dx)) < eps;
derivat2 := dy/(dx*dx)
end;
344 
Программа
{ Решение уравнений методом касательных. method - метод }
{ tangent - касательная. Правило пропорциональных частей }
Program Method_Tangent;
uses WinCrt;
var
a, b, x, min, eps : real;
{----------------------------------------------------------------------------------------}
{ Заданная функция }
Function fx(x : real) : real;
begin
fx := x*x*x - 2*x*x - 4*x - 7
end;
{----------------------------------------------------------------------------------------}
{ Вычисление 1-й производной }
{ derivative - производная }
Function derivat1(x0, eps : real) : real;
var
dx, dy, dy2 : real;
begin
dx := 1;
repeat
dx := dx/2;
dy := fx(x0 + dx/2) - fx(x0 - dx/2);
dy2 := fx(5*x0/4 + dx) - 2*fx(5*x0/4);
dy2 := dy2 + fx(5*x0/4 - dx)
until abs((dy2*dy2*fx(x0))/(2*dx)) < eps;
derivat1 := dy/dx
end;
{----------------------------------------------------------------------------------------}
Function derivat2(x0, eps : real) : real;
var
dx, dy, dy3 : real;
begin
dx := 1;
repeat
dx := dx/2;
dy := fx(x0 + dx) - 2*fx(x0) + fx(x0 - dx);
dy3 := fx(5*x0/4 + 2*dx) - 2*fx(5*x0/4 + dx);
dy3 := dy3 - fx(5*x0/4 - 2*dx) + 2*fx(5*x0/4 - dx)
until abs(dy3/(6*dx)) < eps;
derivat2 := dy/(dx*dx)
end;
{----------------------------------------------------------------------------------------}
{ Функция вычисления порядка - кол-во знаков после запятой }
Function t(eps : real) : integer;
var
k : integer;
begin
k := -1;
repeat
345

eps := eps*10;
k := k + 1
until eps > 1;
t := k
end;
{----------------------------------------------------------------------------------------}
{ Процедура определения наименьшего значения производной }
{ на заданном промежутке }
Procedure minimum(a, b, eps : real; var min : real);
var
d : real;
begin
a := a - eps;
b := b + eps;
repeat
a := a + eps;
b := b - eps;
min := abs(derivat1(a, eps));
d := abs(derivat1(b, eps));
if min > d then min := d
until min <> 0
end;
{----------------------------------------------------------------------------------------}
{ Процедура уточнения корня методом касательных }
Procedure tangent(a, b, eps, min : real; var x : real);
var
x1 : real;
begin
x1 := a;
repeat
x := x1 - fx(x1)/derivat1(x1, eps);
x1 := x
until abs(fx(x))/min < eps
end;
{----------------------------------------------------------------------------------------}
{ Основная программа }
begin
write('Введите левый конец промежутка a = '); readln(a);
write('Введите правый конец промежутка b = ');
readln(b);
write('Введите точность вычисления корня eps = ');
readln(eps);
minimum(a, b, eps, min);
if fx(a)*derivat2(a, eps) > 0
then tangent(a, b, eps, min, x)
else tangent(b, a, eps, min, x);
writeln('Корень уравнения равен x = ', x:6:t(eps));
writeln('С точностью до eps = ', eps:1:t(eps))
end.
346 
Вы обратили внимание, что первая производная вычисляется с определением точности вторым способом через приращение аргумента и приращение функции. Почему это
сделано?
Когда выяснялся вопрос о точности вычисления производных, то оговаривалось, что
при оценки погрешности первой производной по значению второй производной, точка, в
которой вычисляется значение второй производной должна быть отлична от x0 и от точек,
которые отстоят от x0 на расстоянии кратном dx. При вычислении корня по методу касательных значение первой производной меняется в зависимости от x1, которое может
неожиданно попасть в точку, отстоящую от x0 на расстоянии кратном dx, что недопустимо. Поэтому оценка погрешности выполняется вторым способом.
1.4. Комбинированный метод касательных и хорд
Он состоит в одновременном использовании как метода касательных, так и метода
хорд.
Если Вы внимательно следили за вычислениями приближенных значений двумя методами, то вероятно заметили, что если методом хорд последовательность значений,
начиная от первоначального значения a - левого конца промежутка, возрастает, то для
этого же случая по методу касательных последовательность убывает.
Для других двух случаев получается наоборот. Таким образом, получаемые последовательности сближаются и тем самым, применяя одновременно два метода можно получить более быстрое приближение корня.
Если мы имеем дело со случаем 1, тогда, обозначая приближенные значения по методу хорд x1, а по методу касательных - z1, получим:
(b  a) f (a)
f (b )
x1  a 
, z1  b 
;
f (b)  f (a)
f ' (b )
тогда,
a < x1 < c < z1 < b.
При следующем шаге заменяется в этих формулах a и b через x1 и z1:
(z1  x 1 ) f ( x 1 )
f (z1 )
.
x 2  x1 
, z2  z1 
f (z1 )  f ( x 1 )
f ' (z1 )
Общие формулу для построения приближений будут следующими:
(z n  x n ) f ( x n )
f ( zn )
.
x n1  x n 
, zn  1  zn 
f (z n )  f ( x n )
f ' ( zn )
О качестве достигнутого приближения, т.е. о точности, можно судить по величине
|zn - xn| - в этом удобство комбинированного метода.
Необходимо изменить процедуры вычисления приближенных корней уравнения по
методу хорд и методу касательных следующим образом:
{ Процедура уточнения корня методом хорд }
Procedure chord(a, b : real; var x : real);
begin
x := a - ((b - a)*fx(a))/(fx(b) - fx(a))
end;
{----------------------------------------------------------------------------------------}
{ Процедура уточнения корня методом касательных }
Procedure tangent(a, b, eps : real; var z : real);
begin
z := a - fx(a)/derivat1(a, eps)
end;
347

В основной программе организовать цикл до выполнения условия | x  z |  eps, а в
самом цикле в зависимости от знака функции и ее производной изменяйте значения a и b
на x и z.
{ Решение уравнений комбинированным методом хорд и касательных }
Program Combination_Method;
uses WinCrt;
var
a, b, x, z, eps : real;
{----------------------------------------------------------------------------------------}
{ Заданная функция }
Function fx(x : real) : real;
begin
fx := x*sin(x) - 0.5
end;
{----------------------------------------------------------------------------------------}
{ Вычисление 1-й производной }
{ derivative - производная }
Function derivat1(x0, eps : real) : real;
var
dx, dy, dy2 : real;
begin
dx := 1;
repeat
dx := dx/2;
dy := fx(x0 + dx/2) - fx(x0 - dx/2);
dy2 := fx(5*x0/4 + dx) - 2*fx(5*x0/4);
dy2 := dy2 + fx(5*x0/4 - dx)
until abs((dy2*dy2*fx(x0))/(2*dx)) < eps;
derivat1 := dy/dx
end;
{----------------------------------------------------------------------------------------}
{ Функция вычисления второй производной }
Function derivat2(x0, eps : real) : real;
var
dx, dy, dy3 : real;
begin
dx := 1;
repeat
dx := dx/2;
dy := fx(x0 + dx) - 2*fx(x0) + fx(x0 - dx);
dy3 := fx(5*x0/4 + 2*dx) - 2*fx(5*x0/4 + dx);
dy3 := dy3 - fx(5*x0/4 - 2*dx) + 2*fx(5*x0/4 - dx)
until abs(dy3/(6*dx)) < eps;
derivat2 := dy/(dx*dx)
end;
{----------------------------------------------------------------------------------------}
{ Функция вычисления порядка - кол-во знаков после запятой }
Function t(eps : real) : integer;
var
k : integer;
begin
348 
k := -1;
repeat
eps := eps*10;
k := k + 1
until eps > 1;
t := k
end;
{----------------------------------------------------------------------------------------}
{ Процедура уточнения корня методом хорд }
Procedure chord(a, b : real; var x : real);
begin
x := a - ((b - a)*fx(a))/(fx(b) - fx(a))
end;
{----------------------------------------------------------------------------------------}
{ Процедура уточнения корня методом касательных }
Procedure tangent(a, b, eps : real; var z : real);
begin
z := a - fx(a)/derivat1(a, eps)
end;
{----------------------------------------------------------------------------------------}
{ Основная программа }
begin
write('Введите левый конец промежутка a = '); readln(a);
write('Введите правый конец промежутка b = '); readln(b);
write('Введите точность вычисления корня eps = ');
readln(eps);
repeat
if fx(a)*derivat2(a, eps) > 0
then
begin
tangent(a, b, eps, z);
chord(b, a, x);
b := z; a := x
end
else
begin
tangent(b, a, eps, z);
chord(a, b, x);
b := x; a := z
end
until abs(z - x) < eps;
writeln('Корень уравнения равен x = ', x:6:t(eps));
writeln('С точностью до eps = ', eps:1:t(eps))
end.
Задание 2
При выполнении задания Вам необходимо использовать программу отделения корней, которая изучалась ранее. Таким образом, задания надо выполнять в таком порядке:
1) графическим путем найти самый "большой" промежуток, на котором может находится один или более корней (это можно сделать "вручную", схематически вычертив графики функции);
349

2) составить программу, в которой объединяется метод отделения корней (другими
словами, нахождение изолированных промежутков) и соответствующий метод уточнения
корня (метод хорд, касательных или комбинированный).
1. При решении следующих уравнений используйте для уточнения корня метод
хорд:
x 3  3x  1  0, x 5  5x  1  0.
2. Примените для уточнения корня метод касательных:
xex  2, x ln x  0,8, 3 x  3x .
Замечание. Последнее уравнение можно преобразовать к виду более удобному для
решения: ln(3x ) = ln(3x) или xln3 = ln(3x), xln3 - ln(3x) = 0.
Вообще для вычисления степени ax с любым действительным показателем и любым
положительным действительным основанием можно составить отдельную процедуру, основываясь на следующих соображениях:
ax = y, ln(a x) = lny, xlna = lny, y = e xlna, окончательно получаем a = exlnx .
На Паскале это запишется так: exp(x*ln(a)).
3. Для решения следующих уравнений используйте в качестве метода уточнения
корней, комбинированный метод:
2x 3  x 2  7x  5
 0;
x 4  3x 2  75x  10000  0;
x sin x  0.5
 0;
x  x 1
 0.
4
2. Выбор метода. Оператор Case...of...
Часто возникает необходимость сделать выбор из любого количества вариантов. В
нашем случае такое может возникнуть, если пользователю необходимо выбрать из трех
методов уточнения корня - один, по усмотрению пользователя, который, в свою очередь,
выбирает метод в зависимости от заданной функции.
Структура оператора выбора в Turbo Pascale следующая:
Case I of
Const1 : S1;
Const2 : S2;
............
ConstN : SN;
else S
end;
В этой записи: I - выражение порядкового типа, значение которого вычисляется;
Const1, Const2, ..., ConstN - константы, с которыми сравнивается значение выражения I;
S1, S2, ..., SN - операторы, из которых выполняется тот, с соответствующей константой
которого совпадает значение выражения I; S - оператор, который выполняется, если значение выражения I не совпадает ни с одной из констант Const1, ..., ConstN.
Ветвь оператора else является необязательной. Если она отсутствует и значение I не
совпадает ни с одной из перечисленных констант, весь оператор рассматривается как пустой. В отличие от оператора if перед словом else точку с запятой можно ставить.
Если для нескольких констант нужно выполнить один и тот же оператор, их можно
перечислить через запятую (или даже указать диапазон, если это возможно), сопроводив
их одним оператором.
350 
Пример 1
Program Problem1; { Вычисление значений функций }
uses WinCrt;
var
i : integer;
x : real;
begin
{ Инструкция }
write('Введите значение аргумента '); readln(x);
writeln('Наберите соответствующий номер для');
writeln('вычисления значения нужной вам функции');
writeln('1 - sin(x), 2 - cos(x), 3 - exp(x), 4 - ln(x)');
readln(i);
Case I of
1 : writeln('Значение sinx = ', sin(x):1:8);
2 : writeln('Значение cosx = ', cos(x):1:8);
3 : writeln('Значение exp(x) = ', exp(x):8:8);
4 : writeln('Значение ln(x) = ', ln(x):8:8)
end
end.
Пример 2.
Case I of
0, 2, 4, 6, 8 : writeln('Четная цифра');
1, 3, 5, 7, 9 : writeln('Нечетная цифра');
10..100
: writeln('Числа от 10 до 100');
else
writeln('Отрицательное число или больше 100')
end;
Обратимся к поставленной задачи - выбора метода уточнения корня в зависимости
от воли пользователя и особенностей заданной функции.
{ Основная программа }
begin
write('Введите левый конец промежутка a = '); readln(a);
write('Введите правый конец промежутка b = '); readln(b);
write('Введите точность вычисления корня eps = '); readln(eps);
writeln('Для выбора метода решения, введите его номер ');
writeln('1 - метод хорд, 2 - метод касательных');
writeln(' 3 - комбинированный метод'); readln(k);
Case k of
1 : вызов процедуры метода хорд;
2 : вызов процедуры метода касательных;
3 : вызов процедуры комбинированного метода;
end;
writeln('Корень уравнения равен x = ', x:12:t(eps));
writeln('С точностью до eps = ', eps:1:t(eps))
end.
351

Но каждая из процедур должна претерпеть некоторые изменения, так как в предыдущих программа каждая из процедур, образно говоря, была менее независима от других
конструкций программы, а теперь она должна быть полностью автономна.
{ Процедура уточнения корня методом хорд }
Procedure chord1(a, b, eps : real; var x : real);
var
x1, min : real;
begin
minimum(a, b, eps, min);
x1 := a;
repeat
x := x1 - ((b - x1)*fx(x1))/(fx(b) - fx(x1));
x1 := x
until abs(fx(x))/min < eps
end;
Она названа Chord1, потому что в программе будет еще одна процедура под именем
Chord, которая помогает в работе комбинированному методу.
Процедура вычисления корня по методу касательных может стать такой:
Procedure Tangent2(a, b, eps : real; var x : real);
var
min : real;
begin
minimum(a, b, eps, min);
if fx(a)*derivat2(a, eps) > 0
then tangent1(a, b, eps, min, x)
else tangent1(b, a, eps, min, x)
end;
Она названа Tangent2, так как сама использует процедуру tangent1:
Procedure tangent1(a, b, eps, min : real; var x : real);
var
x1 : real;
begin
x1 := a;
repeat
x := x1 - fx(x1)/derivat1(x1, eps);
x1 := x
until abs(fx(x))/min < eps
end;
А эта процедура названа tangent1, потому что процедура под именем tangent используется в работе комбинированного метода, процедура которого может быть такой:
{ Комбинированный метод }
Procedure Combination(a, b, eps : real; var x : real);
var
z : real;
begin
352 
repeat
if fx(a)*derivat2(a, eps) > 0
then
begin
tangent(a, b, eps, z);
chord(b, a, x);
b := z; a := x
end
else
begin
tangent(b, a, eps, z);
chord(a, b, x);
b := x; a := z
end
until abs(z - x) < eps
end;
Разумеется в программе должны быть функции вычисления первой и второй производных, а также заданная функция.
Задание 3
Составьте полностью программу. Используйте ее для вычисления корней уравнений
из предыдущего задания 2, выбирая метод в зависимости от уравнения и собственных соображений.
3. Приближенное вычисление интегралов
b
Пусть требуется вычислить определенный интеграл  f (x )dx , где f(x) непрерывная
a
на [a, b] функция. Надо заметить, что с помощью различных способов нахождения первообразных можно вычислить интегралы для довольно незначительного класса функций,
поэтому возникает необходимость в приближенных методах вычисления интегралов.
На этом занятии мы познакомимся с простыми способами приближенного вычисления: формулой прямоугольников, формулой трапеций, формулой Симпсона или параболическим интегрированием, методом Монте-Карло.
3.1. Формула прямоугольников
Будем исходить из геометрических соображений и рассматривать определенный инb
теграл
 f (x)dx ,как площадь некоторой фигуры, чаще всего ее называют криволинейной
a
трапецией, ограниченной кривой y = f(x), осью Ox и прямыми y=a, y = b. Будем также
предполагать, что функция y = f(x) непрерывна на [a. b].
353

Рис. 48
Идея, которая привела к понятию определенного интеграла заключалась в следующем. Разбить всю фигуру на полоски одинаковой ширины dx = (b - a)/n, а затем каждую
полоску заменить прямоугольником, высота которого равно какой-либо ординате (см. рис.
48).
Тогда получится следующая формула:
b
ba
a f (x)dx  n ( f (c0 )  f (c1 )... f (cn1 )),
где xi <= ci <= xi+1 (i = 0, 1, ..., n-1). Площадь криволинейной фигуры заменится площадью
сумм прямоугольников. Эта приближенная формула и называется формулой прямоугольников.
Практически, в качестве точки ci берут середину промежутка [xi , xi+1], т. е.
x x
ci  i i 1 .
2
Нетрудно составить процедуру вычисления такой суммы.
{ Вычисление интеграла методом прямоугольников }
{ Rectangle - прямоугольник }
Procedure Rectangle(a, b : real; n : integer; var j : real);
var
dx, c, f : real;
i
: integer;
begin
dx := (b - a)/n;
c := a + dx/2;
f := fx(c);
for i := 1 to n - 1 do
begin
c := c + dx;
f := f + fx(c)
end;
j := dx * f
end;
Теперь возникает вопрос о числе точек деления - n, который напрямую связан с точностью вычисления интеграла.
Известно, что точность вычисления интеграла по формуле прямоугольников оценивается по дополнительному члену, который выражается формулой:
354 
(b  a ) 3
f ' ' (c), где a  c  b,
24n 2
значит оценивать точность вычисления можно по модулю этого остаточного или дополнительного члена, |Rn|.
Вторую производную вычислить мы сможем с достаточно высокой степенью точности, применив следующую функцию:
Rn 
{ Функция вычисления второй производной }
Function derivat2(x0, eps : real) : real;
var
dx, dy, dy3 : real;
begin
dx := 1;
repeat
dx := dx/2;
dy := fx(x0 + dx) - 2*fx(x0) + fx(x0 - dx);
dy3 := fx(5*x0/4 + 2*dx) - 2*fx(5*x0/4 + dx);
dy3 := dy3 - fx(5*x0/4 - 2*dx) + 2*fx(5*x0/4 - dx)
until abs(dy3/(6*dx)) < eps;
derivat2 := dy/(dx*dx)
end;
Осталось выяснить, в какой точке промежутка интегрирования [a, b] находить значение этой производной. Остаточный член не требует строго определенного значения аргумента из этого промежутка, поэтому можно выбрать любое значение, не выходящее за
пределы интервала [a, b]. Сразу возникает мысль вычислить вторую производную в середине промежутка, т.е. в точке (a + b)/2. Но представьте себе ситуацию, когда промежуток
[-1, 1] или [-6.28; 6.28], тогда середина этого отрезка - точка 0 и значение производной будет равно нулю, а значит для числа точек деления n может быть установлено значение
любое, даже 1, что, конечно, не даст требуемой точности вычисления интеграла.
Итак, следующая проблема, в какой точке промежутка находить значение производной?
Можно найти наибольшее значение производной на промежутке интегрирования [a,
b]. Это можно сделать с помощью процедуры:
{ Определение наибольшего значения второй производной }
Procedure Maximum(a, b, eps : real; var max : real);
var
dx, x : real;
begin
dx := 0.1; x := a;
max := abs(derivat2(x, eps));
while x<= b do
begin
x := x + dx;
if max < abs(derivat2(x, eps))
then max := abs(derivat2(x, eps))
end
end;
В ней установлен шаг - 0.1 и затем, в каждой следующей точке промежутка определяется значение второй производной и находится наибольшее.
355

Теперь составим процедуру определения числа точек деления, а затем и полностью
программу.
{ Процедура определения числа точек деления промежутка интегр. }
Procedure Number(a, b, eps, max : real; var n : integer);
var
d : real;
begin
n := 1;
d := abs((b - a)*(b - a)*(b - a));
while (max*d)/(24*n*n) >= eps do n := n+1;
end;
Программа вычисления интеграла по формуле прямоугольников
{ Вычисление интеграла по формуле прямоугольников }
Program Jntegral_Rectangle2;
uses WinCrt;
var
a, b, eps, j : real;
n
: integer;
{----------------------------------------------------------------------------------------}
Function fx(x : real) : real;
begin
fx := sin(x)
end;
{----------------------------------------------------------------------------------------}
{ Функция вычисления порядка - кол-во знаков после запятой }
Function t(eps : real) : integer;
var
k : integer;
begin
k := -1;
repeat
eps := eps*10;
k := k + 1
until eps > 1;
t := k
end;
{----------------------------------------------------------------------------------------}
{ Функция вычисления второй производной }
Function derivat2(x0, eps : real) : real;
var
dx, dy, dy3 : real;
begin
dx := 1;
repeat
dx := dx/2;
dy := fx(x0 + dx) - 2*fx(x0) + fx(x0 - dx);
dy3 := fx(5*x0/4 + 2*dx) - 2*fx(5*x0/4 + dx);
dy3 := dy3 - fx(5*x0/4 - 2*dx) + 2*fx(5*x0/4 - dx)
until abs(dy3/(6*dx)) < eps;
356 
derivat2 := dy/(dx*dx)
end;
{----------------------------------------------------------------------------------------}
{ Процедура определения числа точек деления промежутка интегр. }
Procedure Number(a, b, eps : real; var n : integer);
var
dy2, d, c, dx : real;
begin
c := (a + b)/2;
dy2 := derivat2(c, eps);
if dy2 = 0
then
begin
c := a; dx := (b - a)/10;
while derivat2(c, eps) = 0 do c := c + dx;
dy2 := derivat2(c, eps)
end;
n := 1;
d := abs((b - a)*(b - a)*(b - a));
while abs(dy2*d)/(24*n*n) >= eps do n := n+1;
end;
{----------------------------------------------------------------------------------------}
{ Вычисление интеграла методом прямоугольников }
Procedure Rectangle(a, b : real; n : integer; var j : real);
var
dx, c, f : real;
i
: integer;
begin
dx := (b - a)/n;
c := a + dx/2;
f := fx(c);
for i := 1 to n - 1 do
begin
c := c + dx;
f := f + fx(c)
end;
j := dx * f
end;
{----------------------------------------------------------------------------------------}
{ Основная программа }
begin
write('Введите нижний предел интегрирования '); readln(a);
write('Введите верхний предел интегрирования '); readln(b);
write('Введите точность вычисления интеграла '); readln(eps);
Number(a, b, eps, n); Rectangle(a, b, n, j);
writeln('Значение интеграла равно ', j:6:t(eps));
writeln('С точностью до ', eps:1:t(eps))
end.
Такой способ можно использовать, но он может быть долгим, особенно, если большой промежуток интегрирования, малый шаг и более высокая точность вычисления производной.
Для определения числа точек деления можно применить и другой прием.

357
{ Процедура определения числа точек деления промежутка интегр. }
Procedure Number(a, b, eps : real; var n : integer);
var
dy2, d, c, dx : real;
begin
c := (a + b)/2;
dy2 := derivat2(c, eps);
dx := (b - a)/10;
if dy2 = 0
then
begin
c := a;
while derivat2(c, eps) = 0 do c := c + dx;
dy2 := derivat2(c, eps)
end;
n := 1;
d := abs((b - a)*(b - a)*(b - a));
while abs(dy2*d)/(24*n*n) >= eps do n := n+1;
end;
Как работает эта процедура? Вычисляется значение второй производной в середине
промежутка: c := (a + b)/2. Если она не равна нулю, тогда все в порядке, вычисляется в зависимости от заданной точности число точек деления n. Если значение второй производной равно нулю в середине промежутка интегрирования: dy2 = 0, тогда устанавливается
шаг dx := (b - a)/10 и начинается цикл, в котором вычисляется производная через каждый
промежуток dx, начиная от точки a, пока производная равна нулю цикл продолжается и
заканчивается как только она не станет равной нулю.
Такой прием экономит время работы программы, производную можно вычислить с
большей точностью, да и сама программа становится менее громоздкой:
Program Jntegral_Rectangle2;
uses WinCrt;
var
a, b, eps, j : real;
n
: integer;
Function fx(x : real) : real;
begin
fx := sin(x)
end;
{----------------------------------------------------------------------------------------}
{ Функция вычисления порядка - кол-во знаков после запятой }
Function t(eps : real) : integer;
var
k : integer;
begin
k := -1;
repeat
eps := eps*10;
k := k + 1
until eps > 1;
t := k
end;
{----------------------------------------------------------------------------------------}
{ Функция вычисления второй производной }
358 
Function derivat2(x0, eps : real) : real;
var
dx, dy, dy3 : real;
begin
dx := 1;
repeat
dx := dx/2;
dy := fx(x0 + dx) - 2*fx(x0) + fx(x0 - dx);
dy3 := fx(5*x0/4 + 2*dx) - 2*fx(5*x0/4 + dx);
dy3 := dy3 - fx(5*x0/4 - 2*dx) + 2*fx(5*x0/4 - dx)
until abs(dy3/(6*dx)) < eps;
derivat2 := dy/(dx*dx)
end;
{----------------------------------------------------------------------------------------}
{ Процедура определения числа точек деления промежутка интегр. }
Procedure Number(a, b, eps : real; var n : integer);
var
dy2, d, c, dx : real;
begin
c := (a + b)/2;
dy2 := derivat2(c, eps);
if dy2 = 0
then
begin
c := a; dx := (b - a)/10;
while derivat2(c, eps) = 0 do c := c + dx;
dy2 := derivat2(c, eps)
end;
n := 1;
d := abs((b - a)*(b - a)*(b - a));
while abs(dy2*d)/(24*n*n) >= eps do n := n+1;
end;
{----------------------------------------------------------------------------------------}
{ Вычисление интеграла методом прямоугольников }
Procedure Rectangle(a, b : real; n : integer; var j : real);
var
dx, c, f : real;
i
: integer;
begin
dx := (b - a)/n;
c := a + dx/2;
f := fx(c);
for i := 1 to n - 1 do
begin
c := c + dx;
f := f + fx(c)
end;
j := dx * f
end;
{----------------------------------------------------------------------------------------}
{ Основная программа }
begin
359

write('Введите нижний предел интегрирования '); readln(a);
write('Введите верхний предел интегрирования '); readln(b);
write('Введите точность вычисления интеграла ');
readln(eps);
Number(a, b, eps, n);
Rectangle(a, b, n, j);
writeln('Значение интеграла равно ', j:6:t(eps));
writeln('С точностью до ', eps:1:t(eps))
end.
3.2. ФОРМУЛА
ТРАПЕЦИЙ
Рис. 49
Заменим данную кривую вписанной в нее ломаной, с вершинами в точках (x i, yi), где
yi = f(xi) (i = 0, 1, 2, ..., n-1). Тогда криволинейная трапеция заменится фигурой, состоящей
из трапеций (см. рис. 49). Будем по-прежнему считать, что промежуток [a, b] разбит на
равные части, тогда площади этих трапеций будут равны:
b  a y0  y1 b  a y1  y2
b  a y n  y n
,
, ...,
.
n
2
n
2
n
2
Складывая полученные значения, приходим к приближенной формуле:
b
b  a  y0  y n

a f ( x )dx  2  2  y1  y2 ... y n1 .
Эта приближенная формула называется формулой трапеций.
Оценка погрешности формулы трапеций определяется по следующему дополнительному члену:
(b  a ) 3
(a  c  b).
Rn  
f ' ' ( c)
12n 2
Задание 4
Составьте процедуры вычисления интеграла по формуле трапеций и процедуру
определения числа точек деления.
Составьте полностью программу и вычислите интегралы следующих функций на
указанных промежутках с заданной точностью:
1) f(x) = 1/x
на [1; 2] с точностью до 0.001;
2
2
2) f(x) = x/(x + 1)
на [-1; 2] с точностью до 0.01;
3) f(x) = 1/cos2 x
на [0; Pi/3] с точностью до 0.0000001.
360 
3.3. Параболическое интерполирование. Дробление промежутка интегрирования. Формула Симпсона
Параболическое интерполирование
Для приближенного вычисления интеграла функции y  f (x ) на промежутке [a, b]
можно заменить функцию f(x) многочленом
y  Pn (x )  a0 x k  a1 x k 1 ... ak 1 x  ak
и тогда будет выполняться приближенное равенство
b
b
a
a
 f (x)dx   Pk (x)dx.
Такая замена тем более важна, когда подынтегральная функция представляет собой
выражение, интеграл которой точно вычислить нельзя.
Геометрически это можно представить так, что криволинейная трапеция, находящаяся под кривой y = f(x) заменяется "параболой k-го порядка", поэтому такой процесс получил название параболическое интерполирование.
Существует много интерполяционных многочленов, о некоторых из них мы будем
говорить на других занятиях, а на этом познакомимся с интерполяционным многочленом
Лагранжа, который строится по следующей формуле:
(x  c1 )(x  c2 )...(x  ck )
(x  c0 )(x  c2 )...(x  ck )
Pk (x ) 
f (c0 ) 
f (c1 )...
(c0  c1 )(c0  c2 )...(c0  ck )
(c1  c0 )(c1  c2 )...(c1  ck )
(x  c1 )(x  c2 )...(x  ck 1 )

f (ck ).
(ck  c0 )(ck  c1 )...(ck  ck 1 )
При
интегрировании
получается
линейное
относительно
значений
f (c0 ), ..., f (x k ) выражение, коэффициенты которого от этих значений не зависят. Вычислив коэффициенты, можно ими пользоваться для любой функции f(x) в заданном промежутке [a, b].
При k = 0, функция f(x) просто заменяется постоянной f(c0), где c0 - любая точка из
промежутка [a, b], например средняя: c0 = (a + b)/2. Тогда приближенно
b
 b  a
a f ( x )dx  (b  a) f  2 .
Геометрически это означает, что криволинейная фигура под кривой y = f(x) заменяется прямоугольником с высотой, равной средней ординате.
При k = 1 функция f(x) заменяется линейной функцией P 1(x), которая имеет одинаковые с ней значения при x = c0 и x = c1. Если взять c0 = a, c1 = b, то
xb
xa
P1 (x ) 
f (a ) 
f (b).
ab
ba
после преобразования, получим
b
f (a )  f (b)
.
a P1 (x)dx  (b  a )
2
Таким образом, здесь мы приближенно допускаем
b
f (a )  f (b)
.
a f (x)dx  (b  a )
2
Геометрически это будет представляться, как замена криволинейной фигуры трапецией: вместо кривой берется хорда, соединяющая ее концы.
Более интересный результат получается, если взять k = 2. Можно положить c0= a, c1
= (a + b)/2, c2 = b, тогда интерполяционный многочлен P2(x), будет иметь вид
361

a  b

x 
 ( x  b)

( x  a)( x  b)
2 
 a  b
P2 ( x ) 
f (a) 
f

a  b
a  b  a  b   2 


 b
a 
 (a  b)
a 




2 
2  2
a  b

(x  a) x 


2 

f (b).
a  b

(b  a) b 


2 
После преобразований и интегрирования многочлена P2(x), приходим к приближенной формуле
b

b a
 a  b
(7)
a f ( x )dx  6  f (a)  4 f  2   f (b).
В этом случае, площадь фигуры под кривой заменяется площадью фигуры, ограниченной параболой (с вертикальной осью), проходящей через крайние и среднюю точки
кривой.
Увеличивая степень k интерполяционного многочлена, т.е. проводя параболу через
все большее число точек данной кривой, можно добиться большей точности. Но на практике часто используют другой способ, основанный на сочетании параболического интерполирования с идеей дробления промежутка.
3.4. Дробление промежутка интегрирования
b
Для вычисления интеграла
 f (x)dx
можно поступить таким способом. Разобьем
a
сначала промежуток [a, b] на некоторое число, n, равных промежутков
[x0, x1], [x1, x2], ..., [xn-1, xn] (x0 = a, xn = b),
искомый интеграл представится в виде суммы
x1
x2
xn
x0
x1
xn  1
 f (x )dx   f (x )dx...  f (x )dx.
После этого, к каждому из этих промежутков применим параболическое интерполирование, т.е. станем вычислять перечисленные интегралы по одной из приближенных
формул: прямоугольников, трапеций или по параболической формуле (7).
В первых двух случаях мы получим уже известные формулы прямоугольников и
трапеций.
Применим теперь формулу (7) к каждому из интегралов, при этом положим, что
x x
f (xi )  yi , i i 1  xi 1/ 2 , f (xi 1/ 2 )  yi 1/ 2 .
2
Получим
x1
 f (x )dx 
x0
x2
 f (x )dx 
x1
ba
( y0  4 y1/ 2  y1 )
6n
ba
( y1  4 y3/ 2  y2 )
6n
................................................
362 
xn
 f (x )dx 
xn 1
ba
( yn 1  4 yn 1/ 2  yn ).
6n
Складывая почленно эти равенства, получим формулу:
b
ba
a f (x)dx  6n [( y0  yn )  2( y1  y2 ... yn1 )  4( y1/ 2  y3/ 2 ... yn1/ 2 )]. (8)
Эта формула называется формулой Симпсона. Ею пользуются для приближенного
вычисления интегралов чаще, чем формулами прямоугольников и трапеций, так как она
дает более точный результат.
Составим процедуру на языке Паскаль реализующую эту формулу.
{ Вычисление интеграла по формуле Симпсона }
Procedure Simpson(a, b : real; n : integer; var j : real);
var
dx, c, c1, f : real;
i
: integer;
begin
dx := (b - a)/n;
c := a;
c1 := a + dx/2;
f := fx(a) + fx(b) + 4*fx(c1);
for i := 1 to n - 1 do
begin
c := c + dx; c1 := c1 + dx;
f := f + 2*fx(c) + 4*fx(c1)
end;
j := (dx/6)* f
end;
Остается выяснить вопрос о числе точек деления в зависимости от заданной точности вычисления, другими словами, установить погрешность вычисления.
Если промежуток [a, b] разделен на n равных частей, то для формулы Симпсона дополнительный член имеет вид
(b  a )5 ( 4 )
Rn 
f (c), (a  c  b)
180(2n)4
Значит оценить точность вычисления можно по модулю этого дополнительного члена: |Rn|.
Однако, это связано с неприятностью находить 4-ю производную функции, что достаточно нелегкое дело. Есть и другой путь оценки точности вычисления интегралов и не
только по формуле Симпсона, но и по формуле прямоугольника и трапеций.
Этот прием заключается в следующем. Искомый интеграл вычисляется дважды: при
делении отрезка [a, b] на n частей и на 2n частей. Полученные значения интегралов In и I2n
сравниваются и первые совпадающие десятичные знаки считаются верными.
Покажем, как, используя такой метод оценить точность интеграла, вычисленного по
формуле Симпсона.
Преобразуем дополнительный член Rn формулы Симпсона:
(b  a )5
(b  a )h4
Rn  
f (c) 
f (c), где h = (b - a)/2n.
180(2n) 4
180
Пусть Rn и R2n - погрешности интегрирования, тогда, учитывая предыдущую формулу можно составить пропорцию:
363

Rn
h4
 4n ,
R2 n h2 n
Понятно, что h2n = hn/2. Тогда из пропорции получаем: Rn = 16 R2n. Если I - истинное
значение интеграла, то I = In + Rn и I = I2n + R2n, откуда находим: In + 16 R2n = I2n + R2n, т.е.
|I  I |
| R2 n |  n 2 n .
15
Надо помнить, что в процессе практических вычислений при последовательном
удвоении числа отрезков разбиения начинает сильно прогрессировать удельный вес
ошибки округления, значение которой с некоторого момента ставит предел достижимой
точности.
Ниже, мы рассмотрим и другой способ оценки точности. А сейчас, основываясь на
последней формуле, составим программу вычисления интеграла с применением формулы
Симпсона.
{ Вычисление интеграла по формуле Симпсона }
Program Jntegral_Simpson;
uses WinCrt;
var
a, b, eps, j, j1 : real;
n
: integer;
Function fx(x : real) : real;
begin
fx := exp(-x*x)
end;
{----------------------------------------------------------------------------------------}
{ Функция вычисления порядка - кол-во знаков после запятой }
Function t(eps : real) : integer;
var
k : integer;
begin
k := -1;
repeat
eps := eps*10;
k := k + 1
until eps > 1;
t := k
end;
{----------------------------------------------------------------------------------------}
{ Вычисление интеграла по формуле Симпсона }
Procedure Simpson(a, b : real; n : integer; var j : real);
var
dx, c, c1, f : real;
i
: integer;
begin
dx := (b - a)/n;
c := a;
c1 := a + dx/2;
f := fx(a) + fx(b) + 4*fx(c1);
for i := 1 to n - 1 do
begin
c := c + dx; c1 := c1 + dx;
364 
f := f + 2*fx(c) + 4*fx(c1)
end;
j := (dx/6)* f
end;
{----------------------------------------------------------------------------------------}
{ Основная программа }
begin
write('Введите нижний предел интегрирования '); readln(a);
write('Введите верхний предел интегрирования '); readln(b);
write('Введите точность вычисления интеграла '); readln(eps);
n := 2;
Simpson(a, b, n, j); Simpson(a, b, 2*n, j1);
while abs(j - j1)/15 > eps do
begin
n := n + 2;
Simpson(a, b, n, j); Simpson(a, b, 2*n, j1)
end;
writeln('Значение интеграла равно ', j1:6:t(eps));
writeln('С точностью до ', eps:1:t(eps))
end.
3.5. Об оценке погрешности
При вычисление интегралов по формуле прямоугольников и по формуле трапеций
оценка погрешности делалась по формуле с помощью второй производной, которая была
ограничена на заданном промежутке своим наибольшим значением.
Так, в формуле трапеций, оценка погрешности использовалась для определения числа точек разбиения, которое определяло точность вычисления. Это делалось с помощью
процедуры:
{ Процедура определения числа точек деления промежутка интегр. }
Procedure Number(a, b, eps, max : real; var n : integer);
var
d : real;
begin
n := 1;
d := abs((b - a)*(b - a)*(b - a));
while (max*d)/(24*n*n) >= eps do n := n+1;
end;
Такого рода оценки погрешности называются гарантированными оценками погрешности.
На основании этой оценки можно гарантировать, что погрешность приближенного
значения интеграла не превосходит определенной величины.
Существует второй способ оценки - отказ от получения строгой, гарантированной
оценки погрешности и получение оценки погрешности лишь с определенной степенью
достоверности. В частности при оценки погрешности вычисления интеграла по методу
Симпсона погрешность оценивалась через разность результатов приближенного значения
интеграла при различных значениях параметров, в частности, при n и 2n.
Необходимость применения метода Симпсона, как раз по причине метода оценки
погрешности, примененной в этом методе, в следующих случаях.
1) Когда уже первая производная подынтегральной функции равна нулю.
365

2) Когда первая производная подынтегральной функции обращается в точках (пределах интегрирования или других) в бесконечность.
Примером может быть интеграл
1
 ln x  ln(1  x )dx
0
Подынтегральная функция при x  0 стремится к 0, а поэтому ее можно считать
непрерывной на промежутке от 0 до 1.
Эти два обстоятельства вызывают необходимость выбирать метод интегрирования в
зависимости от заданной функции и поведения ее производных.
Задание 5
1. Используя оператор выбора Case ... of ..., составьте программу, с помощью которой пользователю можно было бы выбирать метод интегрирования, подобно программе
выбора метода решения уравнений.
2. Вычислите по формуле Симпсона следующие интегралы:
Pi / 2
1
1) полный эллиптический интеграл 2-го рода  1  sin2 xdx ,
2
0
1
2)
e
0
x 2
1
dx ,
3)
arctgx
dx.
x
0

3.6. Вычисление интегралов методом Монте-Карло
Вычисление интегралов методом Монте-Карло часто применяется для двойных,
тройных, вообще, кратных интегралов. Идея метода состоит в следующем.
Пусть задана некоторая подынтегральная функция F - непрерывная в области интегрирования Q. Выберем в этой области n случайных точек M, найдем значение заданной
функции в некоторой "средней" точке области интегрирования. При достаточно большом
n можно считать, что
1 n
Ycp   F ( Mi ).
n i 1
Тогда, значение интеграла приблизительно равно I  Y ср D, где D - многомерный
объем области интегрирования.
Применим этот метод для простейшего интеграла на промежутке [a, b], т.е. необходимо вычислить интеграл:
b
I   f (x )dx.
a
В этом случае в качестве объема области интегрирования D выступает длина отрезка
[a, b], которая равна: D = b - a.
Пусть xi (i = 1, 2, ..., n) - случайные точки из промежутка [a, b], тогда значение функции f(x) в некоторой "средней" точке будет:
1 n
Ycp   f (xi )
n i 1
а значение интеграла станет равно
ba n
I
 f (xi )
n i 1
366 
Для получение точек xi можно использовать уже известный способ нахождения случайных точек с помощью функции random,
x := random*(b - a) + a
Функция для вычисления интеграла получится такой:
{ Функция вычисления интеграла методом Монте-Карло }
Function I(n : longint; a, b : real) : real;
var
x, f : real;
k : longint;
begin
randomize;
f := 0;
for k := 1 to n do
begin
x := random*(b - a) + a;
f := f + fx(x)
end;
I := (b - a)*f/n
end;
Итак, с помощью генератора случайных чисел (random) вырабатывается случайное
число из промежутка [a, b], находится значение функции в этой точке и суммируются ее
абсолютные величины (учитывая, что функция может принимать и отрицательные значения) в переменную f. Приближенное значение интеграла вычисляется с помощью оператора I := (b - a)*f/n.
Теперь стоит очень болезненный вопрос оценки точности значения интеграла. Не
вдаваясь в долгие математические рассуждения (о чем смотрите [19]), покажем неравенства, с помощью которых можно оценить точность вычисления интеграла.
Пусть I(f) - точное значение интеграла, а Sn(f) - его приближенное значение, тогда с
вероятностью 0,997 и 0,99999 выполняются следующие соотношения
D( f )
D( f )
и | Sn ( f )  I ( f )| 5
| Sn ( f )  I ( f )| 3
n
n
Здесь D(f) - дисперсия непрерывной случайной величины, которая вычисляется по
формуле:
1 n
D( f ) 
 (sj ( f )  Sn ( f ))2 ,
n  1 j 1
где сумма есть математическое ожидание случайной величины.
Приведем схему последовательного вычисления интеграла с заданной точностью
eps. Последовательно, при n = 1, ... получаются случайные точки x и вычисляющая величины tn , Sn , dn , пользуясь рекуррентными соотношениями
tn  tn 1  In (x)
t
Sn  n
n
n
dn  dn 1 
(In (x )  Sn )2
n 1
d
Dn  n
n 1
367

и величину 3
D( f )
D( f )
или 5
.
n
n
Начальные условия рекурсии n = 1, t1  I1 (x), S1  t1 , d1  D1  0.
D( f )
D( f )
<= eps или 5
. <=eps, то вычисления прекращаn
n
ются и полагают, что приближенное значение интеграла равно S n с вероятностью 0,997
или 0,99999 и точностью eps.
Изложенные математические соображения можно реализовать следующей процедурой:
Если оказалось, что 3
{ Процедура оценки точности и вычисления интеграла }
Procedure Monte_Karlo(a, b, eps : real; var s : real);
var
t, d, f, dd : real;
n
: longint;
begin
n := 1;
t := I(n, a, b);
s := t;
d :=0;
repeat
n := n + 1;
t := t + I(n, a, b);
s := t/n;
d := d + (n/(n - 1))*sqr(I(n, a, b) - s);
dd := d/(n - 1)
until 5*sqrt(dd/n) < eps
end;
Полностью программа приводится ниже. Надо заметить, что для интегралов на промежутке программа работает медленно и лучше применять для их вычисления другие методы, а вот для кратных интегралов программа может быть очень полезной.
{Вычисление интеграла и оценка его точности методом Монте-Карло}
Program Integral_Monte_Karlo;
uses WinCrt;
var
a, b, s, eps : real;
{-----------------------------------------------------------------------------------------}
Function fx(x : real) : real; { Промежуток интегрир. [3, 4] }
begin
{ Интеграл хорошо вычисл. с точн. до 0.00001 }
fx := sin(0.2*x - 3)/(x*x + 1)
end;
{-----------------------------------------------------------------------------------------}
Function t(eps : real) : integer;
var
k : integer;
begin
k := -1;
repeat
368 
eps := eps*10;
k := k + 1
until eps > 1;
t := k
end;
{----------------------------------------------------------------------------------------}
{ Функция вычисления интеграла методом Монте-Карло }
Function I(n : longint; a, b : real) : real;
var
x, f : real;
k : longint;
begin
randomize;
f := 0;
for k := 1 to n do
begin
x := random*(b - a) + a;
f := f + fx(x)
end;
I := (b - a)*f/n
end;
{----------------------------------------------------------------------------------------}
{ Процедура вычисления точности и интеграла }
Procedure Monte_Karlo(a, b, eps : real; var s : real);
var
t, d, f, dd : real;
n
: longint;
begin
n := 1;
t := I(n, a, b);
s := t;
d :=0;
repeat
n := n + 1;
t := t + I(n, a, b);
s := t/n;
d := d + (n/(n - 1))*sqr(I(n, a, b) - s);
dd := d/(n - 1)
until 5*sqrt(dd/n) < eps
end;
{----------------------------------------------------------------------------------------}
{ Основная программа }
begin
randomize;
write('Введите нижний предел интегрирования '); readln(a);
write('Введите верхний предел интегрирования '); readln(b);
write('Введите точность вычисления '); readln(eps);
Monte_Karlo(a, b, eps, s);
writeln('Значение интеграла равно ', s:6:t(eps));
write('С точностью до ', eps:1:t(eps));
writeln(' и вероятностью 0.99999')
end.
369

Задание 6
Используя второй способ оценки погрешности через разность результатов приближенного значения интеграла при различных значениях аргументов, изменить программу
вычисления интеграла по методу Монте-Карло. И вычислить с ее помощью интегралы из
задания 5.
3.7. Вычисление двойных интегралов методом Монте-Карло
Вначале сделаем отступление в курс математического анализа и познакомимся с понятием двойного интеграла. Как и прежде, в определении понятий математического анализа, мы будем следовать Г.М. Фихтенгольцу.
Возникновение двойного (определенного) интеграла связывают с задачей определения объема цилиндрического бруса, подобно тому, как определенный интеграл возник из
задачи определения площади криволинейной трапеции.
Рассмотрим тело (V), которое сверху ограничено поверхностью z = f(x, y), с боков цилиндрической поверхностью с образующими, параллельными оси z, наконец, снизу плоской фигурой (P) на плоскости xy. Требуется найти объем V тела.
Для решения этой задачи мы прибегаем к обычному в интегральном исчислении
приему, состоящему в разложении искомой величины на элементарные части, приближенному подсчету каждой части, суммированию и последующему предельному переходу.
С этой целью разложим область (P) сетью кривых на части (P1), (P2), ..., (Pn) и рассмотрим
ряд цилиндрических столбиков, которые имеют своими основаниями эти частичные области и в совокупности составляют данное тело.
Для подсчета объема отдельных столбиков возьмем произвольно в каждой фигуре
(Pi) по точке (xi, yi). Если приближенно принять каждый столбик, за настоящий цилиндр с
высотой, равной аппликате f(xi, yi), то объем отдельного столбика оказывается приближенно равным f(xi, yi)*Pi, где Pi означает площадь фигуры (Pi). В таком случае приблиn
женное выражение объема всего тела будет V   f ( x i , y i ) Pi .
i 1
Для повышения точности этого равенства будем уменьшать размеры площадок (Pi),
увеличивая их число. В пределе, при стремлении к нулю наибольшего из диаметров всех
n
областей (Pi), это равенство делается точным, так что V  lim  f (xi , yi ) Pi .
i 1
и поставленная задача решена.
Предел этого вида и есть двойной интеграл от функции f(x, y) по области (P); он обозначается символом  f (x , y )dP так что формула для объема принимает вид
( P)
V   f ( x , y)dP
(P )
Таким образом, двойной интеграл является прямым обобщением понятия простого
определенного интеграла на случай функции двух переменных.
Пример 1. Вычислить интеграл, распространенный на прямоугольник
(P) = [3, 4; 1, 2]:
2 4
dxdy
dxdy

.
2
2



(
x

y
)
(
x

y
)
( P)
1 3
370 
Решить этот интеграл методом Монте-Карло очень просто. Для этого достаточно изменить функцию:
Function fx(x, y : real) : real;
begin
fx := 5*x*x*y - 2*y*y*y
end;
Изменить функцию вычисления интеграла, куда добавить в качестве входных параметров две другие координаты прямоугольной области по оси OY и в результате вычисления умножать среднее значение функции, не на длину отрезка, а на площадь области, в
данном случае, на площадь прямоугольника. Разумеется, задавать случайные значения для
y из соответствующего промежутка [a1, b1].
Функция станет такой:
{ Функция вычисления интеграла методом Монте-Карло }
Function I(n : longint; a, b, a1, b1 : real) : real;
var
x, y, f : real;
k
: longint;
begin
randomize;
f := 0;
for k := 1 to n do
begin
y := random*(b1 - a1) + a1;
x := random*(b - a) + a;
f := f + fx(x, y)
end;
I := (b - a)*(b1 - a1)*f/n
end;
Необходимо внести незначительные изменения в процедуру Monte_Karlo, а в основной программа, не забыть описать новые переменный и ввести их в программу.
Составьте программу самостоятельно и выполните ее.
Задание 7
Вычислить двойной интеграл
I
 y
2
R 2  x 2 dP ,
( P)
где (P) есть круг радиуса R с центром в начале координат.
371

Библиотека часто встречающихся процедур и функций
43. Процедура уточнения корня методом хорд.
{ Процедура уточнения корня методом хорд }
Procedure chord(a, b, eps, min : real; var x : real);
var
x1 : real;
begin
x1 := a;
repeat
x := x1 - ((b - x1)*fx(x1))/(fx(b) - fx(x1));
x1 := x
until abs(fx(x))/min < eps
end;
44. Функция вычисления первой производной.
{ Вычисление 1-й производной и опред. точности ее вычислен.}
{ derivative - производная }
Function derivat1(x0, eps : real) : real;
var
dx, dy, dy2 : real;
begin
dx := 1;
repeat
dx := dx/2;
dy := fx(x0 + dx/2) - fx(x0 - dx/2);
dy2 := fx(5*x0/4 + dx) - 2*fx(5*x0/4);
dy2 := dy2 + fx(5*x0/4 - dx)
until abs(dy2/(2*dx)) < eps;
derivat1 := dy/dx
end;
45. Процедура определения наименьшего значения первой производной.
{ Процедура определения наименьшего значения производной }
{ на заданном промежутке }
Procedure minimum(a, b, eps : real; var min : real);
var
d : real;
begin
a := a - eps;
b := b + eps;
repeat
a := a + eps;
b := b - eps;
min := abs(derivat1(a, eps));
d := abs(derivat1(b, eps));
if min > d then min := d
until min <> 0
end;
372 
46. Функция вычисления порядка, в зависимости от задаваемой точности.
{ Функция вычисления порядка - кол-во знаков после запятой }
Function t(eps : real) : integer;
var
k : integer;
begin
k := -1;
repeat
eps := eps*10;
k := k + 1
until eps > 1;
t := k
end;
47. Процедура уточнения корня методом касательных.
{ Процедура уточнения корня методом касательных }
Procedure tangent(a, b, eps, min, dy : real; var x : real);
var
x1 : real;
begin
x1 := a;
repeat
x := x1 - fx(x1)/derivat1(x1);
x1 := x
until abs(fx(x))/min < eps
end;
48. Функция вычисления второй производной.
{ Функция вычисления второй производной }
Function derivat2(x0, eps : real) : real;
var
dx, dy, dy3 : real;
begin
dx := 1;
repeat
dx := dx/2;
dy := fx(x0 + dx) - 2*fx(x0) + fx(x0 - dx);
dy3 := fx(5*x0/4 + 2*dx) - 2*fx(5*x0/4 + dx);
dy3 := dy3 - fx(5*x0/4 - 2*dx) + 2*fx(5*x0/4 - dx)
until abs(dy3/(6*dx)) < eps;
derivat2 := dy/(dx*dx)
end;
49. Процедура вычисления корня уравнения (комбинированный метод).
{ Комбинированный метод }
Procedure Combination(a, b, eps : real; var x : real);
var
z : real;
373

begin
repeat
if fx(a)*derivat2(a, eps) > 0
then
begin
tangent(a, b, eps, z);
chord(b, a, x);
b := z; a := x
end
else
begin
tangent(b, a, eps, z);
chord(a, b, x);
b := x; a := z
end
until abs(z - x) < eps
end;
50. Процедура определения числа точек деления промежутка в зависимости от вычисляемой точности.
{ Процедура определения числа точек деления промежутка интегр. }
Procedure Number(a, b, eps : real; var n : integer);
var
dy2, d, c, dx : real;
begin
c := (a + b)/2;
dy2 := derivat2(c, eps);
if dy2 = 0
then
begin
c := a; dx := (b - a)/10;
while derivat2(c, eps) = 0 do c := c + dx;
dy2 := derivat2(c, eps)
end;
n := 1;
d := abs((b - a)*(b - a)*(b - a));
while abs(dy2*d)/(24*n*n) >= eps do n := n+1;
end;
{--------------------------------------------------------------}
{ Вычисление интеграла методом прямоугольников }
Procedure Rectangle(a, b : real; n : integer; var j : real);
var
dx, c, f : real; i : integer;
begin
dx := (b - a)/n; c := a + dx/2;
f := fx(c);
for i := 1 to n - 1 do
begin
c := c + dx;
f := f + fx(c)
end;
374 
j := dx * f
end;
51. Процедура вычисления интеграла по формуле прямоугольников.
{ Вычисление интеграла методом прямоугольников }
{ Rectangle - прямоугольник }
Procedure Rectangle(a, b : real; n : integer; var j : real);
var
dx, c, f : real;
i
: integer;
begin
dx := (b - a)/n;
c := a + dx/2;
f := fx(c);
for i := 1 to n - 1 do
begin
c := c + dx;
f := f + fx(c)
end;
j := dx * f
end;
52. Процедура вычисления интеграла по формуле трапеций.
{ Вычисл. интеграла по формуле трапеций. Trapezoid - трапеция }
Procedure Trapezoid(a, b : real; n : integer; var j : real);
var
dx, c, f : real;
i
: integer;
begin
dx := (b - a)/n; c := a;
f := (fx(a)) + fx(b))/2;
for i := 1 to n - 1 do
begin
c := c + dx;
f := f + fx(c)
end;
j := dx * f
end;
53. Процедура вычисления интеграла по формуле Симпсона.
Procedure Simpson(a, b : real; n : integer; var j : real);
var
dx, c, c1, f : real;
i
: integer;
begin
dx := (b - a)/n;
c := a;
c1 := a + dx/2;
f := fx(a) + fx(b) + 4*fx(c1);
375

for i := 1 to n - 1 do
begin
c := c + dx; c1 := c1 + dx;
f := f + 2*fx(c) + 4*fx(c1)
end;
j := (dx/6)* f
end;
54. Процедуры вычисления интеграла по методу Монте-Карло.
Function I(n : longint; a, b : real) : real;
var
x, f : real; k : longint;
begin
randomize;
f := 0;
for k := 1 to n do
begin
x := random*(b - a) + a;
f := f + fx(x)
end;
I := (b - a)*f/n
end;
{----------------------------------------------------------------------------------------}
Procedure Monte_Karlo(a, b, eps : real; var s : real);
var
t, d, f, dd : real; n : longint;
begin
n := 1;
t := I(n, a, b);
s := t;
d :=0;
repeat
n := n + 1;
t := t + I(n, a, b);
s := t/n;
d := d + (n/(n - 1))*sqr(I(n, a, b) - s);
dd := d/(n - 1)
until 5*sqrt(dd/n) < eps
end;
Упражнения
184. Вычислить значение дифференциала функции y 
1
при изменении не( tgx  1) 2
зависимой переменной от Pi/6 до 61Pi/360.
185. y  31/ x  21/ 2 x  6 x . Вычислить dy при x = 1 и dx = 0.2.
186. Доказать, что функция y = ex sinx удовлетворяет соотношению y' '2y'2y  0, а
функция y = e-x sinx соотношению y' '2y'2y  0. (В качестве x0 взять произвольное значение x из области определения функции).
187. Решите уравнения, выбирая подходящий метод решения:
x3 - 9x + 2 = 0, xeч = 2, x = 0.538sinx + 1, aч = ax при a > 1, x2 arctgx = a, где a  0.
376 
188. Решить уравнение
x
x
dx


x
,

dx
.
x  1 12 ln 2 ex  1
189. Пользуясь правилами прямоугольника, трапеции и правилом Симпсона, вычислить приближенно число  . Полученные результаты сравнивать между собой и значением  с заданной точностью.
1
dx

0 1  x 2  2 .
2
2
10
dx
, используя правило Симпсона.
x
1
Найти модуль перехода от натурального логарифма к десятичному.
191. Вычислить по формуле Симпсона или методом Монте-Карло.
1
1
5
 /3
 /3
dx
sin x
4
3
0 1  x dx , 0 1  x dx , 2 ln x , 2 cos xdx , 0 x dx.
192. В следующих задачах при нахождении пределов интегрирования необходимо
воспользоваться методами приближенного решения уравнений.
а) Найти площадь фигуры, ограниченной дугами парабол y = x3- 7 и
y = - 2x2+ 3x и осью ординат.
б) Найти площадь фигуры, ограниченной параболой y = x3 и прямой
y = 7(x + 1).
в) Найти площадь фигуры, ограниченной параболой y=16 - x3 и полукубической параболой y = 3 x .
193. Вычислить двойной интеграл по методу Монте-Карло:
K   (x 2  y )dxdy ,
190. Вычислить ln10 

( A)
если область (A) ограничена двумя параболами: y = x2 и y2 = x.
Ответы
К заданию 1
Program derivative2;
uses WinCrt;
var
x0, eps, dx, dy, dy3 : real;
Function fx(x : real) : real;
begin
fx := x*x*x*x
end;
{----------------------------------------------------------------------------------------}
{ Функция вычисления порядка - кол-во знаков после запятой }
Function t(eps : real) : integer;
var
k : integer;
begin
k := -1;
repeat
eps := eps*10;
k := k + 1
377

until eps > 1;
t := k
end;
{----------------------------------------------------------------------------------------}
{ Функция вычисления второй производной }
Function derivat2(x0, eps : real) : real;
var
dx, dy, dy3 : real;
begin
dx := 1;
repeat
dx := dx/2;
dy := fx(x0 + dx) - 2*fx(x0) + fx(x0 - dx);
dy3 := fx(5*x0/4 + 2*dx) - 2*fx(5*x0/4 + dx);
dy3 := dy3 - fx(5*x0/4 - 2*dx) + 2*fx(5*x0/4 - dx)
until abs(dy3/(6*dx)) < eps;
derivat2 := dy/(dx*dx)
end;
{----------------------------------------------------------------------------------------}
{ Основная программа }
begin
write('Введите точку, в которой находится ');
write('вторая производная '); readln(x0);
write('Введите точность вычисления второй производной ');
readln(eps);
dy := derivat2(x0, eps);
write('Вторая производная функции в точке ', x0:6:t(eps));
writeln(' равна ', dy:6:t(eps));
writeln('с точностью до ', eps:1:t(eps))
end.
К заданию 3
{ Выбор метода решения уравнений: метод хорд, метод касательн. }
{ комбинированный метод }
Program Case_method;
uses WinCrt;
var
a, b, x, eps : real;
k
: integer;
{----------------------------------------------------------------------------------------}
{ Заданная функция }
Function fx(x : real) : real;
begin
fx := x*sin(x) - 0.5
end;
{----------------------------------------------------------------------------------------}
{ Функция вычисления порядка - кол-во знаков после запятой }
Function t(eps : real) : integer;
var
k : integer;
begin
k := -1;
repeat
378 
eps := eps*10;
k := k + 1
until eps > 1;
t := k
end;
{----------------------------------------------------------------------------------------}
{ Вычисление 1-й производной }
Function derivat1(x0, eps : real) : real;
var
dx, dy, dy2 : real;
begin
dx := 1;
repeat
dx := dx/2;
dy := fx(x0 + dx/2) - fx(x0 - dx/2);
dy2 := fx(5*x0/4 + dx) - 2*fx(5*x0/4);
dy2 := dy2 + fx(5*x0/4 - dx)
until abs((dy2*dy2*fx(x0))/(2*dx)) < eps;
derivat1 := dy/dx
end;
{----------------------------------------------------------------------------------------}
{ Вычисление 2-й производной }
Function derivat2(x0, eps : real) : real;
var
dx, dy, dy3 : real;
begin
dx := 1;
repeat
dx := dx/2;
dy := fx(x0 + dx) - 2*fx(x0) + fx(x0 - dx);
dy3 := fx(5*x0/4 + 2*dx) - 2*fx(5*x0/4 + dx);
dy3 := dy3 - fx(5*x0/4 - 2*dx) + 2*fx(5*x0/4 - dx)
until abs(dy3/(6*dx)) < eps;
derivat2 := dy/(dx*dx)
end;
{----------------------------------------------------------------------------------------}
{ Процедура определения наименьшего значения производной }
{ на заданном промежутке }
Procedure minimum(a, b, eps : real; var min : real);
var
d : real;
begin
a := a - eps;
b := b + eps;
repeat
a := a + eps;
b := b - eps;
min := abs(derivat1(a, eps));
d := abs(derivat1(b, eps));
if min > d then min := d
until min <> 0
end;
379

{----------------------------------------------------------------------------------------}
{ Процедура уточнения корня методом хорд }
Procedure chord1(a, b, eps : real; var x : real);
var
x1, min : real;
begin
minimum(a, b, eps, min);
x1 := a;
repeat
x := x1 - ((b - x1)*fx(x1))/(fx(b) - fx(x1));
x1 := x
until abs(fx(x))/min < eps
end;
{----------------------------------------------------------------------------------------}
{ Процедура уточнения корня методом касательных }
Procedure tangent1(a, b, eps, min : real; var x : real);
var
x1 : real;
begin
x1 := a;
repeat
x := x1 - fx(x1)/derivat1(x1, eps);
x1 := x
until abs(fx(x))/min < eps
end;
{----------------------------------------------------------------------------------------}
Procedure Tangent2(a, b, eps : real; var x : real);
var
min : real;
begin
minimum(a, b, eps, min);
if fx(a)*derivat2(a, eps) > 0
then tangent1(a, b, eps, min, x)
else tangent1(b, a, eps, min, x)
end;
{----------------------------------------------------------------------------------------}
{ Процедура уточнения корня методом хорд }
Procedure chord(a, b : real; var x : real);
begin
x := a - ((b - a)*fx(a))/(fx(b) - fx(a))
end;
{----------------------------------------------------------------------------------------}
{ Процедура уточнения корня методом касательных }
Procedure tangent(a, b, eps : real; var z : real);
begin
z := a - fx(a)/derivat1(a, eps)
end;
{----------------------------------------------------------------------------------------}
{ Комбинированный метод }
Procedure Combination(a, b, eps : real; var x : real);
var
z : real;
380 
begin
repeat
if fx(a)*derivat2(a, eps) > 0
then
begin
tangent(a, b, eps, z);
chord(b, a, x);
b := z; a := x
end
else
begin
tangent(b, a, eps, z);
chord(a, b, x);
b := x; a := z
end
until abs(z - x) < eps
end;
{----------------------------------------------------------------------------------------}
{ Основная программа }
begin
write('Введите левый конец промежутка a = '); readln(a);
write('Введите правый конец промежутка b = '); readln(b);
write('Введите точность вычисления корня eps = ');
readln(eps);
writeln('Для выбора метода решения, введите его номер ');
writeln('1 - метод хорд, 2 - метод касательных');
writeln(' 3 - комбинированный метод'); readln(k);
Case k of
1 : chord1(a, b, eps, x);
2 : Tangent2(a, b, eps, x);
3 : Combination(a, b, eps, x)
end;
writeln('Корень уравнения равен x = ', x:6:t(eps));
writeln('С точностью до eps = ', eps:1:t(eps))
end.
К заданию 4
{ Вычисление интеграла по формуле трапеций }
Program integral_trapezoid;
uses WinCrt;
var
a, b, eps, j : real;
n
: integer;
Function fx(x : real) : real;
begin
fx := 1/x
end;
{----------------------------------------------------------------------------------------}
{ Функция вычисления порядка - кол-во знаков после запятой }
Function t(eps : real) : integer;
var
k : integer;
381

begin
k := -1;
repeat
eps := eps*10;
k := k + 1
until eps > 1;
t := k
end;
{----------------------------------------------------------------------------------------}
{ Функция вычисления второй производной }
Function derivat2(x0, eps : real) : real;
var
dx, dy, dy3 : real;
begin
dx := 1;
repeat
dx := dx/2;
dy := fx(x0 + dx) - 2*fx(x0) + fx(x0 - dx);
dy3 := fx(5*x0/4 + 2*dx) - 2*fx(5*x0/4 + dx);
dy3 := dy3 - fx(5*x0/4 - 2*dx) + 2*fx(5*x0/4 - dx)
until abs(dy3/(6*dx)) < eps;
derivat2 := dy/(dx*dx)
end;
{----------------------------------------------------------------------------------------}
{ Процедура определения числа точек деления промежутка интегр. }
Procedure Number(a, b, eps : real; var n : integer);
var
dy2, d, c, dx : real;
begin
c := (a + b)/2;
dy2 := derivat2(c, eps);
dx := (b - a)/10;
if dy2 = 0
then
begin
c := a;
while derivat2(c, eps) = 0 do c := c + dx;
dy2 := derivat2(c, eps)
end;
n := 1;
d := abs((b - a)*(b - a)*(b - a));
while abs(dy2*d)/(12*n*n) >= eps do n := n+1;
end;
{----------------------------------------------------------------------------------------}
{ Вычисл. интеграла по формуле трапеций. Trapezoid - трапеция }
Procedure Trapezoid(a, b : real; n : integer; var j : real);
var
dx, c, f : real;
i
: integer;
begin
dx := (b - a)/n;
c := a;
382 
f := (fx(a) + fx(b))/2;
for i := 1 to n - 1 do
begin
c := c + dx;
f := f + fx(c)
end;
j := dx * f
end;
{----------------------------------------------------------------------------------------}
begin
write('Введите нижний предел интегрирования '); readln(a);
write('Введите верхний предел интегрирования '); readln(b);
write('Введите точность вычисления интеграла ');
readln(eps);
Number(a, b, eps, n);
Trapezoid(a, b, n, j);
writeln('Значение интеграла равно ', j:6:t(eps));
writeln('С точностью до ', eps:1:t(eps))
end.
2-й способ
{ Вычисление интеграла по формуле трапеций }
Program integral_trapezoid;
uses WinCrt;
var
a, b, eps, max, j : real;
n
: integer;
Function fx(x : real) : real;
begin
fx := 1/x
end;
{----------------------------------------------------------------------------------------}
{ Функция вычисления порядка - кол-во знаков после запятой }
Function t(eps : real) : integer;
var
k : integer;
begin
k := -1;
repeat
eps := eps*10;
k := k + 1
until eps > 1;
t := k
end;
{----------------------------------------------------------------------------------------}
{ Функция вычисления второй производной }
Function derivat2(x0, eps : real) : real;
var
dx, dy, dy3 : real;
begin
dx := 1;
383

repeat
dx := dx/2;
dy := fx(x0 + dx) - 2*fx(x0) + fx(x0 - dx);
dy3 := fx(5*x0/4 + 2*dx) - 2*fx(5*x0/4 + dx);
dy3 := dy3 - fx(5*x0/4 - 2*dx) + 2*fx(5*x0/4 - dx)
until abs(dy3/(6*dx)) < eps;
derivat2 := dy/(dx*dx)
end;
{----------------------------------------------------------------------------------------}
{ Определение наибольшего значения второй производной }
Procedure Maximum(a, b, eps : real; var max : real);
var
dx, x : real;
begin
dx := 0.1; x := a;
max := abs(derivat2(x, eps));
while x<= b do
begin
x := x + dx;
if max < abs(derivat2(x, eps))
then max := abs(derivat2(x, eps))
end
end;
{----------------------------------------------------------------------------------------}
{ Процедура определения числа точек деления промежутка интегр. }
Procedure Number(a, b, eps, max : real; var n : integer);
var
d : real;
begin
n := 1;
d := abs((b - a)*(b - a)*(b - a));
while (max*d)/(24*n*n) >= eps do n := n+1;
end;
{----------------------------------------------------------------------------------------}
{ Вычисл. интеграла по формуле трапеций. Trapezoid - трапеция }
Procedure Trapezoid(a, b : real; n : integer; var j : real);
var
dx, c, f : real;
i
: integer;
begin
dx := (b - a)/n;
c := a;
f := (fx(a) + fx(b))/2;
for i := 1 to n - 1 do
begin
c := c + dx;
f := f + fx(c)
end;
j := dx * f
end;
{----------------------------------------------------------------------------------------}
{ Основная программа }
384 
begin
write('Введите нижний предел интегрирования '); readln(a);
write('Введите верхний предел интегрирования '); readln(b);
write('Введите точность вычисления интеграла '); readln(eps);
Maximum(a, b, eps, max); Number(a, b, eps, max, n);
Trapezoid(a, b, n, j);
writeln('Значение интеграла равно ', j:6:t(eps));
writeln('С точностью до ', eps:1:t(eps))
end.
К заданию 6
{ Вычисление интеграла методом Монте-Карло }
Program integral_Monte_Karlo;
uses WinCrt;
var
a, b, eps : real;
n
: longint;
{----------------------------------------------------------------------------------------}
Function fx(x : real) : real; { Промежуток интегрир. [3, 4] }
begin
{ Интеграл хорошо вычисл. с точн. до 0.00001 }
fx := sin(0.2*x - 3)/(x*x + 1)
end;
{----------------------------------------------------------------------------------------}
{ Функция вычисления порядка - кол-во знаков после запятой }
Function t(eps : real) : integer;
var
k : integer;
begin
k := -1;
repeat
eps := eps*10;
k := k + 1
until eps > 1;
t := k
end;
{----------------------------------------------------------------------------------------}
{ Функция вычисления интеграла методом Монте-Карло }
Function I(n : longint; a, b : real) : real;
var
x, f : real;
k : longint;
begin
randomize;
f := 0;
for k := 1 to n do
begin
x := random*(b - a) + a;
f := f + fx(x)
end;
I := (b - a)*f/n
end;
{----------------------------------------------------------------------------------------}
385

{ Основная программа }
begin
write('Введите нижний предел интегрирования '); readln(a);
write('Введите верхний предел интегрирования '); readln(b);
write('Введите точность вычисления '); readln(eps);
n := 10;
repeat
n := 2*n
until abs(I(n, a, b) - I(2*n, a, b)) <= eps;
writeln('Значение интеграла равно ', I(2*n, a, b):6:t(eps));
writeln('С точностью до ', eps:1:t(eps));
end.
386 
Глава 12. Числовые и функциональные ряды
Снова сделаем небольшую экскурсию в математику и познакомимся с числовыми и
функциональными рядами.
Определение. Пусть задана некоторая бесконечная последовательность чисел
a1 , a 2 , a3 , ..., a n , ... (1)
Составленный из этих чисел символ или сумма
a1  a2  a3 ...an ...
(2)
называется бесконечным рядом, а сами числа - членами ряда.
Вместо записи (2), пользуясь знаком суммы, можно записать так:

a
n
,
где знак

- сумма,  - бесконечность; указатель n пробегает значения
n 1
от 1 до 
Примеры числовых рядов.
1. Простейшим примером бесконечного ряда является геометрическая прогрессия:
a  aq  aq2 ... aq n ...
1
1
1
1


... 
...
2.
25 36 4 7
( n  1)  ( n  4)
3. Следующий ряд называется гармоническим:

1 1
1
 1   ...( 1) n1
...
4
3 5
2n  1
4. Ряды могут быть не только с положительными членами, но и знакопеременными.
Вот простейшие примеры таких рядов:
1 1
1
a) 1   ... (1) n 1 ...
2 3
n
1 1 1 1 1 1 1 1
б) 1         ...
1! 2! 3! 4! 5! 6! 7! 8!
3
1 8
n 1 n
...
в)  ... (1)
2 4
2n
n


(1) n
n 1 2
г) 
.
, д)  (1)
n!
n 1
n  1 n ln n
1. Функциональные ряды
Функциональным рядом
называется выражение u1 (x )  u2 (x )  u3 (x )...un (x )..., где u1 (x ), u2 (x ), ... (члены
ряда) - суть функции одного и того же аргумента x, определенные в некотором промежутке (a, b).
Примеры функциональных рядов.
1). 1  x  1  2  x 2  1  2  3  x 3 ...  n ! x n ...
387

x2 x3
xn


...

...
22 32
n2
x
x2
x3
xn
3).


... 
...
1 2 2  3 3  4
n  ( n  1)
2). x 
Функции можно разложить в ряды
1. Показательная функция:
x x2 x3
xn
  ... ...
1! 2! 3!
n!
на множестве всех действительных чисел R, т. е. на промежутке от   до   .
ex  1 
2. Тригонометрические функции.
sin x 
x x 3 x5 x 7
x 2 n 1
   ... (1) n 1
...
1! 3! 5! 7!
(2n  1)!
на множестве всех действительных чисел R.
cos x  1 
x2 x4 x6
x2n
  ... (1) n
...
2! 4! 6!
(2n)!
на множестве R.
2 n 1
x 3 x5
n 1 x
arctgx  x   ... (1)
...
3 5
2n  1
на промежутке [-1, 1].
Из этого ряда при x = 1 получается знаменитый ряд Лейбница

1 1
1
 ...(1) n1
...
4
3 5
2n  1
- первый ряд, дающий разложение числа  .
Для вычисления числа  есть еще много других рядов. Вот некоторые из них, которые дают более быстрое приближение к числу  :
2 1 1
1
1
 2  2  2 ...
...;
a)
8 1
3
5
(2n  1) 2
1
б) ряд Леонардо Эйлера:
2
6
1
3. Логарифмическая функция
1
1
1
1
2  2 
2 ...  2 ...;
2
3
4
n
n
x x2 x3
n 1 x
ln(1  x )    ... (1)
...
1 2
3
n
на промежутке (-1, 1).
4. Разложение бинома в ряд или биномиальный ряд:
(1  x )m  1  mx 
m(m  1) 2
m(m  1)...(m  n  1) n
x ...
x ...
2!
n!
на промежутке (-1, 1), где m - любое вещественное число, отличное от 0 и от всех натуральных чисел (при натуральном m получается известное разложение по формуле Ньютона - бином Ньютона).
Вы уже знакомы с последовательностями, которые задавались формулами n-го члена
этих рядов и находили члены этих последовательностей. Это обстоятельство упростит нам
процесс составления программ суммирования рядов.
388 
Совершенно ясно, что с помощью этих рядов можно вычислять значения соответствующих функций.
Возникает следующий вопрос. Как оценить точность, с которой надо найти значение
функции?
Математика также дает на этот вопрос ответ.
Пусть требуется вычислить значение функции ex с точностью до eps, где eps любое
положительное число (в частности, eps может быть равно 0,1, 0,01, 0,001, 0,0001 и т.д.).
Для вычисления ex с заданной степенью точности eps необходимо n членов ряда, тогда можно записать, что приблизительно
ex  1 
x x2 x3
xn
  ... ...
1! 2! 3!
n!
Оставшиеся члены ряда можно обозначить rn(x) и назвать остатком ряда или остаточным членом, или дополнительным членом.
Чему равен этот остаточный член? Совершенно очевидно, что он по абсолютной величине будет меньше или равен заданной точности вычисления, т.е. числу eps,
rn (x )  eps. Поэтому по абсолютной величине остатка rn(x) можно определять точность
вычисления ex с помощью данного ряда.
Можно записать, что
x x2 x3
xn
  ...  rn (x ).
1! 2! 3!
n!
Математика дает несколько формул дополнительного члена различных рядов. Для
этого ряда дополнительный член может быть
ex
x n 1 , где  зависит от n и находится в промезаписан в следующем виде: rn ( x ) 
(n  1)!
жутке (0, 1), 0 <  < 1.
При x>0 погрешность по этой формуле оценивается так:
x n 1
x
| rn (x )| e
(n  1)!
В частности, при x = 1,
1 1
1
3
e  1   ...  rn (1), где | rn (1)|
.
( n  1)!
1! 2!
n!
Подумайте, почему в числителе дроби дополнительного члена оказалось число 3?
С помощью этой формулы можно с большой степенью точности вычислить число e.
ex  1 
Пример 1. Составим программу вычисления числа e по этой формуле.
Прежде найдем рекуррентную формулу, связывающую предыдущий и последующий
члены ряда.
1
un
n!  ( n  1)!  1 , отсюда получим,

Это сделать нетрудно:
1
un1
n!
n
( n  1)!
un  un1 
1 un1

.
n
n
389

Алгоритм
1. Начало.
2. Установить переменные и их типы.
Переменная n будет участвовать в получении членов ряда и должна иметь целый тип
(integer).
Переменная eps задает точность, с которой подсчитывается сумма ряда, т.е. значение
числа e. Она имеет вещественный тип.
Нужна переменная, в которую будут последовательно заноситься члены ряда. Эту
переменную обозначим u. Она будет иметь вещественный тип.
И, наконец, переменная e - результат вычисления, т.е. сумма ряда имеет вещественный тип.
3. Основная программа, в которой вычисляется сумма членов ряда.
1). Ввод пользователем точности, с которой должно быть вычислено значение e. Оно
присваивается переменной eps.
2). Для вычисления суммы ряда организуем цикл с последующим условием. Перед
началом цикла установим переменным n и u первоначальные значения, которые равны 1, а
переменной e - значение 0 (ведь в переменной e будет накапливаться сумма членов ряда).
3). В цикле подсчитывается сумма, "вырабатывается" следующий член ряда и увеличивается значение n на единицу.
4). Условие в конце цикла должно связывать заданную точность вычисления - eps и
3
. Подумайте, как оно должно быть записано?
остаток ряда
(n  1)!
5). Вывод информации.
4. Конец.
Программа
Program Problem1; {Вычисление числа e}
uses WinCrt;
var
n
: integer;
e, u, z, eps : real;
{----------------------------------------------------------------------------------------}
{ Функция вычисления порядка - кол-во знаков после запятой }
Function t(eps : real) : integer;
var
k : integer;
begin
k := -1;
repeat
eps := eps*10;
k := k + 1
until eps > 1;
t := k
end;
{----------------------------------------------------------------------------------------}
begin
write('Задайте точность вычисления '); readln(eps);
e := 0; u := 1; n := 1;
repeat
e := e+u;
u := u/n; n := n+1
390 
until 3*u <= eps;
write('Число e равно ', e:3:t(eps));
writeln(' с точность до ', eps:1:t(eps))
end.
Задание 1
Вы уже знаете, что значения sinx можно вычислять с помощью следующего ряда:
sin x  x 
x 3 x5
x 2 n 1
 ... (1) n 1
 r2 n (x ),
3! 5!
(2n  1)!
где погрешность оценивается легко:
| x |2 n1
| r2 n ( x )| 
.
(2n  1)!
Так как ряд знакочередующийся, то его остаток меньше по абсолютной величине
последнего "отброшенного" члена, т. е. n + 1 - го.
Составьте программу вычисления значений sinx с заданной степенью точности eps
для различных, вводимых пользователем значений x.
Пример 2. С помощью биномиального ряда, в который разлагается двучлен (1  x ) m
можно не только возводить двучлены в любую степень, но и извлекать корни с любым
вещественным показателем.
Надо лишь помнить, что значения x принадлежат промежутку (-1, 1), на котором
рассматривается биномиальный ряд.
Для примера посмотрим, как вычислить значение корня кубического из числа 10, т.е.
3
10 .
Прежде надо преобразовать подкоренное выражение к виду (1  x ), где |x| <1. Для этого
достаточно подобрать число, куб которого близок к числу 10. Таким числом является 2,
так как 23 =8, и тогда 3 10 преобразуем так:
3
10  23
10
 23 125
.  23 1  0.25  2(1  0.25)1/ 3 .
8
Полученное выражение можно разложить в биномиальный ряд и вычислить с любой
степенью точности.
Осталось выяснить вопрос относительно оценки точности вычисления с помощью
дополнительного члена. Для этого снова обратимся к разложению и его остатку.
(1  x )m  1  mx 
m(m  1) 2
m(m  1)...(m  n  1) n
x ...
x  rn (x ).
2!
n!
Этот ряд также знакочередующийся, значит остаток по абсолютной величине меньше абсолютной величины n + 1 - го члена.
| rn ( x )| 
m( m  1)... ( m  n  2)
 x n1 .
( n  1)!
Нетрудно найти рекуррентную формулу для получения членов этого ряда.
Она будет такой:
un  un1  x 
m  n 1
.
n
Теперь составим программу для вычисления корней с помощью этого ряда.
391

Программа
Program Problem2;
uses WinCrt;
var
n
: integer;
x, m, z, eps, u, b : real;
{----------------------------------------------------------------------------------------}
{ Функция вычисления порядка - кол-во знаков после запятой }
Function t(eps : real) : integer;
var
k : integer;
begin
k := -1;
repeat
eps := eps*10;
k := k + 1
until eps > 1;
t := k
end;
{----------------------------------------------------------------------------------------}
begin
write('Введите значение x, |x|<1 '); readln(x);
write('Введите значение дробного показателя m '); readln(m);
write('Задайте точность вычисления '); readln(eps);
b := 1; u := 1; n := 1;
repeat
u := (m - n + 1)*x*u/n;
b := b + u;
n := n+1
until abs(u) <= eps;
writeln('Корень', 1/m:3:0, ' - й степени из ', (1 + x):3:t(eps));
writeln(' равен ', b:3:t(eps),' с точностью до ', eps:3:t(eps))
end.
Задание 2
Составьте программу, которая вычисляет значение числа  с заданной степенью
точности при помощи ряда Лейбница:

4
1 
1 1
1
 ...( 1) n1
...
3 5
2n  1
392 
2. Сходимость числовых и функциональных рядов
Пусть дан бесконечный ряд: a1  a2  a3 ...an ...
Станем последовательно складывать члены ряда, составляя (в бесконечном количестве) суммы;
A1  a1 , A2  a1  a2 , A3  a1  a2  a3 , ..., An  a1  a2 ...an ...;
их называют частными суммами (или отрезками) ряда.
Конечный или бесконечный предел A частичной суммы An ряда при n   :
A  lim An
n 

называется суммой ряда и пишут A  a1  a2  a3 ...an ...   an .
n 1
Если ряд имеет конечную сумму, его называют сходящимся, в противном случае (т.е.
если сумма равна  или  , либо же суммы вовсе нет - расходящимся.
Попробуем установить являются ли некоторые ряды сходящимися?

Пример 3. Является ли ряд
(n!) 2
сходящимся?

n  1 ( 2 n )!
Для установления этого, надо определить имеет ли предел последовательность частичных сумм ряда, а это в свою очередь, означает будет ли разность между суммами по
абсолютной величине меньше заданного положительного, даже очень малого числа eps,
т.е. будет ли выполняться неравенство:
| An  Am |  eps.
Отсюда вытекает алгоритм составления программы.
Надо находить сумму членов ряда и как только разность между текущей суммой и
следующей будет меньше eps, то цикл закончить, значит ряд сходится и выдать его сумму,
которая будет равна текущей сумме с заданной степенью точности.
Установить является ли следующий ряд сходящимся и найти то число с заданной точностью eps, к которому он сходится.
Для вычисления суммы ряда нам придётся находить его члены и прибавлять к текущей сумме, а для нахождения членов ряда воспользуемся подпрограммой - функцией для
вычисления факториала числа.
Программа
Program Problem3;
uses WinCrt;
var
n
: integer;
z, z1, e, eps : real;
{----------------------------------------------------------------------------------------}
Function fakt(n : longint) : real;
var
i : longint;
f : real;
393

begin
f := 1;
if n = 0 then f := 1
else for i := 1 to n do f := f*i;
fakt := f
end;
{----------------------------------------------------------------------------------------}
{ Функция вычисления порядка - кол-во знаков после запятой }
Function t(eps : real) : integer;
var
k : integer;
begin
k := -1;
repeat
eps := eps*10;
k := k + 1
until eps > 1;
t := k
end;
{----------------------------------------------------------------------------------------}
begin
write('Задайте точность eps '); readln(eps);
z := 0; n := 1;
repeat
z := z + sqr(fakt(n))/fakt(2*n);
n := n + 1;
z1 := z + sqr(fakt(n))/fakt(2*n)
until abs(z1 - z) < eps;
write('Сумма ряда равна ', z1:6:t(eps));
writeln(' с точностью до ', eps:3:t(eps))
end.
Задание 3

Установить, является ли ряд
1
1 a
n 1
n
, при a > 1 сходящимся?
3. Задачи с использованием последовательностей и рядов
Пример 4. Последовательность (an) 1,
задается так: a1  1 и an1  1 
2 3 5 8
, , , , ...
1 2 3 5
1
для каждого n=1, 2, 3, ...
an
Найдите число, которое меньше всех членов последовательности с четными номерами и одновременно больше всех ее членов с нечетными номерами.
Если такое число существует, обозначим его a, тогда должно выполняться неравенство
3 8
2 5 13
1, , ,... a  , , ,...
2 5
1 3 8
394 
Нетрудно заметить, что последовательность слева является возрастающей, а справа
убывающей, а значит число a является "сгустком" для членов этой последовательности,
т.е. ее пределом. Теперь осталось найти этот предел. Для этого воспользуемся признаком
существования предела.
Зададимся положительным числом eps, даже очень малым и найдем члены последовательности, разность между которыми по абсолютной величине будет меньше eps.
Найденный член последовательности и даст искомое число с указанной точностью.
Кстати говоря, это число в математике известно и равно
5 1
.
2
Программа
Program Problem4;
uses WinCrt;
var
n, k
: integer;
a, a1, eps, e : real;
{----------------------------------------------------------------------------------------}
{ Функция вычисления порядка - кол-во знаков после запятой }
Function t(eps : real) : integer;
var
k : integer;
begin
k := -1;
repeat
eps := eps*10;
k := k + 1
until eps > 1;
t := k
end;
{----------------------------------------------------------------------------------------}
begin
write('Задайте точность eps '); readln(eps);
a := 1;
repeat
a := 1 + 1/a; {с четными номерами}
a1 := 1 + 1/a {с нечетными номерами}
until abs(a1 - a) < eps;
write('Искомое число ', a1:3:t(eps));
writeln(' с точностью до ', eps:3:t(eps));
writeln('Сравните с точным результатом ', (sqrt(5)+1)/2:3:t(eps))
end.
Задание 4
Последовательность (an ) задается так: a1  7, an1 - сумма цифр числа an2 . Найдите
a1000 .
395

4. Бесконечные произведения
Напомним основные понятия, относящиеся к бесконечным произведениям.
Определение. Если p1 , p2 , p3 ,..., pn , ...
(1) есть некоторая заданная последовательность чисел, то составленный из них символ

p1  p2  p3 . .. pn . ..   pn
(2)
n1
называют бесконечным произведением.
Станем последовательно перемножать числа (1), составляя частичные произведения
P1  p1 , P2  p1  p2 , P3  p1  p2  p3 , ..., Pn  p1  p2  p3 ... pn , ...
(3)
Эту последовательность частичных произведений Pn  мы всегда будем сопоставлять символу (2).
Предел P частичного произведения Pn при n   (конечный или бесконечный)
lim Pn  P
называют значением произведения (2) и пишут:

P  p1  p2 ... pn ...   pn .
n1
Если бесконечное произведение имеет конечное значение P и притом отличное от
0, то само произведение называют сходящимся, в противном случае - расходящимся.
Достаточно одному из сомножителей произведения быть нулем, чтобы и значение
всего произведения также было равно нулю. В дальнейшем этот случай будет исключен
из рассмотрения, так что для нас всегда pn  0.
4.1. Примеры некоторых замечательных бесконечных произведений

Пример 1.

1
2 .

 1  n
n 2
Так как частичное произведение
1 
1 
1  1 n 1 1

Pn  1  2  1  2  ... 1  2   
 ,
 2  3   n  2 n
2
1
то бесконечное произведение сходится, и его значением будет .
2
Проверим этот факт, для чего составим программу вычисления произведения:

1

1  2  .

n 
n 2 
Составим процедуру, которая с заданной точностью вычисляет это произведение и
включим ее в программу. Зачем нам нужна процедура, если можно сразу составить программу?
Ответ понятен. Нам придется составлять еще много программ, в которых не только
вычисляются произведения, но и выполняется ряд других задач. Изменив только одну
процедуру, мы сможем использовать новое произведение для поставленных в программе
задач.
396 
Процедура
Procedure Multiplication(eps : real; var Mult : real);
var
n : longint;
Mult1 : real;
begin
n := 2; Mult1 := 1;
repeat
Mult1 := Mult1*(1 - 1/sqr(n));
n := n + 1;
Mult := Mult1*(1 - 1/sqr(n))
until abs(Mult - Mult1) < eps
end;
Программа
Program Multiply1;
uses WinCrt;
var
Mult, eps : real;
{----------------------------------------------------------------------------------------}
{ Функция вычисления порядка - кол-во знаков после запятой }
Function t(eps : real) : integer;
var
k : integer;
begin
k := -1;
repeat
eps := eps*10;
k := k + 1
until eps > 1;
t := k
end;
{----------------------------------------------------------------------------------------}
Procedure Multiplication(eps : real; var Mult : real);
var
n : longint;
Mult1 : real;
begin
n := 2; Mult1 := 1;
repeat
Mult1 := Mult1*(1 - 1/sqr(n));
n := n + 1;
Mult := Mult1*(1 - 1/sqr(n))
until abs(Mult - Mult1) < eps
end;
{----------------------------------------------------------------------------------------}
begin
write('Введите точность вычисления '); readln(eps);
Multiplication(eps, Mult);
writeln('Значение произведения равно ', Mult:6:t(eps));
397

writeln('С точностью до ', eps:1:t(eps))
end.
Пример 2.
4.2. Формула Валлиса (J. Wallis)
Формула Валлиса имеет для нас не только исторический интерес, но она поможет
применять методику, которая будет использоваться при вычислении числа  с помощью
этой формулы.
2

 2n !! 
1
 lim 

Итак, формула Валлиса имеет вид:

2 n  (2n  1)!! 2n  1
или

2  2  4  4...2n  2n
.
2 n 1  3  3  5  5...(2n  1)  (2n  1)  (2n  1)

Этот предел равносилен разложению числа
в бесконечное произведение
2
 2 2 4 4
2n
2n
     ... 

 ...
2 1 3 3 5
2n  1 2n  1
Она же приводит к формулам



   
 4m 2  
1
1  2
 .
  или  

1 
  ,  1 
2
2
(2m  1) 2  4 m 1  4 m 2  
m 1 
m 1  4 m  1
Но надо заметить, что для вычисления числа  существуют методы, гораздо быстрее ведущие к цели.
Составим процедуру, а затем и программу вычисления числа  по последней формуле.
Процедура
 lim
Procedure Wallis(eps : real; var Mult : real);
var
n : longint;
Mult1 : real;
begin
n := 1; Mult := 1;
repeat
Mult := Mult*(4*sqr(n)/(4*sqr(n)-1));
n := n + 1;
Mult1 := 4*sqr(n)/(4*sqr(n)-1)
until Mult1 < eps
end;
Следует заметить, что оценка погрешности в этой процедуре отличается от оценки
погрешности в процедуре примера 1. Такая оценка вытекает из математических соображений, n-й множитель в произведении Валлиса
чем разность между n - 1-м произведением и n-м.
4n 2
"быстрее" стремится к нулю,
4n2  1
398 
Программа
Program Problem2;
uses WinCrt;
var
Mult, eps : real;
{----------------------------------------------------------------------------------------}
{ Функция вычисления порядка - кол-во знаков после запятой }
Function t(eps : real) : integer;
var
k : integer;
begin
k := -1;
repeat
eps := eps*10;
k := k + 1
until eps > 1;
t := k
end;
{----------------------------------------------------------------------------------------}
Procedure Wallis(eps : real; var Mult : real);
var
n : longint;
Mult1 : real;
begin
n := 1; Mult := 1;
repeat
Mult := Mult*(4*sqr(n)/(4*sqr(n)-1));
n := n + 1;
Mult1 := 4*sqr(n)/(4*sqr(n)-1)
until Mult1 < eps
end;
{----------------------------------------------------------------------------------------}
begin
write('Введите точность вычисления '); readln(eps);
Wallis(eps, Mult);
writeln('Значение числа Пи равно ', 2*Mult:6:t(eps));
writeln('С точностью до ', eps:1:t(eps))
end.
4.3. Полный эллиптический интеграл 1-го рода
Для полного эллиптического интеграла 1-го рода установлена формула
K (k ) 

2
lim 1  k 1 1  k 2   ...  1  k n ,
n 
где переменная k n определяется рекуррентным соотношением:
kn 
1  1  k n21
1  1  k n21
( k 0  k ) , (0 < k < 1).
Эта формула дает разложение K(k) в бесконечное произведение
399

K (k ) 

2

  1  k n .
n1
Процедура
Procedure Elliptic(k, eps : real; var Kk : real);
var
Kk1 : real;
begin
Kk1 := k;
repeat
k := (1 - sqrt(1 - sqr(k)))/(1 + sqrt(1 - sqr(k)));
Kk1 := Kk1*(1 + k);
k := (1 - sqrt(1 - sqr(k)))/(1 + sqrt(1 - sqr(k)));
Kk := Kk1*(1 + k);
until abs(Kk1 - Kk) < eps;
Kk := Kk*Pi/2
end;
Программа
Program Problem3;
uses WinCrt;
var
Kk, k, eps : real;
{----------------------------------------------------------------------------------------}
{ Функция вычисления порядка - кол-во знаков после запятой }
Function t(eps : real) : integer;
var
k : integer;
begin
k := -1;
repeat
eps := eps*10;
k := k + 1
until eps > 1;
t := k
end;
{----------------------------------------------------------------------------------------}
Procedure Elliptic(k, eps : real; var Kk : real);
var
Kk1 : real;
begin
Kk1 := k;
repeat
k := (1 - sqrt(1 - sqr(k)))/(1 + sqrt(1 - sqr(k)));
Kk1 := Kk1*(1 + k);
k := (1 - sqrt(1 - sqr(k)))/(1 + sqrt(1 - sqr(k)));
Kk := Kk1*(1 + k);
until abs(Kk1 - Kk) < eps;
Kk := Kk*Pi/2
end;
400 
{----------------------------------------------------------------------------------------}
begin
write('Введите значение k (0 < k < 1) '); readln(k);
write('Введите точность вычисления '); readln(eps);
Elliptic(k, eps, Kk);
writeln('Значение интеграла равно ', Kk:6:t(eps));
writeln('С точностью до ', eps:1:t(eps))
end.
Задание 5
Известен предел: lim cos

 cos

... cos


sin 

2

 sin 
.
Теперь мы можем записать это так:  cos n 

2
n1

В частности, при   , придем к разложению:
n
2
2
2


n
(  0).

 cos ... cos n1 ...
(1).

4
8
2

1

1 1
Если вспомнить, что cos 
и cos 
 cos  , то это разложение можно
4
2
2
2 2
переписать в виде
2
 cos
2
2
1 1 1 1
1 1 1 1 1





...

2 2 2 2
2 2 2 2 2
Эта формула впервые была предложена Ф. Виетом (F. Viet) и является вместе с формулой Валлиса примерами первых бесконечных произведений.
Используя формулу (1) составьте программу вычисления числа  .

5. Приближенное вычисление интегралов с помощью рядов
С помощью почленного интегрирования рядов получаются разложения в бесконечные степенные ряды для некоторых интегралов, не выражающихся в конечном виде через
элементарные функции. Эти разложения могут быть использованы для приближенных
вычислений.
Так, исходя из разложения
x x2 x3
xn
e  1    ... ... ,
1! 2! 3!
n!
x
x
найдем значение интеграла
e

x2
2
dx для всех действительных значений x.
0
Вначале разложим в ряд функцию
2
e

x
2
1
e

x2
2
:
x2
x4
x6
x8
x 2n
 2
 3
 4
...(1) n n
... .
2  1! 2  2 ! 2  3 ! 2  4 !
2  n!
Интегрируем почленно этот ряд, получим:
401

x
x2
2
1 x3
1
x5
1
x7
1
x9
(1) n x 2n1
0 e dx  x  2  1!  3  22  2 !  5  23  3 !  7  24  4 !  9 ... 2 n  n !  2n  1 ...,
который сходится на множестве всех действительных чисел.
Чтобы составить программу, найдем рекуррентную формулу для вычисления суммы
ряда.
( 1) n1
( 1) n1  ( 1)
x 2 n1
x 2 n1  x 2
un1 ( x )  n1

, un ( x )  n1

, u0 (x )  x ,
2  ( n  1)! 2n  1
2  2  ( n  1)! n 2n  1

un (x ) (1) n1  (1)  x 2n1  x 2  2 n1  (n  1)! (2n  1)
x 2  (2n  1)


,
un1 (x )
2  n  (2n  1)
(1) n1  x 2n1  2 n1  2  (n  1)! n  (2n  1)
отсюда получаем:
x 2  (2n  1)
un ( x )  un1 ( x ) 
, u0 ( x )  x .
2  n  (2n  1)
Так как ряд знакочередующийся, то оценить точность вычисления можно по абсолютной величине последнего "отброшенного" члена, т. е. по значению un1 (x ).
Программа
Program Problem1;
uses WinCrt;
var
n
: longint;
u, I, x, eps : real;
{----------------------------------------------------------------------------------------}
{ Функция вычисления порядка - кол-во знаков после запятой }
Function t(eps : real) : integer;
var
k : integer;
begin
k := -1;
repeat
eps := eps*10;
k := k + 1
until eps > 1;
t := k
end;
{----------------------------------------------------------------------------------------}
begin
write('Введите значение аргумента x '); readln(x);
write('Введите точность вычисления '); readln(eps);
u := x; n := 0; I := 0;
repeat
I := I + u;
n := n + 1;
u := -(u*x*x*(2*n - 1))/(2*n*(2*n + 1))
until abs(u) < eps;
writeln('Значение интеграла равно ', I:6:t(eps))
end.
402 
В теории вероятностей нам придется иметь дело с функцией - интегралом вероятностей (x ) 
2
2
x
e

x2
2
dx .
0
Надо лишь заметить, что значение этой функции при x  5 равно 1, а при x  5
равно -1.
Для составления программы вычисления значений этого интеграла и большего удобства использования в других программах, создадим функцию:
{ Рекуррентная функция вычисления интеграла вероятностей }
Function FF(x : real) : real;
var
n : integer;
u, I : real;
begin
if x >= 5
then FF := 1
else if x <= -5
then FF := -1
else
begin
u := x; n := 0; I := 0;
repeat
I := I + u;
n := n + 1;
u := -u*(x*x*(2*n - 1)/(2*n*(2*n + 1)))
until abs(u) < 0.00001;
FF := 2*I/sqrt(2*Pi)
end
end;
Использование ее в программе приводится ниже.
Program Problem2;
uses WinCrt;
var
x, eps : real;
{----------------------------------------------------------------------------------------}
Function t(eps : real) : integer;
var
k : integer;
begin
k := -1;
repeat
eps := eps*10;
k := k + 1
until eps > 1;
t := k
end;
{----------------------------------------------------------------------------------------}
{ Рекуррентная функция вычисления интеграла вероятностей }
403

Function FF(x, eps : real) : real;
var
n : integer;
u, I : real;
begin
if x >= 5
then FF := 1
else if x <= -5
then FF := -1
else
begin
u := x; n := 0; I := 0;
repeat
I := I + u; n := n + 1;
u := -u*(x*x*(2*n - 1)/(2*n*(2*n + 1)))
until abs(u) < eps;
FF := 2*I/sqrt(2*Pi)
end
end;
{-----------------------------------------------------------------------------------------}
begin
write('Введите значение аргумента x '); readln(x);
write('Введите точность вычисления '); readln(eps);
writeln('Значение интеграла вероятностей равно ', FF(x, eps):6:t(eps))
end.
x
Аналогично предыдущему примеру вычислим интеграл

0
sin x
dx .
x
Для этого надо вспомнить ряд, в который разлагается функция sinx
sin x 
x x 3 x5 x 7
x 2 n 1
   ... (1) n 1
...
1! 3! 5! 7!
(2n  1)!
при всех x  R .
sin x
:
x
sin x 1 x 2 x 4
x 2 n 2
n1
 

...(1)
...
x
1! 3 ! 5 !
(2n  1)!
Интегрируя его, получим:
x
sin x
x3
x5
x 2n1
n1
0 x dx  x  3! 3  5! 5 ...(1) (2n  1)! (2n  1) ...
Найдем рекуррентную формулу для составления программы.
x 2 n 3
x 2 n 3  x 2
n 2
n 2
un1 (x )  (1)
, un (x )  (1)  (1) 
,
(2n  3)! (2n  3)
(2n  3)!(2n  2)(2n  1)(2n  1)
Разложим в ряд
x 2  (2n  3)
.
u1 ( x )  x . Отсюда находим, что un (x )   un1 (x ) 
(2n  2)  (2n  1) 2
Оценить точность можно по абсолютной величине n-го члена, т. е. по величине
un1 ( x ).
404 
Составим процедуру вычисления этого интеграла.
Procedure Integral(x, eps : real; var I : real);
var
n : integer;
u : real;
begin
u := x; n := 1; I := 0;
repeat
I := I + u;
n := n + 1;
u := -(u*x*x*(2*n - 3))/((2*n - 2)*sqr(2*n - 1))
until abs(u) < eps
end;
Программа
Program Problem2;
uses WinCrt;
var
I, x, eps : real;
{----------------------------------------------------------------------------------------}
Procedure Integral(x, eps : real; var I : real);
var
n : integer;
u : real;
begin
u := x; n := 1; I := 0;
repeat
I := I + u;
n := n + 1;
u := -(u*x*x*(2*n - 3))/((2*n - 2)*sqr(2*n - 1))
until abs(u) < eps
end;
{----------------------------------------------------------------------------------------}
{ Функция вычисления порядка - кол-во знаков после запятой }
Function t(eps : real) : integer;
var
k : integer;
begin
k := -1;
repeat
eps := eps*10;
k := k + 1
until eps > 1;
t := k
end;
{----------------------------------------------------------------------------------------}
begin
write('Введите значение аргумента x '); readln(x);
write('Введите точность вычисления '); readln(eps);
Integral(x, eps, I);
writeln('Значение интеграла равно ', I:6:t(eps))
end.
405

Задание 6
1
Вычислить с помощью разложения в ряд интеграл

0
arctgx
dx .
x
5.1. Полный эллиптический интеграл 2-го рода

d
2
Полный эллиптический интеграл 1-го рода K (k ) 

0
1  k 2 sin 2 
.

2
Полный эллиптический интеграл 2-го рода (k ) 

1  k 2 sin 2  d .
0
Поставим задачу разложить эти интегралы по степеням модуля k (0 < k < 1). Для этого, положим в формуле интеграла 1-го рода
1
1
3
5
35 4
(2n  1)!! n
1 x  x 2  x 3 
x ...(1) n
x ... (1  x  1) (1)
2
8
16
128
2n !!
1 x
(2n  1)!! 2n
k  sin 2n  .
2n !!
n1

1
x   k sin  , получим:
2
1 
1  k 2 sin 2 
Этот ряд сходится равномерно относительно  , ибо мажорируется при всех значениях  сходящимся рядом
(2n  1)!! 2n
k ,
2n !!
n1

1 
следовательно, допустимо почленное интегрирование, получим:

2


 (2n  1)!!
K (k )  
 1   
 k 2n .


1  k 2 sin 2  2 
0
 n1  2n !! 

Аналогично, исходя из формулы
1
1
1
5 4
(2n  3)!! n
1 x 1 x  x 2  x 3 
x ...(1) n1
x ... (1  x  1) , (2)
2
8
16
128
2n !!
найдем
d
2

2
(k )  
0
 

 

2
k 2n 
 (2n  1)!!
1  k sin  d  1   

.
2  n1  2n !!  2n  1
2
2
Ряды (1) и (2) являются частными случаями биномиального ряда при m  
1
m .
2
Найдем рекуррентную формулу для вычисления суммы
2

k 2n
 (2n  1)!!

 2n !!   2n  1

n1 
1
и
2
406 
2
2
 (2n  3)!! k 2n 2
k 2n
1
 (2n  1)!!
un (k )  

, un1 (k )  

, u1 (k )   k 2 ,


4
 2n !!  2n  1
 (2n  2)!! 2n  3
2
k  (2n  1)(2n  3)
.
получаем un (k )  un1 (k ) 
4n 2
Процедура
Procedure Elliptic2(k, eps : real; var Ek : real);
var
n : integer;
u : real;
begin
u := k*k/4; n := 1; Ek := 0;
repeat
Ek := Ek + u;
n := n + 1;
u := (u*k*k*(2*n - 1)*(2*n - 3))/(4*n*n);
until abs(u) < eps;
Ek := Pi*(1 - Ek)/2
end;
Программа
Program Problem3;
uses WinCrt;
var
Ek, k, eps : real;
{----------------------------------------------------------------------------------------}
Procedure Elliptic2(k, eps : real; var Ek : real);
var
n : integer;
u : real;
begin
u := k*k/4; n := 1; Ek := 0;
repeat
Ek := Ek + u;
n := n + 1;
u := (u*k*k*(2*n - 1)*(2*n - 3))/(4*n*n);
until abs(u) < eps;
Ek := Pi*(1 - Ek)/2
end;
{----------------------------------------------------------------------------------------}
{ Функция вычисления порядка - кол-во знаков после запятой }
Function t(eps : real) : integer;
var
k : integer;
begin
k := -1;
repeat
eps := eps*10;
k := k + 1
отсюда
407

until eps > 1;
t := k
end;
{----------------------------------------------------------------------------------------}
begin
write('Введите значение аргумента 0 < k < 1 '); readln(k);
write('Введите точность вычисления '); readln(eps);
Elliptic2(k, eps, Ek);
writeln('Значение интеграла равно ', Ek:6:t(eps));
writeln('С точностью до ', eps:1:t(eps))
end.
Задание 7
Составить программу вычисления эллиптического интеграла 1-го рода и сравнить
результат с результатом, полученным с помощью бесконечных произведений.
6. Некоторые замечательные функции
6.1. Функция Бесселя
Для n  0
(1) k  x 
J n (x )  
 
k  0 k !( k  n)! 2 

2k  n
(1) k  x 
, а для n  0, J n (x )  
 
k  n k !( k  n)!  2 

2k  n
.
Легко видеть, что J  n (x )  (1) n J n (x ) . Эти функции играют важную роль в математической физике, небесной механике и т. д.
Для определения слагаемых применим рекуррентную формулу
y k   y k 1 
x
 
 2
2
k (n  k )
.
В качестве начальных значений суммы и слагаемого использовать член ряда при k =
0, равный
x
 
 2
n
.
n!
Для вычисления значения функции при k = 0, необходимо использовать функции
x
вычисления степени c основанием
и показателем n, а также функцию вычисления фак2
ториала числа n.
Функция вычисления степени.
Function Extent(x : real; n : integer) : real;
var
i : integer;
E : real;
begin
E := 1;
if n = 0 then E := 1
else for i := 1 to n do E := E*x/2;
408 
Extent := E
end;
Функция вычисления факториала.
Function Fakt(n : integer) : longint;
var
i : integer;
F : longint;
begin
F := 1;
if n = 0 then F := 1
else for i := 1 to n do F := F*i;
Fakt := F
end;
А теперь составим функцию вычисления всей суммы
( 1) k  x 
J n (x )  
 
k 0 k !( k  n )! 2 
Function J(x, eps : real; n : integer) : real;
var
y, jj : real;
k : integer;
begin
k := 0; y := Extent(x, n)/Fakt(n); jj := 0;
repeat
jj := jj + y;
k := k + 1;
y := -y*x*x/(4*k*(n + k))
until abs(y) < eps;
J := jj
end;

2 k n
,
Программа
Program Bessel;
uses WinCrt;
var
n
: integer;
x, eps : real;
{----------------------------------------------------------------------------------------}
Function t(eps : real) : integer;
var
k : integer;
begin
k := -1;
repeat
eps := eps*10;
k := k + 1
until eps > 1;
t := k
end;
{----------------------------------------------------------------------------------------}
409

Function Extent(x : real; n : integer) : real;
var
i : integer;
E : real;
begin
E := 1;
if n = 0 then E := 1
else for i := 1 to n do E := E*x/2;
Extent := E
end;
{----------------------------------------------------------------------------------------}
Function Fakt(n : integer) : longint;
var
i : integer;
F : longint;
begin
F := 1;
if n = 0 then F := 1
else for i := 1 to n do F := F*i;
Fakt := F
end;
{----------------------------------------------------------------------------------------}
Function J(x, eps : real; n : integer) : real;
var
y, jj : real;
k : integer;
begin
k := 0; y := Extent(x, n)/Fakt(n); jj := 0;
repeat
jj := jj + y;
k := k + 1;
y := -y*x*x/(4*k*(n + k))
until abs(y) < eps;
J := jj
end;
{----------------------------------------------------------------------------------------}
begin
write('Введите значение x '); readln(x);
write('Введите значение n '); readln(n);
write('Введите точность вычисления '); readln(eps);
writeln('Значение функции Бесселя равно ', J(x, eps, n):6:t(eps))
end.
6.2. Гамма-функция Эйлера
Рассмотрим (вместе с Эйлером) бесконечное произведение
x
 1
1 
 

n
1
(x )  
,
x
x n1
1
n
считая x отличным от нуля и от всех целых отрицательных чисел.
410 
Легко представить его общий множитель так:
x
 1
1  

n
x (x  1)
 1
1


 2 ;
n 
x
2n 2
1
n
отсюда вытекает, что наше произведение (абсолютно) сходится.
Определяемая им функция ( x ) является (после элементарных) одной из важнейших рассматриваемых в анализе функций, а ее роль в теории вероятностей просто неоценима.
x
 1
1  
n
1  
, составим функцию вычисления (x ).
Используя формулу (x )  
x
x n1
1
n
Для этого найдем, что n-й член бесконечного произведения


n 1

1 

1

n
x
1
n
x


n 1
 n  1
n

 n 
x n
x
,
будет равен n (x ) 
 n  1
n

 n 
x n
x
, а первый член
1 2x
, тогда, при увеличении n можно получать соответдолжен быть равен 1 ( x )  
x x 1
ствующие значения гамма-функции.
Теперь надо оставить функцию для вычисления степени действительного положительного аргумента a с любым действительным показателем x. Для этого достаточно воспользоваться соотношением:
ax  ex ln a , где a > 0.
Function Extent_real(a, x : real) : real;
begin
Extent_real := exp(x*ln(a))
end;
Теперь можно составить основную функцию для вычисления гамма-функции.
Function G(x, eps : real) : real;
var
n : longint;
g1, gg : real;
begin
n := 1; gg := Extent_real((n + 1)/n, x)/(x*(x + n));
repeat
n := n + 1;
gg := gg*n*Extent_real((n + 1)/n, x)/(x + n);
n := n + 1;
g1 := gg*n*Extent_real((n + 1)/n, x)/(x + n)
until abs(g1 - gg) < eps;
G := gg
end;
411

Программа
Program Gamma_function;
uses WinCrt;
var
x, eps : real;
{----------------------------------------------------------------------------------------}
{ Функция вычисления порядка - количества знаков после запятой }
Function t(eps : real) : integer;
var
k : integer;
begin
k := -1;
repeat
eps := eps*10;
k := k + 1
until eps > 1;
t := k
end;
{----------------------------------------------------------------------------------------}
Function Extent_real(a, x : real) : real;
begin
Extent_real := exp(x*ln(a))
end;
{----------------------------------------------------------------------------------------}
Function G(x, eps : real) : real;
var
n
: longint;
g1, gg : real;
begin
n := 1; gg := Extent_real((n + 1)/n, x)/(x*(x + n));
repeat
n := n + 1;
gg := gg*n*Extent_real((n + 1)/n, x)/(x + n);
n := n + 1;
g1 := gg*n*Extent_real((n + 1)/n, x)/(x + n)
until abs(g1 - gg) < eps;
G := gg
end;
{----------------------------------------------------------------------------------------}
begin
write('Введите значение аргумента '); readln(x);
write('Введите точность вычисления '); readln(eps);
writeln('Значение гамма-функции равно ', G(x, eps):6:t(eps))
end.
Так как n-е частичное произведение имеет вид
x
(n  1) x
n!nx
 n  1

, тогда можно поло 
 x   x   n  x (x  1)(x  2)...(x  n)
x (1  x )1   ...1  

2 
n
жить
412 
n!nx
.
n x (x  1)(x  2)...(x  n)
(x )  lim
Написав аналогичную формулу для (x  1), легко видеть, что
 (x  1)
nx
 lim
 x,
n x  1  n
 (x )
и мы приходим к простому и важному соотношению:  (x  1)  x   (x ).
Если вы выполняли предыдущую программу для различных значений аргумента, то
смогли убедиться, что точность вычисления невелика, даже при достаточно большом значении n.
Формула ( x  1)  x  ( x ) дает возможность более точно вычислять значения гамма-функции для значений аргумента, заключенного в интервале (1; 2).
Для этого составим следующую функцию:
Function Gamma(x, eps : real) : real;
begin
x := x - 1;
Gamma := x*G(x, eps)
end;
Program Gamma_function;
uses WinCrt;
var
x, eps, gg : real;
{----------------------------------------------------------------------------------------}
{ Функция вычисления порядка - количества знаков после запятой }
Function t(eps : real) : integer;
var
k : integer;
begin
k := -1;
repeat
eps := eps*10;
k := k + 1
until eps > 1;
t := k
end;
{----------------------------------------------------------------------------------------}
Function Extent_real(a, x : real) : real;
begin
Extent_real := exp(x*ln(a))
end;
{----------------------------------------------------------------------------------------}
Function G(x, eps : real) : real;
var
n
: longint;
g1, gg : real;
begin
n := 1; gg := Extent_real((n + 1)/n, x)/(x*(x + n));
repeat
413

n := n + 1;
gg := gg*n*Extent_real((n + 1)/n, x)/(x + n);
n := n + 1;
g1 := gg*n*Extent_real((n + 1)/n, x)/(x + n)
until abs(g1 - gg) < eps;
G := gg
end;
{----------------------------------------------------------------------------------------}
Function Gamma(x, eps : real) : real;
begin
x := x - 1;
Gamma := x*G(x, eps)
end;
{----------------------------------------------------------------------------------------}
begin
write('Введите значение аргумента '); readln(x);
write('Введите точность вычисления '); readln(eps);
if (x < 2) and (x > 1) then gg := Gamma(x, eps)
else gg := G(x, eps);
writeln('Значение гамма-функции равно ', gg:6:t(eps))
end.
Если положить x равным натуральному числу m, то получим рекуррентную формулу
 (m  1)  m   (m).
Так как (1)  1 (что легко проверить), то отсюда (m  1)  m !
Эта формула дает еще одну возможность уточнить значения функции для натуральных значений аргумента. Для вычисления по этой формуле составим еще одну функцию.
Function G_natural(m : integer) : longint;
var
i : integer;
g : longint;
begin
g := 1;
for i := 2 to m do g := g*i;
G_natural := g
end;
Программа изменится и станет такой:
Program Gamma_function;
uses WinCrt;
var
x, eps, gg : real;
{----------------------------------------------------------------------------------------}
{ Функция вычисления порядка - количества знаков после запятой }
Function t(eps : real) : integer;
var
k : integer;
begin
k := -1;
repeat
414 
eps := eps*10;
k := k + 1
until eps > 1;
t := k
end;
{----------------------------------------------------------------------------------------}
Function Extent_real(a, x : real) : real;
begin
Extent_real := exp(x*ln(a))
end;
{----------------------------------------------------------------------------------------}
Function G(x, eps : real) : real;
var
n : longint;
g1, gg : real;
begin
n := 1; gg := Extent_real((n + 1)/n, x)/(x*(x + n));
repeat
n := n + 1;
gg := gg*n*Extent_real((n + 1)/n, x)/(x + n);
n := n + 1;
g1 := gg*n*Extent_real((n + 1)/n, x)/(x + n)
until abs(g1 - gg) < eps;
G := gg
end;
{----------------------------------------------------------------------------------------}
Function Gamma(x, eps : real) : real;
begin
x := x - 1;
Gamma := x*G(x, eps)
end;
{----------------------------------------------------------------------------------------}
Function G_natural(m : integer) : longint;
var
i : integer;
g : longint;
begin
g := 1;
for i := 2 to m do g := g*i;
G_natural := g
end;
{----------------------------------------------------------------------------------------}
begin
write('Введите значение аргумента '); readln(x);
write('Введите точность вычисления '); readln(eps);
if x = trunc(x)
then gg := G_natural(trunc(x))
else
if (x < 2) and (x > 1)
then gg := Gamma(x, eps)
else gg := G(x, eps);
writeln('Значение гамма-функции равно ', gg:6:t(eps));
415

end.
Еще одну важную формулу для функции  мы получим, если перемножим почленно равенства
 1
1 
 

n
 (x  1)   (x )  x  
x
n1
1
n
x

Cx
и e 
n1
e
x
n
 1
1  

n
x
,
Мы находим:

e
x
n

1
x   xn

Cx
1    e .
x или ( x  1)  e 
n
n1
n 1 
1
n
Это - формула Вейерштрасса.
eCx  (x  1)  
Библиотека часто встречающихся процедур и функций
55. Вычисление числа e.
Procedure number_e(eps : real; var e : real);
var
n : integer;
u : real;
begin
e := 0; u := 1; n := 1;
repeat
e := e + u;
u := u/n; n := n + 1
until 3*u <= eps;
end;
56. Вычисление корней любой степени из произвольного числа.
Procedure Radical(n : integer ; x, eps : real; var b : real);
var
n
: integer;
z, m, u : real;
begin
b := 1; u := 1; n := 1;
repeat
u := (m - n + 1)*x*u/n; b := b + u; n := n+1
until abs(u) <= eps;
end;

57. Процедура вычисления бесконечного произведения
n 2
Procedure Multiplication(eps : real; var Mult : real);
var
n : longint;
Mult1 : real;

1
2 .

 1  n
416 
begin
n := 2; Mult1 := 1;
repeat
Mult1 := Mult1*(1 - 1/sqr(n));
n := n + 1;
Mult := Mult1*(1 - 1/sqr(n))
until abs(Mult - Mult1) < eps
end;
58. Процедура вычисления числа  по формуле Валлиса.
Procedure Wallis(eps : real; var Mult : real);
var
n : longint;
Mult1 : real;
begin
n := 1; Mult := 1;
repeat
Mult := Mult*(4*sqr(n)/(4*sqr(n)-1));
n := n + 1;
Mult1 := 4*sqr(n)/(4*sqr(n)-1)
until Mult1 < eps
end;
59. Процедур вычисления эллиптического интеграла 1-го рода через бесконечное
произведение.
Procedure Elliptic(k, eps : real; var Kk : real);
var
Kk1 : real;
begin
Kk1 := k;
repeat
k := (1 - sqrt(1 - sqr(k)))/(1 + sqrt(1 - sqr(k)));
Kk1 := Kk1*(1 + k);
k := (1 - sqrt(1 - sqr(k)))/(1 + sqrt(1 - sqr(k)));
Kk := Kk1*(1 + k);
until abs(Kk1 - Kk) < eps;
Kk := Kk*Pi/2
end;
60. Рекуррентная функция вычисления интеграла вероятностей.
Function FF(x : real) : real;
var
n : integer;
u, I : real;
begin
if x >= 5
then FF := 1
else if x <= -5
then FF := -1
417

else
begin
u := x; n := 0; I := 0;
repeat
I := I + u;
n := n + 1;
u := -u*(x*x*(2*n - 1)/(2*n*(2*n + 1)))
until abs(u) < 0.00001;
FF := 2*I/sqrt(2*Pi)
end
end;
x
61. Процедура вычисления интеграла

0
sin x
dx .
x
Procedure Integral(x, eps : real; var I : real);
var
n : integer;
u : real;
begin
u := x; n := 1; I := 0;
repeat
I := I + u;
n := n + 1;
u := -(u*x*x*(2*n - 3))/((2*n - 2)*sqr(2*n - 1))
until abs(u) < eps
end;
62. Процедура вычисления эллиптического интеграла 2-го рода с помощью интегрирования рядов.
Procedure Elliptic2(k, eps : real; var Ek : real);
var
n : integer;
u : real;
begin
u := k*k/4; n := 1; Ek := 0;
repeat
Ek := Ek + u;
n := n + 1;
u := (u*k*k*(2*n - 1)*(2*n - 3))/(4*n*n);
until abs(u) < eps;
Ek := Pi*(1 - Ek)/2
end;
2k  n

( 1) k  x 
.
 
63. Функция Бесселя: J n ( x )  
k  0 k !( k  n)! 2 
Function J(x, eps : real; n : integer) : real;
var
y, jj : real;
k : integer;
begin
418 
k := 0; y := Extent(x, n)/Fakt(n); jj := 0;
repeat
jj := jj + y;
k := k + 1;
y := -y*x*x/(4*k*(n + k))
until abs(y) < eps;
J := jj
end;
64. Функция вычисления степени положительного действительного числа с произвольным действительным показателем.
Function Extent_real(a, x : real) : real;
begin
Extent_real := exp(x*ln(a))
end;
65. Функции для вычисления гамма-функции.
Для произвольного действительного аргумента x, отличного от нуля и от всех целых
отрицательных чисел.
Function G(x, eps : real) : real;
var
n : longint;
g1, gg : real;
begin
n := 1; gg := Extent_real((n + 1)/n, x)/(x*(x + n));
repeat
n := n + 1;
gg := gg*n*Extent_real((n + 1)/n, x)/(x + n);
n := n + 1;
g1 := gg*n*Extent_real((n + 1)/n, x)/(x + n)
until abs(g1 - gg) < eps;
G := gg
end;
Вычисление гамма-функции для значений аргумента из промежутка (1, 2)
Function Gamma(x, eps : real) : real;
begin
x := x - 1;
Gamma := x*G(x, eps)
end;
Вычисление гамма-функции натурального аргумента.
Function G_natural(m : integer) : longint;
var
i : integer;
g : longint;
begin
g := 1;
for i := 2 to m do g := g*i;
G_natural := g
end;
419

Упражнения
194. Вычислить сумму членов рядов, заданных формулами общего члена. Число
членов ряда задается пользователем.
1
1
2n  1
10 n
n!
2n n!
a) an  n  n , б) an  n , в) an 
, г) an  n , д) an  n .
n!
2
3
2
n
n  !
195. Составьте функции для нахождения с указанной точностью числа  путем вычисления следующих рядов:
2 1 1
1
1
a)
 2  2  2 ...
...;
8 1
3
5
(2n  1) 2
б) ряд Леонардо Эйлера:
2
1
1
1
1
 1  2  2  2 ... 2 ...;
6
2
3
4
n
196. Составьте функции для вычисления с указанной точностью значений тригонометрических функций путем вычисления следующих рядов:
x2 x4 x6
x 2n
а) cos x  1 


...(1) n
...
2! 4 ! 6!
(2n)!
Для вычисления значения члена ряда использовать рекуррентную формулу
x2
y n   y n1 
.
2n(2n  1)
x3 x5
x 2 n1

... ( 1) n1
..., | x |  1.
3
5
2n  1
Для определения значения члена ряда использовать формулу
x 2 (2n  3)
y n   y n1 
.
2n  1
197. Дано действительное x. Вычислить приближенное значение бесконечной сум-
б) arctgx  x 
мы:
x2 x3
x3 x5

 ...
(| x | 1), б )
x

 ... (| x | 1),
2
3
3
5
x  1 ( x  1) 2 ( x  1) 3
1
1
1
1

в)


 ...  x  , г )
 3  5  ... ( x  1).
2
3
x
2
x 3x
2x
3x
5x

Нужное приближение считается полученным, если вычислена сумма нескольких
первых слагаемых, и очередное слагаемое оказалось по модулю меньше 0.00001.
198. Вычислить приближенное значение бесконечной суммы (справа от каждой
суммы дается ее точное значение, с которым можно сравнить полученный результат):
1 1 1
а) 1    ...
0.6931478... ,
2 3 4
1
1
1
б)
1,


...
1 2 2  3 3  4
3
1
1
1
в)


...
,
1 3 2  4 3  5
4
1
1
1
1
г)


...
.
1 2  3 2  3  4 3  4  5
4
Нужное приближение считается полученным, если вычислена сумма нескольких
первых слагаемых, и очередное слагаемое оказалось по модулю меньше данного положительного числа eps.
а)
x
420 
199. Дано: натуральное n, действительное x. Вычислить:
а) sin x  sin 2 x  sin 3 x ... sin n x , б) sin x  sin x 2  sin x 3 ... sin x n ,
в) sin x  sin sin x ... sin sin... sin x .
200. Дано: действительные a, h, натуральное n. Вычислить
f (a)  f (a  h)  f (a  2h)... f (a  nh), где f (x )  (x 2  1) cos x .
201. Дано: натуральное n, действительное x. Вычислить:
1
 1

1

  | x |     | x |   ...    | x | ,
 1!
  2!

 n!

202. Вычислить:
1
1
1
а) 2  2 ...
,
1
2
1002
1 1
1
,
в)   .. 
1! 2!
10!
203. Вычислить сумму членов ряда
1
1
1
,
3  3 ... 
1
2
503
1
1
1
1
г) 2  2  2  ... 
.
2
4
8
1282
б)
( x  1) 5
( x  1) 2 n 1
x  1 ( x  1) 3
z 2


 ... 
 ...
x  1 3( x  1) 3 5( x  1) 5
(2 n  1)( x  1) 2 n 1
с точностью до члена ряда меньшего 0.0000001.
204. Установить, сходятся ли следующие ряды:

n!
а)  n , б)
n 1 n
3n  2 n
, в)

6n
n 1

( n  1)!
.
n
* n!
n 1

2
205. Составить программу вычисления бесконечного произведения:


n1
e
1
n
1
1
n
.
Частичное произведение имеет вид
Pn 
1
1
1 ... 
2
n
e
e ln n C  n
n


 eC  e n ,
n 1
n 1
n 1
где C - эйлерова постоянная, а  n бесконечно малая. Произведение сходится и его значение равно P  eC .
206. Эйлером были найдены следующие разложения тригонометрических функций в
бесконечные произведения:


 x 2 
x2 
x2  
x2 
...

1

1) sin x  x   1  2 2   x 1  2  1 


 ...,
    4 2   n2 2 
n  
n1 





x2


.
2) cos x   1 
2
2
n

1
n1


 
  
 
  2
Составьте программы вычисления этих произведений и вычислите значения sinx и
cosx с заданной точностью.
207. Дано натуральное n. Получить:
1 
1 
1
1 
1 
1


а) 1  n   1  n ...1  n  ,
б) 1  1   1  2 ...1  n  ,
 1   2   n 
 1  2   n 
421

 sin x   sin 2x   sin nx 
в) 1 
  1 
...1 
,

1!  
2!  
n! 
1
 2
  n

г)   cos| x |    cos 2 | x |...
 cos n | x | ,
2
 3
  n 1

 12   22   522 
1 
1 
1 
1

д)  2
  2
... 2
 , е)  2     2     2  ... 2   .

1! 
2 ! 
3 ! 
8 !
 1  3  2  3  52  3
208. Дано натуральное n. Получить f 0  f1 ... f n , где
1
1
1
 2
... 2
, i  0, 1, ..., n.
i 1 i  2
i  i 1
1
ln(1  x )
dx . Использовать разложение в логариф209. Вычислить интеграл I  
x
0
fi 
2
мический ряд.
Ответы
К заданию 1
Program Task1; {Вычисление sinx с помощью ряда}
uses WinCrt;
var
n, k
: integer;
x, e, eps, sin, u : real;
{----------------------------------------------------------------------------------------}
{ Функция вычисления порядка - кол-во знаков после запятой }
Function t(eps : real) : integer;
var
k : integer;
begin
k := -1;
repeat
eps := eps*10;
k := k + 1
until eps > 1;
t := k
end;
{----------------------------------------------------------------------------------------}
begin
write('Задайте точность вычисления '); readln(eps);
write('Введите значение аргумента в радианах '); readln(x);
u := x; n := 2;
sin := x;
repeat
u := -u*x*x/((2*n-1)*(2*n-2));
sin := sin + u;
n := n + 1
until abs(u) < eps;
write('Значение sin( ', x:1:t(eps), ' ) равно ', sin:3:t(eps));
writeln(' с точностью до ', eps:1:t(eps))
end.
422 
К заданию 2
Program Task2;
uses WinCrt;
var
n
: integer;
p, u, eps : real;
{----------------------------------------------------------------------------------------}
{ Функция вычисления порядка - кол-во знаков после запятой }
Function t(eps : real) : integer;
var
k : integer;
begin
k := -1;
repeat
eps := eps*10;
k := k + 1
until eps > 1;
t := k
end;
{----------------------------------------------------------------------------------------}
begin
write('Укажите точность вычисления числа пи '); readln(eps);
u := 1; p := 0; n := 1;
repeat
p := p + u;
n := n + 1;
u := -u*(2*n - 3)/(2*n - 1)
until abs(u) < eps;
write('Число Пи равно ', 4*p:1:t(eps), ' с точностью до ');
writeln(eps:1:t(eps))
end.
К заданию 3
Program Task3;
uses WinCrt;
var
k
: integer;
a, u, z, z1, e, eps : real;
{----------------------------------------------------------------------------------------}
{ Функция вычисления порядка - кол-во знаков после запятой }
Function t(eps : real) : integer;
var
k : integer;
begin
k := -1;
repeat
eps := eps*10;
k := k + 1
until eps > 1;
t := k
end;
423

{----------------------------------------------------------------------------------------}
begin
write('Введите значение a>1 '); readln(a);
write('Задайте точность eps '); readln(eps);
u := 1; z := 0;
repeat
u := u*a;
z := z + 1/(1 + u);
z1 := z + 1/(1 + u*a)
until abs(z1 - z) < eps;
write('Сумма ряда равна ', z1:1:t(eps));
writeln(' с точностью до ', eps:1:t(eps))
end.
К заданию 4
Program Task4;
uses WinCrt;
n : integer;
var
a : longint;
{----------------------------------------------------------------------------------------}
Function c(a : integer) : longint;
var
s, z : integer;
begin
z := 0;
repeat
s := a mod 10;
z := z + s;
a := a div 10
until s = 0;
c := z
end;
{----------------------------------------------------------------------------------------}
begin
a := 7;
n := 1;
while n <= 1000 do
begin
a := c(a*a);
n := n + 1
end;
writeln(n - 1, '-й член последовательности равен ', a)
end.
424 
Литература
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
Абрамов С.А., Зима Е.В. Начала информатики. - М.: Наука. Гл. ред. физ.-мат.
лит., 1989.
Брудно А.Л., Каплвн Л.И. Московские олимпиады по программированию/Под
ред. акад. Б.Н. Наумова. - 2-е изд., доп. и перераб. - М.: Наука. Гл. ред. физ.мат. лит., 1990.
Васильев Н. Б., Гутенмахер В.Л., Раббот Ж.М., Тоом А.Л. Заочные математические олимпиады. - 2-е изд., перераб. - М.: Наука. Гл. ред. физ.-мат. лит., 1997.
Васюкова Н.Д., Тюляева В.В. Практикум по основам программирования. Язык
ПАСКАЛЬ: Учеб. пособие для учащихся сред. спец. учеб. заведений. - М.:
Высш. шк., 1991.
Дагене В.А. и др. 100 задач по программированию: Кн. для учащихся: Пер. с
лит./В.А. Дагене, Г.К. Григас, К.Ф. Аугутис. - М.: Просвещение, 1993.
Джонс Ж., Харроу К. Решение задач в системе Турбо Паскаль/Пер. с англ.;
Предисл. Ю.П. Широкого. - М.: Финансы и статистика, 1991.
Епанешников А., Епанешников В. Программирование в среде Turbo Pascal 7.0.
- м.: "ДИАЛОГ-МИФИ", 1993.
Есаян В.И. Ефимов, Л.П. Лапицкая и др Информатика. Учеб. пособие. для пед.
спец. высш. учеб. заведений/А. Р.. - М.: Просвещение, 1991.
Журналы "Информатика и образования", 1986-1994 гг. 17. Журналы "Квант",
1986-1994 гг.
Заварыкин В. М. и др. Численные методы: Учеб. пособие для студентов физ.мат. спец. пед. ин-тов/В.М. Заворыкин, В.Г. Житомирский, М.П. Лапчик. - М.:
Просвещение, 1990.
Зубов В. С. Программирование на языке Turbo Pascal. "Фтлинъ". Москва.
1997г.
Офицеров Д.В., Старых В.А. Программирование в интегрированной среде Турбо-Паскаль: Справ. пособие. - Мн.: Беларусь, 1992.
Очков В. Ф., Пухначев Ю.В. 128 советов начинающему программисту. - М.:
Энергоатомиздат, 1991.
Перминов О. Н. Программирование на языке Паскаль. "Радио и связь". Москва,
1988 г.
Скопец и др. Дополнительные главы по курсу математики. Учеб. пособие по
факультативному курсу для учащихся 10 кл. Сборник статей. Сост. З.А.. Изд.
2-е, перераб. М., "Просвещение", 1974.
Тарасов Л.В. Мир, построенный на вероятности: Кн. для учащихся. - М.: Просвещение, 1984.
Тумасонис В., Дагене В., Григас Г. Паскаль. Руководства для программиста:
Справочник: Пер. с литовск. - М.: Радио и связь, 1992.
Фаронов В. В. Турбо Паскаль (в 3-х книга). Книга 1. Основы Турбо Паскаля. М.: Учебно-инженерный центр "МВТУ-ФЕСТО ДИДАКТИК", 1992.
Федоров А., Рогатин Д. Borland Pascal в среде Windows. "Диалектика", Киев,
1993 г.
Download