Algoritmus hledání průsečíku funkce f(x) s osou x metodou půlení intervalu (2019)



Zadání:

Metodou půlení intervalu nalezněte průsečík funkce s osou x. Funkce je daná polynomem.

Je dán interval pro hledání průsečíku. Předpokládáme, že v zadaném intervalu je pouze jeden průsečík. Rozdělení funkce na úseky s jedním průsečíkem by se řešilo jiným algoritmem.
Pro testy použijte funkci f(x)=10*(x-200)3=10x3 - 6000x2 + 1200000x – 80000000.  Počáteční podmínky krajních bodů intervalu pro testy nastavte na -1000 a +1000.


Představu o průběhu funkce lze získat například pomocí online nástroje http://wolframalpha.com .


Popis algoritmu:
Je dána funkce
f(x) a interval <a,b> na ose x, kde a < b. Funkce f() musí mít na intervalu <a,b> právě jeden průsečík s osou x.

1.      Vypočtěte hodnoty funkce f(a) a f(b) v krajních bodech intervalu a, b.

2.      Vypočtěte hodnotu funkce f(xs) v bodě xs = (a+b)/2 (xs je střed intervalu <a,b>).

3.      Je-li délka intervalu menší než zadané číslo Tolerance nebo algoritmus proběhl MAXKROKU krát, výpočet ukončete.

4.      Hodnota xs nahradí ten z původních krajních bodů, jehož funkční hodnota má stejné znaménko. Tím se prohledávaný úsek zmenší na polovinu, přičemž průsečík s osou zůstane mezi krajními body. Má-li hodnota f(xs) stejné znaménko jako hodnota f(a), pak a=xs. V opačném případě b=xs.

5.      Pokračujte opět bodem 1.



Poznámka 1: Vzhledem k tomu, že počítač vždy pracuje s čísly s omezenou přesností, nemusí se ani při teoreticky nekonečném počtu opakování kroků 1 až 4 algoritmu podařit nalézt bod x, kde by f(x) měla přesně hodnotu 0. Proto se musíme spokojit s nalezením bodu x, který je dostatečně blízko skutečnému řešení. Proto se zvolí přesnost Tolerance nalezení hodnoty x od skutečné hodnoty. Potom ukončíme algoritmus, pokud se krajní body intervalu na ose x k sobě přiblíží na hodnotu menší než zvolená Tolerance. Samozřejmě se ukončí při f(x) = 0.

 

Postup řešení:

0.      Vytvořte projekt a v něm soubory mainpul.c, funkcepul.c a funkcepul.h. Soubor mainpul.c bude obsahovat funkci main a volání funkcí ostatních funkcí. Soubor funkcepul.c bude obsahovat funkce popsané v bodech 2 a 3. V souboru funkcepul.h. budou hlavičky funkcí definovaných v souboru funkcepul.c. Hlavičkový soubor ošetřete proti vícenásobnému načtení.

1.      Načtěte ze standardního vstupu koeficienty polynomu 3. řádu (4 koeficienty). Vstup bude mít tvar např. 10;-6000;1200000;-80000000. Koeficienty uložte do pole typu double. Při psaní programu uvažujte možnost snadného rozšíření na polynom N-tého řádu.
Dojde-li k chybě při načítání koeficientů, ukončete program s návratovou hodnotou 1.
Dále načtěte tři čísla. První dvě čísla určující levý resp. pravý okraj intervalu, třetí číslo je hodnota
Tolerance. Čísla jsou opět oddělena znakem středník. Pro ukládání výše uvedených čísel použijte typ double, hodnoty intervalu uložte do pole.
Vhodný vstup je například
-1000;1000;0.1
Dojde-li k chybě při načítání Tolerance, ukončete program s návratovou hodnotou 1.
Budou-li špatně zadány hodnoty okrajů (
a>b), ukončete program s návratovou hodnotou 2.
Bude-li špatně zadán
Tolerance (<=0), ukončete program s návratovou hodnotou 3.
Pro načítání dat použijte funkci
scanf, kontrolujte návratovou hodnotu (počet skutečně načtených parametrů).
Vstupní data nezadávejte ručně z klávesnice, ale postupujte dle poznámky 2.

