Сторінка
3
static var V : integer. У діалекті Турбо Паскаль локальну статичну змінну задає означення з ініціалізацією (п.2.3.6), записане в підпрограмі. Нагадаємо його дещо дивний вигляд:
const ім'я : тип = ініціалізуюче-значення; З ним наша функція виглядає так:
function NextRand : integer;
const V : integer = 0; const m=1001; a=21; c=57;
begin V := ( a*V+ c ) mod m; NextRand := V
end; Як видно, першим псевдовипадковим числом завжди буде 0. Але в задачі було потрібно, щоб перше число надходило "із зовнішнього світу". Змінимо функцію так, що при виконанні її першого виклику відбувається запит на введення першого числа з клавіатури, а при наступних – обчислення за рекурентним співвідношенням:
function NextRand : integer;
const V : integer = 0; First : Boolean = true;
const m=1001; a=21; c=57;
function Rand1: integer;
var t : integer;
begin
write('Задайте ціле від 0 до ', m-1, '>'); readln(t);
Rand1 := t
end;
begin if First then
begin First := false; V := Rand1 end else V := ( a*V+ c ) mod m;
NextRand := V
end; Тепер можна записувати цю функцію та її виклики в програмах, де потрібно імітувати появу випадкових чисел. Проте краще помістити цю функцію в модуль (п.7.2 ) з ім'ям, наприклад, Randoms, транслювати його та у програмі вказувати лише його використання: uses Randoms. Використання модулів дозволяє розв'язати нашу задачу взагалі без використання локальних статичних змінних. Справа в тім, що змінні, означені в модулі, як і змінні програми, є статичними. Тому модуль можна записати в такому вигляді: Unit Randoms; Interface function NextRand : integer; Implementation const m=1001; a=21; c=57; var V : integer; First : Boolean;
function Rand1: integer;
var t : integer;
begin
write('Задайте ціле від 0 до ', m-1, '>'); readln(t);
Rand1 := t
end;
function NextRand;
begin if First then begin First := false; V := Rand1 end else V := ( a*V+ c ) mod m;
NextRand := V
end; Begin First := true End. Як бачимо, змінні V та First стали глобальними в модулі і доступними в його підпрограмах, але за його межами їх "не видно". Можна сказати, що їх означення локалізовані в модулі. Задачі 2. Переробити модуль Randoms так, щоб він задавав породження псевдовипадкової послідовності а) дійсних чисел з проміжку [0; 1]; б) дійсних чисел з проміжку [c; d]. 3. Переробити модуль Randoms так, щоб зовні його можна було використовувати функцію Rand1. Написати програму обчислення середнього арифметичного значення M та дисперсії D псевдовипадкової послідовності дійсних чисел {Xi} з проміжку [0;1]. Дисперсія – це середнє арифметичне квадратів різниць між числами та M: D = ( ( X1 - M )2 + … + ( XN - M )2 )/N, де N – загальна кількість елементів. Добрий генератор має давати значення M і D, близькі до 1/2 та 1/12 відповідно. Але не всякий генератор, що дає такі середнє значення та дисперсію, є добрим. 4. Площу S двовимірної геометричної фігури обмежених розмірів можна обчислити в такий спосіб. Розташувати фігуру всередині іншої, площа S2 якої обчислюється досить просто за формулами. Нею, як правило, є прямокутник у декартовій системі координат. Вибрати довільно N точок із другої фігури, указуючи їхні координати, та обчислити кількість K тих із них, що належать першій фігурі. Відношення K/N буде наближенням до S/S2. Координати точок обчислюються за допомогою випадкових чисел, тому цей спосіб називається методом Монте-Карло – за назвою курорту, де грали в рулетку. Написати програму обчислення за методом Монте-Карло наближення до площі кола, заданого координатами центру та радіусом. 5. Реалізувати генератор псевдовипадкових чисел, оснований на рекурентному співвідношенні Vi=(a*Vi-1+b*Vi-2+c) mod m. Перші два значення V1 і V2 задаються випадково. Параметри підібрати самостійно. Використати генератор в задачах 8.3–8.4.
7. Підпрограми як параметри У мові Паскаль параметрами підпрограм можуть бути не тільки змінні, але й підпрограми. Розглянемо приклад. Нам потрібно надрукувати три таблиці значень трьох математичних функцій на заданому відрізку [a; b], де a>0, у точках, розташованих із заданим кроком h. Функції такі:
sh(x) = (ex-e-x)/2, ch(x) = (ex+e-x)/2,
th(x) = (ex-e-x)/(ex+e-x) = (e2x-1)/(e2x+1) . У програмі можна записати функції з іменами sh, ch і th, що задають необхідні обчислення, та означити змінні a, b, h, n, k, x. Тоді оператори тіла програми можуть мати такий вигляд: Readln(a, b, h); n:= trunc((b-a)/h); for k:=0 to n do
begin x:=a+k*h; writeln(x, ' ', sh(x)) end; for k:=0 to n do
begin x:=a+k*h; writeln(x, ' ', ch(x)) end; for k:=0 to n do
begin x:=a+k*h; writeln(x, ' ', th(x)) end; Достатньо нудно. Якби в нас була підпрограма (процедура) з ім'ям tabf, параметризована не тільки відрізком і відстанню між точками, але також і функцією, то замість трьох циклів достатньо було б написати лише tabf(sh, a, b, h); tabf(ch, a, b, h); tabf(th, a, b, h); Займемося написанням процедури tabf. Нехай f буде ім'ям параметра, що позначає функцію, яка табулюється; імена й зміст інших параметрів очевидні. Для початку маємо procedure tabf( означення параметра f; a, b, h : real); var k, n : integer; x : real; begin n := trunc((b-a)/h); for k:=0 to n do
begin x:=a+k*h; writeln(x, ' ', f(x)) end; end; Уточнимо тепер означення параметра f. У стандарті мови Паскаль воно мало б вигляд заголовка функції, ім'я параметра в якій не має значення, наприклад,