
Зубенко, Омельчук - Програмування. Поглиблений курс
.pdf
Розділ ІІ. ЕЛЕМЕНТИ ІНФОРМАТИКИ
i
Hi = Σ 1/i , i ≥1, задаються системою рекурентних співвідношень
k =1
(*) H1 =1,Hi = Hi −1 +1/((i −1) +1);
i − лічильник, i1 =1.
Конструктором першої послідовності є операція f (x,y) = x +1/(y +1) . За означенням H 2 = H1 +1/(i1 +1) =1+1/2 = 3/2 , i2 = 2 тощо ■
2.5.3. РЕКУРЕНТНІ ФУНКЦІЇ
З кожною рекурентною системою послідовностей (*) виміру n по- в'язана певна функція F типу T n ×N → T n , яка вектору α = (a0,b0,...)
початкових членів і числу i ≥ 0 ставить у відповідність вектор з і-х членів даних послідовностей:
def
F (α,i ) = αi , де αi = (ai ,bi ,...).
Щоб знайти значення функції F (α,m) для довільного m ≥ 0 , доста- тньо послідовно побудувати всі попередні значення F (α,i ), i =1,m −1.
Зазвичай для фіксованого початкового вектора α інтерес становлять не всі значення функції F – члени послідовності αi ,i ≥ 0 , а лише виді-
лені, і найчастіше – лише одне. Щоб відокремити потрібне значення, або прямо задають його конкретний номер, або його виділяють неявно за
допомогою умови-фільтра Q типу T n → Bool . Щоб такий вибір був од- нозначним, обмежуються, наприклад, першим з αi , що задовольняє (порушує) фільтр. Якщо всі αi порушують (задовольняють) Q , то резуль- тат вибору конкретного значення на даному вході α буде невизначе- ний. Далі вважається, що вибирається перше з αi , на якому порушуєть-
ся умова. Позначимо нову функцію μQ(*) і назвемо її рекурентною, поро- дженою системою (*) і фільтром Q . Вона є частковою й має тип T n → T n . Композицію, визначену на конструкторах системи (*) і фільтрі Q , результатом якої є функція μQ(*) , назвемо μ -оператором.
На практиці можуть варіюватися початкові значення тільки окре- мих із n аргументів рекурентної функції, а решта відіграють роль параметрів – вони або просто фіксуються, або відразу обчислюються
201

ПРОГРАМУВАННЯ
за допомогою конструкторів. Перші називаються вхідними парамет- рами, або входами, рекурентної функції. Цікавими з погляду резуль- татів можуть бути не всі компоненти в значенні рекурентної функції, а тільки окремі з них – вихідні. Послідовності, що відповідають вихід- ним компонентам, називаються опорними в рекурентній системі. По- слідовності, що не належать ні до вхідних, ні до опорних, називають- ся проміжними, або робочими. Нехай m та r – кількість відповідно
вхідних і опорних послідовностей. Рекурентні функції μQ(*) : T m → T r із
виділеними сукупностями вхідних і опорних послідовностей назива-
ються параметризованими.
Наведемо кілька прикладів параметризованих рекурентних функцій. Приклад 2.24. n -й член арифметичної прогресії.
Нехай a1 ,a2,... – арифметична прогресія з певною фіксованою різ- ницею d і початковим членом a1 = a . Позначимо an n -й член арифме-
тичної прогресії. Розглянемо систему (*) із трьох рекурентних послідов- ностей: арифметичної прогресії ak , послідовності-константи n і лічиль-
ника i з початковим значенням 1. |
Візьмемо за фільтр умову |
Q (i,n ) = i < n , за вхідні послідовності – n |
і прогресію ak , за опорну – |
прогресію ak . Тоді an збігається зі значенням μQ(*)(a,n) . Коректність та-
кого подання an випливає з того, що лічильник із початковим значен-
ням 1 стає перший раз хибним саме на n -му кроці, тобто при k = n ■ Приклад 2.25. Гармонічна функція.
Гармонічна функція задає n -те гармонічне число Hn і є рекурен- тною функцією μQ(*) , породженою фільтром Q (i,n ) = i < n і системою
рекурентних співвідношень (*):
H1 =1,Hi = Hi −1 +1/i;
i − лічильник, i1 =1;n − константа.
Вхідною послідовністю є n , а вихідною – Hi ■
Нехай m − певне фіксоване натуральне число. Послідовності
a1,a2,... Tb1,b2,... T...
202

