Miejsca zerowe funkcji

Definicja miejsca zerowego

Miejscem zerowym funkcji f(x) będziemy nazywali argument xo, dla którego funkcja przyjmuje wartość 0:
 

xo jest miejscem zerowym wtedy i tylko wtedy, gdy f(xo) = 0

 

Uwaga:

Często uczniowie (nawet ci lepsi) mylą to proste pojęcie i twierdzą, iż miejsce zerowe to argument xo = 0. Prawdopodobnie zamęt wprowadza indeks przy literce x. Zastanów się, jeśli by tak było, to po co potrzebna jest nam ta cała procedura znajdowania czegoś, co jest przecież równe 0...?

 

Przykład:

Funkcja f(x) = 2x - 4 posiada miejsce zerowe dla xo = 2, ponieważ:

 f(xo)  = 2xo - 4
 f(2)  = 2 obrazek 2 - 4 = 4 - 4 = 0

Miejsce zerowe często nazywamy pierwiastkiem funkcji.

Funkcja może posiadać więcej niż jeden pierwiastek:

Przykład:

Funkcja f(x) = x2 - 1 posiada dwa pierwiastki: xo = -1 oraz xo = 1, gdyż:

 f(xo)  = (xo)2 - 1
 f(-1)  = (-1)2 - 1 = 1 - 1 = 0
  f(1)  = 12 - 1 = 1 - 1 = 0

Funkcja może posiadać nieskończenie wiele pierwiastków:

Przykład:

Funkcja f(x) = sin(x - 2) posiada pierwiastki dla każdego xo = + 2, gdzie k = 0, ±1, ±2 ...

 


Graficznie miejsce zerowe funkcji możemy interpretować jako punkt przecięcia osi współrzędnych OX przez wykres funkcji:

 

 

Znajdowanie miejsc zerowych ma olbrzymie znaczenie w matematyce, fizyce, astronomii, technice itp. Dlatego już dawno temu matematycy opracowali wiele metod rozwiązywania tego zagadnienia. Zasadniczo istnieją dwa podejścia:

 

Metoda połowienia - bisekcji

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:

 

1. 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ę:

 

obrazek

 

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ść.

 

2. 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ę:

 

obrazek

 

Funkcja w przedziale <-2,1> posiada następujący wykres:

 

obrazek

 

Nieciągłość występuje w punkcie x = 0, 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!!!

 

3. Funkcja f(x) na krańcach przedziału <a,b> przyjmuje różne znaki. Ponieważ funkcja, zgodnie z poprzednim podpunktem, 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 xo w przedziale <a,b>, dla którego funkcja przyjmuje wartość pośrednią:

 