2.      Napište funkci s prototypem double HodnotaFunkce(unsigned int aRad, double aKoef[], double aX), která vypočte hodnotu polynomu. Např. pro polynom 2. řádu se hodnota polynomu počítá dle vztahu: f(x)=(k[2]*x+k[1])*x+k[0].
Ve funkci main ověřte správné fungování výpočtu pro polynom s koeficienty
10;-6000;1200000;-80000000 voláním s parametry x, které jsou zde uvedeny s výsledky (vstup,vystup): (0,-80000000),(1,-78805990), (-1,-81206010) .
Tuto funkci budou využívat následující funkce.

3.      Napište funkci s prototypem double Prusecik(unsigned int aRad, double aKoef[],double aOkraje[2], double aTolerance). Funkce realizuje výše popsaný algoritmus hledání průsečíku funkce s osou x metodou půlení intervalu. Návratovou hodnotou je nalezený průsečík s osou x.
Ve funkci
main zavolejte tuto funkci a vytiskněte výsledek.

4.      Napište funkci s prototypem double PrusecikRek(unsigned int aRad, double aKoef[],double aOkraje[2], double aTolerance). Funkce realizuje výše popsaný algoritmus hledání průsečíku funkce s osou x metodou půlení intervalu s využitím rekurzivního způsobu výpočtu.
Ve funkci
main zavolejte tuto funkci a vytiskněte výsledek.


DU pro další procvičení:
5. Upravte program tak, aby pracoval pro libovolný řád od 1 do MAXRAD (nastavte jako konstantu pomocí #define, v programu volte hodnotu 10). Jako první tedy načtěte ze vstupu celočíselnou hodnotu – řád polynomu funkce (pro uvedenou funkci tedy hodnotu řádu = 3 (celočíselný typ)). Při hodnotě řádu mimo stanovené meze, vraťte chybový kód 4. Následně načtěte koeficienty funkce, kdy jejich počet musí odpovídat zadanému řádu.

 

Poznámka 2: Jelikož vstup z klávesnice je dosti rozsáhlý, byl by při testování programu problém s neustálým zadáváním hodnot. Proto použijte pro načítání hodnot mechanizmus přesměrování vstupu místo klávesnice ze souboru. Vytvořte si soubor (například vstup.input s daty „ 10;-6000;1200000;-80000000 -1000;1000;0.1“. (Vstupní řetězce z minulých bodů jsou odděleny mezerou)
Pro přesměrování vstupu na soubor se na příkazové řádce používá symbol pro přesměrování „<program.exe < input.stdin. Tento mechanizmus funguje i v ladícím modu. Soubor input.stdin je ovšem nutné umístit do pracovního adresáře, kterým je adresář se zdrojovými texty (standardně by tento soubor byl ve stejném adresáři jako spustitelný soubor). Přesměrování provedeme uvedením textu „<input.stdin“ do parametru argumenty překladače (u projektu volba properties/ configuration properties/ debugging/command arguments).
Bohužel, v současné době daný mechanizmus nezastaví na konci programu, aby bylo možné si prohlédnout výsledky. Proto je nutné použít obdobného mechanizmu pro přesměrování výstupu do souboru a výsledky si prohlédnout v prohlížeči. program.exe < input.stdin >output.txt.
(Méně vhodné řešení s horší možností změny parametrů: Po dobu ladění programu je také možné zakomentovat načítání z klávesnice, zadat testovací hodnoty v definici proměnných a po odladění vrátit načítání ze standardního vstupu).

 

V případě zájmu o další rozšíření programu a procvičení dalších vlastností můžete zkusit naprogramovat
Zobrazování proměnných během ladění

Po dobu ladění si pro kontrolu činnosti algoritmu tiskněte aktuální hodnoty mezí. K tisku použijte makro LOG1, LOG2..., kde číslo v názvu udává počet tisknutých parametrů pomocí funkce printf. Pro toto makro použijte mechanizmus podmíněného překladu – v případě nadefinování proměnné LADENI (pomoci #define) bude makro tisknout hodnoty (tj. program bude obsahovat printf), v opačném případě bude makro „prázdné“ (tj. při překladu se na jeho místo neumístí žádný text).

Pozn.: funkci LOGX lze nahradit funkcí univerzální pro libovolný počet parametrů LOG(format, …) printf(format, __VA_ARGS__). „Parametr“ tři tečky značí, že na tomto místě může být libovolný počet parametrů. Tyto parametry se umístí do místa označeného __VA_ARGS__.



















Poslední změna 2019-02-11