Розділ ІІ. ЕЛЕМЕНТИ ІНФОРМАТИКИ
називаються m -рекурентними відносно конструкторів f ,g,..., якщо всі їхні члени для i ≥ m +1 пов'язані співвідношеннями
(**)ai = f (ai −1,ai −2,...,ai −m ,bi −1,bi −2,...,bi −m ,...),
bi = g (ai −1,ai −2,...,ai −m ,bi −1,bi −2,...,bi −m ,...), … .
Щоб повністю задати таку систему послідовностей, достатньо зада- ти перші m членів кожної послідовності a1 ,a2,...,am ,b1,b2,...bm ,.... Ре- шту знаходять за допомогою конструкторів. Наприклад, для 2-рекурентної послідовності a3 = f1 (a1,a2,b1,b2,...), b3 = f2 (a1,a2,b1,b2,...) тощо m -рекурентні послідовності можуть індексуватися і з 0. Відо-
мий приклад 2-рекурентної послідовності – числа Фібоначчі ■ |
|
|||
Приклад 2.26. Числа Фібоначчі. |
|
|
||
За |
означенням |
f0 = f1 =1, fk = fk −2 + fk −1 , |
k ≥ 2 , |
тоді |
f2 = f0 + f1 =1+1 = 2 , f3 = f1 + f2 =1+ 2 = 3 , f4 = f2 + f3 = 2 + 3 = 5 тощо ■
Для m -рекурентних |
послідовностей |
теж вводиться поняття |
m -рекурентної функції |
μ(*) та μ -оператора. Конструкція аналогічна |
|
|
Q |
має тип (T m )n → T n . |
вищенаведеній, m -рекурентна функція μQ(*) |
Теорема 2.5 (про обчислення m -рекурентних функцій). Парамет- ризовані m -рекурентні функції, і тільки вони, обчислюються детермі- нованими стандартними програмами.
Доведення. Обмежимося доведенням тільки для випадку непараме- тризованих функцій і програм. Доведення в загальному випадку сут- тєво не зміниться (див. вправу 12). Нехай на універсумі T задано до- вільну непараметризовану m -рекурентну систему (*) виміру n і
фільтр Q : T n → Bool . Покажемо, як за допомогою стандартної про- грами обчислити m -рекурентну функцію μQ(*) .
Розглянемо спочатку для простоти випадок m =1. Для кожної з n рекурентних послідовностей введемо змінну типу T та її дублікат.
Нехай |
V ={x,xx,…,z,zz} |
– сукупність усіх 2n таких змінних, де |
xx,…,zz |
– дублікати відповідних змінних. Тоді стандартна програма |
|
Prog має вигляд: |
|
|
/*Вх: x,…,z; |
Вих: x,…,z*/ |
|
{x:=a1 ;… z:=b1 ; |
|
203

ПРОГРАМУВАННЯ
while (Q(x,...,z)) do
{ /*обчислення нових значень змінних*/ xx:=f(x,...,z);
…
zz:=g (x,..,z); /*оновлення змінних*/
x:=xx;
…
z:=zz;
}
}
Присвоювання перед циклом початкових значень змінним назива- ється їх ініціалізацією. Чергові нові члени рекурентних послідовностей спочатку зберігаються в дублікатах xx,…,zz, і тільки після цього пере- силаються в змінні x,…,z. Якщо відразу їх записати в змінні, то будуть втрачені попередні значення, від яких може залежати обчислення но-
вих значень у сусідніх послідовностях. Позначимо Prog векторний аналог програми Prog. У нашому випадку тип Prog збігається з T n → T n . Покажемо, що Prog (α ) = μQ(*) (α ) для будь-якого набору по-
чаткових значень α = (a ,b ,...) із T n . Нехай |
|
(α) = (a,b,...). Це озна- |
|||||||
Prog |
|||||||||
|
|
|
1 |
1 |
|
|
|
|
|
чає, |
що |
існують |
таке k ≥1 |
і |
такі |
послідовності значень |
|||
′ |
′ |
′ |
|
|
′ |
|
′ |
|
′ |
a1(= a1),a2 |
,...,ak (= a) |
змінної x тощо b1(= b1),b2 |
,...,bk (= b) змінної z, що |
||||||
(i) i =1,...,k −1 Q(ai′,...,bi′) =1; (ii) Q(ak′ ,...,bk′ ) = 0 . |
|||||||||
За побудовою для всіх 1 ≤ i ≤ k |
значення вектора αi′ = (ai′,bi′,...) збі- |
гається зі значенням функції F (α,i ), породженої даною системою ре- курентних співвідношень. Однак з умов (і) та (іі) випливає: k є най- меншим індексом таким, що Q(ak′ ,...,bk′ ) = 0 , тобто μQ(*) (α ) = αk =
= Prog (α), що й треба було довести.
Аналогічно будується стандартна програма Prog для m -рекурентних функцій. Тільки в цьому разі необхідно зберігати m останніх членів кожної з n m -рекурентних послідовностей. Для цього необхідно ввести n ×m змінних, а також, як і вище, ще n змінних для обчислення нових членів послідовностей. У тілі циклу після визначен- ня нових членів необхідно поновити значення всіх n ×m змінних.
Нехай тепер маємо певну стандартну непараметризовану детермі- новану програму Prog.
204

