7.3 Органiзацiя рекурсii при рiшеннi завдань, що використають iм'я функцiї як аргумент iншої функцiї
Розглянемо органiзацiю таких рекурсивних обчислень на прикладi рiшення приведеного нижче завдання.
Методом дiления вiдрiзка навпiл знайти с точнiстю eps корiнь рiвняння f(x)=0 на вiдрiзку [a,b]. Вирiшити цим методом рiвняння x2-2x-5=0 та sin(2x-3)=0.
Якщо для рiвняння f(x)=0 визначено iнтервал iзоляцiї кореня (деякий iнтервал, на якому рiвно один корiнь цього рiвняння), то знаходження кореня зводиться до такого алгоритму.
Крок 1. Вiдрiзок [a, b] дiлиться навпiл.
Крок 2. Якщо значення функцiї f(x) на кiнцях цього вiдрiзкку розрiзняються менш, чим на eps, то як корень вхiдного рiвняння приймається обчислена середина вiдрiзка [a, b].
Крок 3. В противному випадку аналiзується, в якiй половинi цього вiдрiзка (лiвiй чи правiй) пiсля дiлення залишається корень.
Крок 4. Пошук кореня триває вiдповiдно в отiй половинi вiдрiзка, на кiнцях якого функцiя f(x) має рiзнi знаки.
Цей алгоритм може бути застосований до рiшення алгебраїчних i трансцендентних рiвнянь рiзноманiтної складностi. Тому необхiдно обрати структуру даних для подання виду вiдповiдного рiвняння.
Такою структурою даних в алгоритмiчних мовах виступає функцiя, аргумент якої вiдповiдає змiннiй рiвняння, а вираз, який визначає значення, що вертається функцiєю, вiдповiдає лiвiй частинi рiвняння f(x)=0.
При рiшеннi рiзноманiтних рiвнянь треба передавати iмена функцiй, вiдповiдних цим рiвнянням, аргументом в функцiю знаходження кореня за методом половинного дiлення.
7.3.1 Постановка завдання
7.3.1.1 Вхiднi данi
a, b: дiйснi; {iнтервал iзоляцiї кореня рiвняння f(x)=0 }
f1, f2.. fn: функцiї; {функцiї, вiдповiднi обчисленню
значення f по значенню аргументу x}
eps: дiйсне; {точнiсть обчислення кореня рiвняння}
7.3.1.2 Обмеження
f1(a)*f1(b) < 0 {[a, b] - це iнтервал iзоляцiї коренiв
f2(a)*f2(b) < 0 ... рiвнянь f1(x)=0, ... fn(x)=0 }
fn(a)*fn(b) < 0
7.3.1.3 Результати
x: дiйсне; {корiнь рiвняння f(x)=0}
повiд: рядок[1..20]; {рядок-повiдомлення}
7.3.1.4 Зв’язок
Алгоритм вирiшення рiвняння приведений в п.7.3.
-
Текст програми на мовi Сi
#include <stdio.h>
#include <conio.h>
#include <math.h>
/* ================= ВХIДНI ДАНI ================= */
float eps; /* точнiсть обчислення кореня рiвняння */
/* ================= РЕЗУЛЬТАТ ================= */
float xx; /* корень рiвняння f(x)=0 */
/* вхiднi данi: функцiї, вiдповiднi рiвнянням, що вирiшуються */
float f1(float x)
{ return(x*x-2*x-5);}
float f2(float x)
{ return(sin(2*x-3));}
/* == функцiя вирiшення рiвняння за методом половинного дiлення == */
void root(float a, float b, float f(float))
{ float c; /* середина поточного iнтервала, що дослiджується */
/* ====== ЧАСТИНА АЛГОРИТМА, ЩО ВИКОНУЄТЬСЯ ======*/
if(f(a)*f(b) <=0) /* перевiрка обмежень */
{ c=(a+b)/2;
if (fabs ((double)(f(a)-f(b))) < (double)eps)
xx = c;
else
if(f(c)*f(b)>0.0)
root(a, c, f ); /* пошук в правiй половинi iнтервалу */
else
if(f(a)*f(c)>0.0)
root(c, b, f ); /* пошук в лiвiй половинi iнтервалу */
}
else
{ printf("Коренiв на цьому iнтервалi немає !!!\n");
exit(-1);
}
}
main()
{float a, /* === ВХIДНI ДАНI: лiвий кiнець */
b; /* i правий кiнець iнтервалу iзоляцiї кореня */
/* ======= прототип допомiжної функцiї знаходження кореня ======*/
void root (float a, float b, float (*f)(float x) );
clrscr ();
/* ======= ВВЕДЕННЯ ВХIДНИХ ДАНИХ ========= */
printf("Введiть iнтервал iзоляцiї кореня рiвняння:\n");
printf("лiвий кiнець = "); scanf("%f", &a);
printf("правий кiнець = "); scanf("%f", &b);
printf("Введiть точнiсть знаходження кореня рiвняння = ");
scanf("%f", &eps);
/* ======== ВИРIШЕННЯ РIВНЯННЯ x2-2x-5=0 ========*/
root(a, b, f1 );
printf("Корень 1-го рiвняння є "%f \n", xx);
getch();
/* ======== ВИРIШЕННЯ РIВНЯННЯ sin(2x-3)=0 ======*/
root(a, b, f2 );
printf("Корень 1-го рiвняння є "%f \n", xx);
getch();
}