f(a) < f(xo) = 0 < f(b lub   f(a) > f(xo) = 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 xo jako środek przedziału <a,b> zgodnie ze wzorem:

 

obrazek

 

Obliczamy wartość funkcji w punkcie xo. Sprawdzamy, czy f(xo) znajduje się dostatecznie blisko 0:

 

obrazek

 

Jeśli nierówność jest spełniona, to xo jest poszukiwaną wartością pierwiastka. Zwracamy wynik i kończymy algorytm. W przeciwnym razie za nowy przedział poszukiwań pierwiastka przyjmujemy tą połówkę <a,xo> lub <xo,b>, w której funkcja zmienia znak na krańcach. Algorytm powtarzamy od początku dotąd, aż znajdziemy pierwiastek

 

Program wyznacza miejsce zerowe funkcji: f(x) = x3(x + sin(x2 - 1) - 1) - 1. Pierwiastków należy poszukiwać w przedziałach <-1,0> i <1,2>.

 

// Znajdowanie miejsc zerowych
// METODA POŁOWIENIA - BISEKCJI
// (C)2010 I LO w Tarnowie
//------------------------

#include <iostream>
#include <iomanip>
#include <cmath>

using namespace std;

const double EPS = 0.00001;

// Tutaj definiujemy naszą funkcję
//--------------------------------

double f(double x)
{
    return x * x * x * (x + sin(x * x - 1) - 1) - 1;
}

int main()
{
    double a,b,x0,fa,fb,f0;

    cout << fixed << setprecision(4);

    cout << "OBLICZANIE MIEJSC ZEROWYCH FUNKCJI - METODA BISEKCJI\n"
            "----------------------------------------------------\n\n";

    // odczytujemy przedział poszukiwań pierwiastka

    cout << "a = "; cin >> a;
    cout << "b = "; cin >> b;

    cout << endl;

    // obliczamy wartości funkcji w punktach a i b

    fa = f(a);
    fb = f(b);

    // sprawdzamy, czy na krańcach funkcja ma różne znaki

    if(fa * fb < 0)
    {
        // pierwiastka szukamy metodą bisekcji

        while(true)
        {
            x0 = (a + b) / 2;
            f0 = f(x0);

            // sprawdzamy, czy x0 jest przybliżonym pierwiastkiem

            if(fabs(f0) < EPS)
            {
                cout << "x0 = " << x0 << " f(x0) = " << f0 << endl << endl;
                break; // pierwiastek znaleziony, przerywamy pętlę
            }

            // za nowy przedział przyjmujemy połówkę, w której funkcja zmienia znak

            if(fa * f0 < 0)
            {
                b = x0; fb = f0;
            }
            else
            {
                a = x0; fa = f0;
            }
        }
    }
    else cout << "FUNKCJA NIE SPELNIA WARUNKU NR 3\n\n";

    return 0;
}

 

Metoda Fałszywej Prostej - Regula Falsi

Mamy daną funkcję f(x) oraz przedział <a,b> poszukiwań pierwiastka. W przedziale tym funkcja musi spełniać następujące warunki:

f(a) < f(xo) = 0 < f(b) lub f(a) > f(xo) = 0 > f(b)

Gdy funkcja f(x) spełnia podane warunki, to w przedziale <a,b> zagwarantowane jest istnienie pierwiastka i możemy go wyszukać algorytmem regula falsi.

obrazek

W języku łacińskim regula falsi oznacza fałszywą prostą. Ideą tej metody jest założenie, iż funkcja w coraz mniejszych przedziałach wokół pierwiastka zaczyna przypominać funkcję liniową. Skoro tak, to przybliżenie pierwiastka otrzymujemy prowadząc linię prostą (sieczną) z punktów krańcowych przedziału. Sieczna przecina oś OX w punkcie xo, który przyjmujemy za przybliżenie pierwiastka - gdyby funkcja faktycznie była liniowa, otrzymany punkt xo byłby rzeczywistym pierwiastkiem.

Wzór dla xo można wyprowadzić na kilka sposobów. My wybierzemy znane twierdzenie Talesa, które mówi, iż jeżeli ramiona kąta przetniemy dwiema prostymi równoległymi, to długości odcinków wyznaczonych przez te proste na jednym ramieniu kąta będą proporcjonalne do długości odpowiednich odcinków wyznaczonych przez te proste na ramieniu drugim. Poniższy rysunek obrazuje tę sytuację:

obrazek

 

obrazek

 

W naszym przypadku postępujemy następująco:

 

Kąt utworzą odpowiednie odcinki:

 

pionowo FA = (a,0)-(a,f(a)) powiększony o odcinek FB = (b,0)-(b,-f(b))

poziomo XAB = (a,0)-(b,0)

Prostymi równoległymi będzie cięciwa z punktów krańcowych przedziału, oraz ta sama cięciwa przesunięta pionowo w górę o długość odcinka FB.

Poniższy rysunek obrazuje otrzymaną sytuację:

obrazek

Zgodnie z twierdzeniem Talesa mamy:

 

obrazek

 

Jeśli podstawimy do tego wzoru długości odcinków:

 

FA = f(a)
FB = -f(b)
XAB = b - a
XX0 = xo - a

 

Otrzymamy:

 

obrazek

 

a dalej:


obrazek

Ostatnie przekształcenie ma na celu otrzymanie wzoru o lepszej "zapamiętywalności". Mnożymy mianownik przez (-1), dzięki czemu staje się on spójny z licznikiem ułamka. Sam ułamek zmienia znak na minus.

Algorytm regula falsi jest bardzo podobny do opisanego w poprzednim rozdziale algorytmu bisekcji. Założenia wstępne dla badanej funkcji w obu algorytmach są identyczne. Różnią się one sposobem wyznaczania punktu xo. W algorytmie bisekcji punkt ten zawsze wyznaczany był w środku przedziału <a,b>. Z tego powodu algorytm bisekcji jest "nieczuły" na przebieg funkcji - zawsze zbliża się do pierwiastka w ten sam sposób.

W algorytmie regula falsi jest inaczej. Punk xo wyznaczany jest w zależności od wartości funkcji na krańcach przedziału poszukiwań. W efekcie w każdej iteracji otrzymujemy lepsze przybliżenie do rzeczywistej wartości pierwiastka. Zatem w większości przypadków algorytm regula falsi szybciej osiągnie założoną dokładność pierwiastka od algorytmu bisekcji (chociaż można oczywiście podać kontrprzykłady).

Po wyznaczeniu przybliżonego pierwiastka postępowanie w obu algorytmach jest w zasadzie takie samo. Sprawdzamy, czy wartość modułu różnicy pomiędzy dwoma ostatnimi przybliżeniami pierwiastka jest mniejsza od zadanego minimum. Jeśli tak, obliczenia kończymy zwracając xo.

Obliczamy wartość funkcji w punkcie xo i sprawdzamy, czy jest ona dostatecznie bliska zeru. Jeśli tak, zwracamy xo i kończymy. Jeśli nie, za nowy przedział przyjmujemy tą część przedziału <a,b> rozdzielonego przez xo, w której funkcja zmienia znak. Całą procedurę powtarzamy, aż do osiągnięcia pożądanego wyniku.

 

Program wyznacza miejsce zerowe funkcji: f(x) = x3(x + sin(x2 - 1) - 1) - 1. Pierwiastków należy poszukiwać w przedziałach <-1,0> i <1,2>.

 

// Znajdowanie miejsc zerowych
// METODA FAŁSZYWEJ PROSTEJ - REGULA FALSI
// (C)2010 I LO w Tarnowie
//------------------------

#include <iostream>
#include <iomanip>
#include <cmath>

using namespace std;

const double EPS = 0.00001;

// Tutaj definiujemy naszą funkcję
//--------------------------------

double f(double x)
{
    return x * x * x * (x + sin(x * x - 1) - 1) - 1;
}

int main()
{
    double a,b,x0,fa,fb,f0;

    cout << fixed << setprecision(4);

    cout << "OBLICZANIE MIEJSC ZEROWYCH FUNKCJI - METODA REGULA FALSI\n"
            "--------------------------------------------------------\n\n";

    // odczytujemy przedział poszukiwań pierwiastka

    cout << "a = "; cin >> a;
    cout << "b = "; cin >> b;

    cout << endl;

    // obliczamy wartości funkcji w punktach a i b

    fa = f(a);
    fb = f(b);

    // sprawdzamy, czy na krańcach funkcja ma różne znaki

    if(fa * fb < 0)
    {
        // pierwiastka szukamy metodą regula falsi

        while(true)
        {
            x0 = a - fa * (b - a) / (fb - fa);
            f0 = f(x0);

            // sprawdzamy, czy x0 jest przybliżonym pierwiastkiem

            if(fabs(f0) < EPS)
            {
                cout << "x0 = " << x0 << " f(x0) = " << f0 << endl << endl;
                break; // pierwiastek znaleziony, przerywamy pętlę
            }

            // za nowy przedział przyjmujemy połówkę, w której funkcja zmienia znak

            if(fa * f0 < 0)
            {
                b = x0; fb = f0;
            }
            else
            {
                a = x0; fa = f0;
            }
        }
    }
    else cout << "FUNKCJA NIE SPELNIA WARUNKU NR 3\n\n";

    return 0;
}

 

Zbadaj dla obu programów liczbę obiegów wewnętrznej pętli while, która wyznacza kolejne przybliżenia xo i wyciągnij odpowiednie wnioski.

 


   I Liceum Ogólnokształcące   
im. Kazimierza Brodzińskiego
w Tarnowie

©2024 mgr Jerzy Wałaszek

Dokument ten rozpowszechniany jest zgodnie z zasadami licencji
GNU Free Documentation License.

Pytania proszę przesyłać na adres email: i-lo@eduinf.waw.pl

W artykułach serwisu są używane cookies. Jeśli nie chcesz ich otrzymywać,
zablokuj je w swojej przeglądarce.
Informacje dodatkowe