Розділ ІІ. ЕЛЕМЕНТИ ІНФОРМАТИКИ
Покажемо: якщо її складові обчислюють рекурентні функції, то й вона робить те саме. Знову припустимо, що m =1. Для m >1 доведен- ня буде аналогічним. Нехай складовими програми Prog є програми Prog1 ,…, Progn з однаковими сукупностями змінних такі, що
|
|
= μ(*k ) ,k = |
|
для певних рекурентних систем |
Prog |
k |
1,n |
||
|
Q |
|||
|
|
k |
( *k ) ai = f (k )(ai −1,bi −1,...), bi = g(k )(ai −1,bi −1,...), ..., i ≥ 2
і фільтрів Qk . Потрібно за ними побудувати рекурентну систему (*)
ai |
= f (ai −1,bi −1,...), bi = g(ai −1,bi −1,...), ..., i ≥ 2 , і |
визначити фільтр S |
|||
так, щоб |
|
= μ(*) . |
|
|
|
Prog |
|
|
|||
|
|
|
S |
|
|
|
1) Нехай програма Prog складена: {Prog1Prog2 } . Визначимо додатко- |
||||
ву |
|
рекурентну |
послідовність: |
r1 = Q1(a1,b1,...) , |
ri = (ri −1 = 0 → ri −1 | Q1(ai ,bi ,...), i ≥ 2 , для контролю за перебуванням обчи- слення в просторі систем (*1 ) та (*2 ), а саме: ri =1 означає, що викону-
ється Prog1 , у протилежному випадку – Prog 2 . Система (*) складається з
послідовності ri і послідовностей систем (*1 ) |
|
та (*2 ), об'єднаних в одну |
||||||||||
рекурентну систему такими умовними конструкторами: |
||||||||||||
a |
i |
= (r |
=1 → f (1)(a |
i −1 |
,b |
,...)| f (2)(a |
i −1 |
,b |
|
,...)),i ≥ 2 |
||
|
i −1 |
|
i −1 |
|
|
i −1 |
|
|||||
b = (r |
=1 → g(1)(a |
i −1 |
,b |
,...)|g(2)(a |
i −1 |
,b |
,...)),i ≥ 2 |
|||||
|
i |
i −1 |
|
i −1 |
|
|
i −1 |
|
|
…
.
Візьмемо за фільтр S = (r =1 Q2 ). За побудовою система (*) і фільтр
Sє шуканими.
2)Нехай програма Prog є розгалуженням if (C ) Prog1 else Prog 2 .
Введемо додаткову контролюючу послідовність r1 = C (a1,b1,...), де C – векторний аналог умови С, ri = ri −1 , i ≥ 2 , смисл якої той самий, що й у п. 1). Відмінність полягає в тому, що тут ri є константою. Рекурент- ною системою (*) для програми Prog теж буде об'єднання відповідних систем ( *1 ) та ( *2 ) із доданою послідовністю ri . Конструктори при цьому отримують охорону – r =1 у системі ( *1 ) та r = 0 у системі ( *2 ) – і стають умовними, а фільтром S буде формула (r =1& Q1 r = 0 & Q2 ).
205

