Artykuł pobrano ze strony eioba.pl Miejsca zerowe funkcji - Metoda połowienia Mamy daną funkcję f(x) oraz przedział <a,b>, w którym będziemy poszukiwali miejsca zerowego (czyli pierwiastka funkcji f(x)). Aby można było zastosować algorytm połowienia (zwany również algorytmem bisekcji), w przedziale <a,b> muszą być spełnione poniższe warunki: Funkcja f(x) jest określona - uczniowie często nie rozumieją tego pojęcia. Określoność funkcji oznacza, iż dla każdej wartości argumentu x z przedziału <a,b> potrafimy policzyć wartość funkcji. W trakcie pracy algorytm połowienia oblicza wartości funkcji dla argumentów należących do tego przedziału <a,b>. Jeśli przypadkowo trafi na punkt, dla którego wartość funkcji jest nieokreślona, obliczenia się załamią. W praktyce konsekwencje mogą być tragiczne, np. zmiana lotu samolotu z poziomego na pionowy w kierunku ziemi... Dla przykładu rozważmy prostą funkcję: Ile wynosi wartość tej funkcji dla x = 1? Musimy dzielić przez 0, a jak wiadomo jest to zadanie niewykonalne. W punkcie x = 1 tak podana funkcja ma nieokreśloną wartość. Co gorsza punkt ten wypada akurat w środku przedziału <a,b> i algorytm bisekcji trafi na niego przy pierwszym obiegu. Funkcja f(x) jest ciągła. Ciągłość funkcji oznacza z kolei, iż jej wartości nie "wykonują" nagłych skoków. Funkcja przebiega przez wszystkie wartości pośrednie - nie istnieją zatem przerwy w kolejnych wartościach funkcji. Dla przykładu rozważmy taką oto funkcję: Funkcja w przedziale <-2,1> posiada następujący wykres:
Nieciągłość występuje w punkcie x =, czyli w miejscu zmiany przepisu funkcji. Zwróć uwagę, iż funkcja jest określona w tym punkcie - nieciągłość i nieokreśloność to dwie różne sprawy - nie myl ich!!! Funkcja f(x) na krańcach przedziału <a,b> przyjmuje różne znaki. Ponieważ funkcja, zgodnie z poprzednim wymogiem, jest ciągła, to przyjmuje w przedziale <a,b> wszystkie wartości pośrednie pomiędzy f(a) i f(b). Wartości te mają różne znaki (czyli leżą po różnych stronach osi OX), zatem musi być taki punkt x o w przedziale <a,b>, dla którego funkcja przyjmuje wartość pośrednią: f(a) < f(x o ) = 0 < f(b) lub f(a) > f(x o ) = 0 > f(b) Gdy funkcja f(x) spełnia powyższe trzy warunki, to w przedziale <a,b> zagwarantowane jest istnienie pierwiastka i możemy go wyszukać algorytmem połowienia (bisekcji). Zasada jest następująca: Wyznaczamy punkt x o jako środek przedziału <a,b> zgodnie ze wzorem: Obliczamy wartość funkcji w punkcie x o. Jeśli długość przedziału jest mniejsza od założonej dokładności wyliczeń pierwiastka, to wartość x o jest poszukiwanym przybliżeniem. Kończymy algorytm. W przeciwnym razie sprawdzamy, czy f(x o ) znajduje się dostatecznie blisko 0: Jeśli nierówność jest spełniona, to x o jest poszukiwaną wartością pierwiastka. Zwracamy wynik i kończymy algorytm. W przeciwnym razie za nowy przedział poszukiwań pierwiastka przyjmujemy tą połówkę <a,x o > lub <x o,b>, w której funkcja zmienia znak na krańcach. Algorytm powtarzamy od początku dotąd, aż znajdziemy pierwiastek lub przedział <a,b> osiągnie założoną długość (może to być również epsilon). Wtedy kończymy zwracając ostatnio wyliczone x o.
Dane wejściowe f(x)-funkcja, której pierwiastek liczymy. Musi być ciągła i określona w przedziale poszukiwań pierwiastka. a,b-punkty krańcowe przedziału poszukiwań pierwiastka funkcji f(x). a,b R Dane wyjściowe x o -pierwiastek funkcji f(x) Zmienne pomocnicze i funkcje f a, f b, f o - wartości funkcji odpowiednio w punktach a, b, x o. f a, f b, f o R ε o - określa dokładność porównania z zerem. ε o = 0.0000000001 ε x - określa dokładność wyznaczania pierwiastka x o. ε x = 0.0000000001 krok 1:Odczytaj a i b krok 2:f a f(a) ; f b f(b) krok 3:Jeśli f a f b > 0, to pisz "Funkcja nie spełnia założeń" i zakończ algorytm krok 4:Dopóki a - b > ε x wykonuj kroki 5..7 krok 5: krok 6: Jeśli f o < ε o, to idź do kroku 8 krok 7: Jeśli f a f o < 0, to b x o, inaczej a x o ; f a f o krok 8:Pisz x o i zakończ algorytm Wykonanie algorytmu rozpoczynamy od odczytu zakresu poszukiwań pierwiastka danej funkcji. W zmiennych f a i f b umieszczamy wartość funkcji na krańcach tego zakresu Pierwszy test ma na celu sprawdzenie warunku różnych znaków wartości funkcji na krańcach zakresu poszukiwań pierwiastka. Różne znaki gwarantują nam istnienie pierwiastka w danym zakresie. Zatem jeśli funkcja na krańcach nie przybiera różnych znaków, wypisujemy odpowiedni komunikat i kończymy algorytm. Rozpoczynamy pętlę wyliczania kolejnych przybliżeń pierwiastka funkcji. Pętla wykonuje się do momentu, aż przedział poszukiwań pierwiastka osiągnie długość ε x. Wewnątrz pętli wyznaczamy punkt x o leżący w środku przedziału <a,b> oraz obliczamy wartość funkcji w punkcie x o i umieszczamy ją w zmiennej f o. Jeśli wartość f o jest dostatecznie bliska zeru (wpada w otoczenie zera o promieniu ε o ), przerywamy pętlę, wypisujemy x o i kończymy algorytm. W przeciwnym razie za nowy przedział <a,b> przyjmujemy połówkę wyznaczoną przez x o, w której funkcja zmienia znak. Testujemy iloczyn f a przez f o. Jeśli iloczyn jest ujemny, to różne znaki funkcja przyjmuje w połówce <a,x o >. Zatem za nowy koniec b przyjmujemy x o i kontynuujemy pętlę. W przeciwnym razie zmiana znaku występuje w drugiej połówce przedziału - <x o,b>. Za nowy początek a przyjmujemy x o. Dodatkowo za f a przyjmujemy f o - zwolni nas to od konieczności ponownego wyliczania wartości funkcji w nowym punkcie a. Po tych czynnościach kontynuujemy pętlę wyznaczania kolejnych przybliżeń pierwiastka x o.
Poniższe, przykładowe programy są praktyczną realizacją omawianego w tym rozdziale algorytmu. Zapewne można je napisać bardziej efektywnie. To już twoje zadanie. Dokładny opis stosowanych środowisk programowania znajdziesz we wstępie. Programy przed opublikowaniem w serwisie edukacyjnym zostały dokładnie przetestowane. Jeśli jednak znajdziesz jakąś usterkę (co zawsze może się zdarzyć), to prześlij o niej informację do autora. Pozwoli to ulepszyć nasze artykuły. Będziemy Ci za to wdzięczni. Programy wyznaczają miejsce zerowe funkcji: f(x) = x 3 (x + sin(x 2-1) - 1) - 1 Pierwiastków należy poszukiwać w przedziałach <-1,0> i <1,2>. Wydruk z uruchomionego programu Obliczanie pierwiastka funkcji - metoda bisekcji f(x) = x^3*(x+sin(x^2-1)-1)-1 ------------------------------------------------ (C)2006 mgr Jerzy Wałaszek I LO w Tarnowie Podaj zakres poszukiwań pierwiastka: a = 1 b = 2 ------------------------------------------------ WYNIK: x0 = 1,18983299 ------------------------------------------------ Koniec. Naciśnij klawisz Enter... Microsoft Visual Basic 2005 Express Edition
Borland Delphi 7.0 Personal Edition // Program znajduje miejsce zerowe funkcji f(x) // za pomocą algorytmu połowienia - bisekcji //--------------------------------------------- // (C)2006 mgr J.Wałaszek I LO w Tarnowie program mzf1; $APPTYPE CONSOLE uses math; const EPS0 = 0.0000000001; // dokładność porównania z zerem EPSX = 0.0000000001; // dokładność wyznaczenia pierwiastka // Funkcja, której miejsce zerowe obliczamy // f(x) = x^3*(x+sin(x^2-1)-1)-1 // <-1,0> i <1,2> //----------------------------------------- function f(x : real) : real; begin Result := x * x * x * (x + sin(x * x - 1) - 1) - 1; end; // Program główny var a,b,x0,fa,fb,f0 : real; begin writeln('obliczanie pierwiastka funkcji - metoda bisekcji'); writeln('f(x) = x^3*(x+sin(x^2-1)-1)-1'); writeln('------------------------------------------------'); writeln('(c)2006 mgr Jerzy Walaszek I LO w Tarnowie'); writeln; writeln('podaj zakres poszukiwan pierwiastka:'); writeln; write('a = '); readln(a); write('b = '); readln(b); writeln; writeln('------------------------------------------------'); writeln('wynik:'); writeln; fa := f(a); fb := f(b); if fa * fb > then writeln('funkcja nie spelnia zalozen') begin while abs(a - b) > EPSX do begin x0 := (a + b) / 2; f0 := f(x0); if abs(f0) < EPS0 then break; if fa * f0 < then b := x0 begin a := x0; fa := f0; end; end; writeln('x0 = ',x0:15:8); end; writeln; writeln('------------------------------------------------'); writeln('koniec. Nacisnij klawisz Enter...'); readln; end.
Borland C++ Builder 6.0 Personal Edition // Program znajduje miejsce zerowe funkcji f(x) // za pomocą algorytmu połowienia - bisekcji //--------------------------------------------- // (C)2006 mgr J.Wałaszek I LO w Tarnowie #include <iostream> #include <iomanip> #include <math> using namespace std; const double EPS0 = 0.0000000001; // dokładność porównania z zerem const double EPSX = 0.0000000001; // dokładność wyznaczenia pierwiastka // Funkcja, której miejsce zerowe obliczamy // f(x) = x^3*(x+sin(x^2-1)-1)-1 // <-1,0> i <1,2> //----------------------------------------- double f(double x) return x * x * x * (x + sin(x * x - 1) - 1) - 1; // Program główny int main(int argc, char* argv[]) double a,b,x0,fa,fb,f0; cout.precision(8); // 8 cyfr po przecinku cout.setf(ios::fixed); // format stałoprzecinkowy cout << "Obliczanie pierwiastka funkcji - metoda bisekcji\n" "f(x) = x^3*(x+sin(x^2-1)-1)-1\n" "------------------------------------------------\n" "(C)2006 mgr Jerzy Walaszek I LO w Tarnowie\n\n" "Podaj zakres poszukiwan pierwiastka:\n\n"; cout << "a = "; cin >> a; cout << "b = "; cin >> b; cout << "\n------------------------------------------------\n\n" "WYNIK:\n\n"; fa = f(a); fb = f(b); if(fa * fb > ) cout << "Funkcja nie spelnia zalozen\n"; while(fabs(a - b) > EPSX) x0 = (a + b) / 2; f0 = f(x0); if(fabs(f0) < EPS0) break; if(fa * f0 < ) b = x0; a = x0; fa = f0; cout << "x0 = " << setw(15) << x0 << endl; cout << "\n------------------------------------------------\n"; system("pause"); return ;
Microsoft Visual Basic 2005 Express Edition ' Program znajduje miejsce zerowe funkcji f(x) ' za pomocą algorytmu połowienia - bisekcji '--------------------------------------------- ' (C)2006 mgr J.Wałaszek I LO w Tarnowie Module Module1 Const EPS0 = 0.0000000001 ' dokładność porównania z zerem Const EPSX = 0.0000000001 ' dokładność wyznaczenia pierwiastka ' Funkcja, której miejsce zerowe obliczamy ' f(x) = x^3*(x+sin(x^2-1)-1)-1 ' <-1,0> i <1,2> '----------------------------------------- Function f(byval x As Double) As Double Return x * x * x * (x + Math.Sin(x * x - 1) - 1) - 1 End Function '----------------------------------------------------- ' Program główny '----------------------------------------------------- Sub Main() Dim a, b, x0, fa, fb, f0 As Double Console.WriteLine("Obliczanie pierwiastka funkcji - metoda bisekcji") Console.WriteLine("f(x) = x^3*(x+sin(x^2-1)-1)-1") Console.WriteLine("------------------------------------------------") Console.WriteLine("(C)2006 mgr Jerzy Wałaszek I LO w Tarnowie") Console.WriteLine("Podaj zakres poszukiwań pierwiastka:") Console.Write("a = ") : a = Val(Console.ReadLine) Console.Write("b = ") : b = Val(Console.ReadLine) Console.WriteLine("------------------------------------------------") Console.WriteLine("WYNIK:") fa = f(a) : fb = f(b) If fa * fb > Then Console.WriteLine("Funkcja nie spełnia założeń") Else While Math.Abs(a - b) > EPSX x0 = (a + b) / 2 : f0 = f(x0) If Math.Abs(f0) < EPS0 Then Exit While If fa * f0 < Then b = x0 Else a = x0 : fa = f0 End If End While Console.WriteLine("x0 = 0,15:F8", x0) End If Console.WriteLine("------------------------------------------------") Console.WriteLine("Koniec. Naciśnij klawisz Enter...") Console.ReadLine() End Sub End Module
Python # -*- coding: cp1250 -*- # Program znajduje miejsce zerowe funkcji f(x) # za pomocą algorytmu połowienia - bisekcji #--------------------------------------------- # (C)2006 mgr J.Wałaszek I LO w Tarnowie import math EPS0 = 0.0000000001 # dokładność porównania z zerem EPSX = 0.0000000001 # dokładność wyznaczenia pierwiastka # Funkcja, której miejsce zerowe obliczamy # f(x) = x^3*(x+sin(x^2-1)-1)-1 # <-1,0> i <1,2> #----------------------------------------- def f(x): return x * x * x * (x + math.sin(x * x - 1) - 1) - 1 #----------------------------------------------------- # Program główny #----------------------------------------------------- "Obliczanie pierwiastka funkcji - metoda bisekcji" "f(x) = x^3*(x+sin(x^2-1)-1)-1" "------------------------------------------------" "(C)2006 mgr Jerzy Walaszek I LO w Tarnowie" "Podaj zakres poszukiwan pierwiastka:" a = float(raw_input("a = ")) b = float(raw_input("b = ")) "-------------------------------------------------" "WYNIK:" fa, fb = f(a), f(b) if fa * fb > : "Funkcja nie spelnia zalozen" : while abs(a - b) > EPSX: x0 = (a + b) / 2 f0 = f(x0) if abs(f0) < EPS0: break if fa * f0 < : b = x0 : a, fa = x0, f0 "x0 = %15.8f" % x0 "---------------------------------------------------------" raw_input("koniec. Nacisnij klawisz Enter...")
JavaScript <html> <head> </head> <body> <div align="center"> <form style="border-right: #ff9933 1px outset; PADDING-RIGHT: 4px; BORDER-TOP: #ff9933 1px outset; PADDING-LEFT: 4px; PADDING-BOTTOM: 1px; BORDER-LEFT: #ff9933 1px outset; PADDING-TOP: 1px; BORDER-BOTTOM: #ff9933 1px outset; BACKGROUND-COLOR: #ffcc66" name="frmbincode"> <h3 style="text-align: center"> Obliczanie pierwiastka funkcji metodą bisekcji </h3> <p style="text-align: center"> <i>f(x) = x<sup>3</sup>(x + sin(x<sup>2</sup> - 1) - 1) - 1</i> </p> <p style="text-align: center"> (C)2006 mgr Jerzy Wałaszek I LO w Tarnowie </p> <hr> <p style="text-align: center"> Wpisz do pól edycyjnych zakres przedziału poszukiwań pierwiastka </p> <div align="center"> <table border="0" id="table144" cellpadding="8" style="border-collapse: collapse"> <tr> <td> a = <input type="text" name="wsp_a" size="20" value="1" style="text-align: right"> </td> <td> b = <input type="text" name="wsp_b" size="20" value="2" style="text-align: right"> </td> <td> <input type="button" value="szukaj pierwiastka" name="b1" onclick="main()"> </td> </tr> </table> </div> <div id="out" align=center>...</div> </form> <script language=javascript> // Program znajduje miejsce zerowe funkcji f(x) // za pomocą algorytmu połowienia - bisekcji //--------------------------------------------- // (C)2006 mgr J.Wałaszek I LO w Tarnowie var EPS0 = 0.0000000001; // dokładność porównania z zerem var EPSX = 0.0000000001; // dokładność wyznaczenia pierwiastka // Funkcja, której miejsce zerowe obliczamy // f(x) = x^3*(x+sin(x^2-1)-1)-1 // <-1,0> i <1,2> //----------------------------------------- function f(x) return x * x * x * (x + Math.sin(x * x - 1) - 1) - 1; // Program główny function main() var a,b,x0,fa,fb,f0,t; a = parsefloat(document.frmbincode.wsp_a.value); b = parsefloat(document.frmbincode.wsp_b.value); if(isnan(a) isnan(b)) t = "<font color=red><b>złe krańce zakresu poszukiwań pierwiastka!</b></font>"; t = "x<sub>o</sub> = "; fa = f(a); fb = f(b); if(fa * fb > ) t = "<font color=red><b>funkcja nie spelnia zalozen</b></font>"; while(math.abs(a - b) > EPSX) x0 = (a + b) / 2; f0 = f(x0); if(math.abs(f0) < EPS0) break; if(fa * f0 < ) b = x0; a = x0; fa = f0; t += x0; document.getelementbyid("out").innerhtml = t; </script> </div> </body> </html> Dokument ten rozpowszechniany jest zgodnie z zasadami licencji GNU Free Documentation License.
Autor: mgr Jerzy Wałaszek Przedruk ze strony: http://www.i-lo.tarnow.pl/edu/inf/alg/zmzf/index.html Artykuł pobrano ze strony eioba.pl