ПРОГРАМУВАННЯ
3) Аналогічно будується рекурентна система послідовностей для ви- падку, коли програма Prog є обходом (частковий випадок розгалужен- ня) і вибором. Зазначимо, що охорони у виборі попарно не перетина- ються (умова детермінованості Prog). Тоді, як і у 2), для кожної з альте- рнатив у систему (*) вводиться своя контролююча послідовність
ri(k ) ,k =1,n , конструктори мають відповідну охорону, а фільтр S – це
диз'юнкція всіх формул вигляду (r(k ) =1& Qk ) , k =1,n , що відповідають контролюючим послідовностям і фільтрам складових програми Prog.
4)Нехай тепер програма Prog є ітерацією while (С) do Prog1 . Систе- ма (*) буде збігатися з такою для випадку обходу, а фільтр S – це фо- рмула Q1 ¬Q1 & C , де C – векторний аналог умови С.
5)Випадок, коли програма Prog є повторенням вигляду do Prog1
while (Q), зводиться до вже розглянутих, оскільки така програма збі-
гається з програмою {Prog1 while (Q) do Prog1 } ■
Увага! Рекурентні співвідношення (*) та (**) в означенні рекурент- них і m -рекурентних послідовностей задають тільки загальний ви- гляд взаємозв'язку між такими послідовностями. У багатьох випад- ках цей зв'язок виявляється досить простим. Зокрема, члени реку- рентних послідовностей зазвичай залежать не від усіх, а тільки від окремих сусідів. Це дозволяє в програмах для рекурентних функцій шляхом підбору порядку оновлення змінних уникнути дублювання нових членів (усіх чи частини), а отже, і введення змінних-дублікатів (див. прикл. 2.27-2.32). Якщо ж член рекурентної послідовності не залежить від своїх попередників, то немає потреби задавати почат- ковий член для даної послідовності ►
2.5.4. ТЕХНІКА ПОБУДОВИ СТАНДАРТНИХ ПРОГРАМ
Теорема 2.1 відкриває універсальний шлях до побудови стандарт- ної програми, яка обчислює задану залежність між величинами, а са- ме: спочатку необхідно специфікувати дану залежність як m -рекурентну за допомогою відповідного μ -оператора, а потім за
нею побудувати стандартну програму. При цьому теорему можна уза- гальнити й використовувати як конструктори будь-які похідні опера- ції та предикати базової алгебри. На практиці найчастіше це – скла- дені й умовні операції.
206

Розділ ІІ. ЕЛЕМЕНТИ ІНФОРМАТИКИ
Проілюструємо дану техніку на прикладах із різних предметних областей.
Приклад 2.27. Для даних x R , n N обчислити суму sin x + sin x2 + ... + sin xn .
Аналіз.
Вхід: x R , n N . Вихід: s R .
Залежність: s = ∑n sin xi .
i =1
Вимоги: побудувати стандартну програму (Prog9.7) для обчислення s . Базовою Ω -системою є дійсна й натуральна арифметики з операціями та предикатами + , –, *, /, %, =, <, до яких додано функцію sin.
Проектування. Побудувати стандартну програму для обчислення s означає побудувати таку програму, параметризований векторний аналог якої буде повертати як результат s . Побудуємо
1-рекурентну функцію μQ(*) для обчислення s , конструктори якої є по-
хідними операціями базової Ω -системи, і застосуємо до неї теоре- му 2.5. Ураховуючи, що сума s залежить від входів x та n , додамо до системи (*) вхідні послідовності-константи n та x і опорну послі-
довність s1 ,s2,...,sn ,sn +1,.... Спробуємо побудувати систему так, щоб
s = s . Оскільки s |
n |
k |
, тобто |
|
= ∑ sin xi , то покладемо s |
= ∑ sin xi , k ≥1 |
|||
n |
n |
k |
i =1 |
|
|
|
i =1 |
|
|
за члени sk |
виберемо часткові суми перших k |
доданків суми s . Для |
рекурентності послідовності sk необхідно знайти залежність суми sk
від |
попередньої |
суми sk −1. |
Ця залежність має |
вигляд |
||||
s |
= s |
+ sin(xk ). Оскільки операція додавання й функція sin |
є при- |
|||||
k |
k −1 |
|
|
|
|
|
|
|
пустимими, |
то псує дану рекурентну залежність тільки степінь xk . |
|||||||
Уведемо |
в |
систему |
допоміжну |
рекурентну послідовність |
a |
k |
= xk , |
|
|
|
|
|
|
|
|
|
a1 = x , ak = ak −1 * x . Тоді sk = sk −1 + sin(ak ) і конструктор праворуч уже є припустимим. Щоб вибрати саме n -й член опорної послідовності, додамо до системи лічильник k,k =1. Тоді за фільтр Q можна взяти
умову Q(k,n) = k < n . Дійсно, для 1 ≤ k ≤ n −1 Q(k,n) =1 та Q(n,n) = 0 . Таким чином, побудована система (*) має вигляд
207

ПРОГРАМУВАННЯ
a1 = x,ak = ak −1 * x;
s1 = sin(x),sk = sk −1 +ak ;
k − лiчильник,k1 =1;n − константа;
x − константа.
За побудовою s = μQ* (n,x) .
Кодування. Нехай ініціалізація вигляду v:=! означає присвоювання змінній v довільного припустимого значення. Для послідовностей систе- ми виберемо змінні з найменуваннями відповідно a,s,k,n,x. Серед них n, x – вхідні, s – вихідна, а a, k – робочі змінні. Програма Prog9.7:
Лістинг.
/*Вх: x,n Вих: s */
{x:=!; n:=!;s:=sin(x); k:=1; a:=x; while (i<n) {a:=a*x;
s:=s+sin(a);
k:=k+1;
}
}
Структура програми Prog9.7 вимагає пояснення, оскільки відрізня- ється від стандартної, застосованої в доведенні теореми 2.5. Як бачимо, член sk залежить від sk −1 та ak (ak = ak −1 * x ) і не залежить від лічиль-
ника k , а член ak і лічильник k залежать тільки від своїх попередників ak та k −1 і не залежать від інших послідовностей. Вибраний порядок
зміни значень змінних забезпечує коректне їхнє оновлення й дозволяє не вводити в програмі Prog9.7 відповідні дублікати-змінні ■
Приклад 2.28. Знайти n -те число Фібоначчі, n ≥ 0 (див. прикл. 2.26).
Аналіз.
Вхід: n N . Вихід: f N .
Залежність: f = fn , де f0 = f1 =1, fi = fi −1 + fi =2 , i >1.
Вимоги: побудувати стандартну програму Prog9.8 для обчислення f . Базовою Ω -системою є натуральна арифметика зі стандартними
операціями та предикатами: + , –, *, /, %, =, <.
Проектування. Маємо послідовності: опорну fi та gi = fi −1 і послі- довність-константу n . Щоб вибрати саме n -й член опорної послідов-
208

Розділ ІІ. ЕЛЕМЕНТИ ІНФОРМАТИКИ
ності, введемо до системи лічильник i з початковим значенням 2. То- ді за фільтр Q можна взяти умову i < n . Таким чином, побудована
система (*) має вигляд:
f0 = f1 =1, fi = fi −1 + gi −1,i ≥ 2;
g1 =1,gi = fi −1,i ≥ 2;i1 = 2,i = (i −1) +1;
n − константа. За побудовою fn = μQ(*) (n).
Кодування. Виберемо змінні програми Prog9.8: f,ff,g,i та n. Се- ред них: n – вхідна, f – вихідна, а ff, g та i – робочі змінні. Програ- ма Prog9.8 будується стандартно:
/*Вх: n N |
Вих: f N */ |
{f:=1; g:=1; |
|
i:=2; n:=!; |
|
if (n ≥ 2) |
|
while (i<n) |
|
{i:=i+1; |
|
ff:=f+g; |
|
g:=f; |
|
f:=ff; |
|
} |
|
} |
|
У програмі використано змінну-дублікат ff для змінної f. Якщо |
цього не зробити, то після присвоювання ff:=f+g зникне значення fi −1 , необхідне для оновлення g ■
Приклад 2.29. |
|
Для даних x R , n N обчислити суму |
||
x + x4 + x9 + … + xn2 , уникнувши вкладених циклів. |
||||
Аналіз. |
|
|
|
|
Вхід: x R , n N . |
|
|
|
|
Вихід: s R . |
n |
|
|
|
Залежність: s = |
|
2 |
. |
|
∑ xi |
|
i =1
Вимоги: побудувати стандартну програму Prog9.9 для обчислення s . Базовою Ω-системою є дійсна й натуральна арифметики зі стандарт-
209

ПРОГРАМУВАННЯ
ними операціями та предикатами. Програма не має містити вкладені цикли, тобто цикли, які є в тілі іншого циклу.
|
Проектування. Як і у прикл. 2.27, шукана рекурентна система (*) |
|||||||||||
включає три послідовності: вхідні послідовності – константи n та x |
– |
|||||||||||
і послідовність часткових сум s1 ,s2,...,sn ,sn +1,... |
таку, |
що sn = s . Для |
||||||||||
останньої маємо співвідношення s |
= s |
+ xk2 . |
Уведемо в систему |
|||||||||
|
|
|
k |
k −1 |
|
|
|
|
|
|
|
|
допоміжну послідовність |
a = xk2 . |
Тоді |
s |
= s |
|
+a |
k |
і |
a = x |
та |
||
|
|
|
k |
|
k |
k −1 |
|
|
1 |
|
||
a |
= a |
* x2k −1 , k >1. Дійсно, якщо поділити a |
на a |
−1 |
, то отримає- |
|||||||
k |
k −1 |
|
|
|
|
k |
|
k |
|
|
|
мо саме x2k −1 . Знову конструктор містить піднесення до степеня та є неприпустимим у базовій алгебрі. Тому необхідно ввести ще одну до-
даткову |
послідовність b = x2k −1 |
, |
k ≥1. Маємо a = a |
k −1 |
* b , |
|
|
|
k |
|
k |
k |
|
b |
= b |
× x2,b = x. Як бачимо, остання послідовність рекурентна з |
||||
k |
k −1 |
1 |
|
|
|
|
конструкторами – похідними операціями базової алгебри. Отже, по- будована система (*) має вигляд:
a1 = x,ak = ak −1 * bk ; |
||||
b = x,b = b |
* x2; |
|||
|
1 |
k |
k −1 |
|
|
|
= x,s = s |
+a ; |
|
s |
||||
|
1 |
k |
k −1 |
k |
k − лічильник,k1 =1; |
||||
n − константа; |
|
|||
|
|
− константа. |
|
|
x |
|
|||
|
|
|
|
|
За побудовою s = μQ* (n,x) .
Кодування. Змінні програми Prog9.9: a,b,s,k,n та x – без дублікатів.
{n:=!; x:=!;k:=1;s:=a:=b:=x; while (i<n) {B:=B*X*X; A:=A*B;
S:=S+A;
K:=K+1;
}
} ■
Приклад 2.30. Наближено обчислити суму ∑∞ (−1)[lg k ] /k . До кінце-
k =1
вої часткової суми додаються тільки члени, які за модулем строго бі- льші заданого ε > 0 . При цьому слід уникати вкладених циклів.
210