Funkcje dla bystrzaków

Szukanie miejsc zerowych

$$f(x)=0$$

Jak to zrobić?

Problem (1)

Problem (2)

Zadanie jest proste:

  1. Mamy funkcję $f(x)$ ciągłą i taką, że na końcach pewnego przedziału $\lbrack A,B\rbrack$ $f(A)f(B) < 0$. Zatem, funkcja ta zmienia znak w przedziale $\lbrack A,B\rbrack$ (co najmniej raz) ma zatem (co najmniej jedno) miejsce zerowe w tym przedziale.
  2. Przedział $\lbrack A,B\rbrack$ dzielimy na pół (wyznaczając odpowiednio punkt $C$).
  3. Odrzucamy ten z przedziałów $\lbrack A,C\rbrack$, $\lbrack C,B\rbrack$ w którym funkcja nie zmienia znaku (to znaczy ma ten sam znak na końcach przedziału).
  4. Postępowanie prowadzimy tak długo, aż długość przedziału $\lbrack A,B\rbrack$ będzie mniejsza od zadanej liczby $\varepsilon$.

Schemat blokowy

graph LR start([Start]) --> ala["C=(A+B)/2"] ala --> przedzial{"f(a)*f(c)<0"} przedzial --> |TAK| Be[B = C] przedzial --> |NIE| Aa[A = C] Be --> koniec{"fabs(A-B)> EPS"} Aa --> koniec koniec --> |TAK| ala koniec --> |NIE| stop([STOP])

Dane

  • wejściowe

    1. Końce przedziału, w którym funkcja zmienia znak

      double A, B;
      
    2. Dokładność obliczeń

      double eps;
      
  • robocze

    double C;
    
  • wyniki

    1. Współrzędna punktu najbliższa miejscu zerowemu

Co zrobić gdy w zadanym przedziale funkcja znaku nie zmienia?

Ba!

Kod algorytmu

do
{
    C = ( A + B ) / 2.;
    if ( f(C) == 0 )
//      wynikiem jest C
    else if ( f(A) * f(C) > 0 )
        A = C;
    else
        B = C;
}while ( fabs(A - B) > eps );
//		wynikiem będzie ( A + B ) / 2.;

Jak użyć tego algorytmu?

#include <stdio.h>
int main(int argc, char **argv)
{
    double A, B, eps;
    A = 1;
    B = 2;
    eps = 0.001;
    double C;
    do
    {
        C = ( A + B ) / 2.;
        if ( f(C) == 0 )
//		wynikiem jest C
            else if ( f(A) * f(C) > 0 )
                A = C;
            else
                B = C;
    }while ( fabs(A - B) > eps );
//		wynikiem będzie ( A + B ) / 2.;
    return 0;
}

Co z funkcją f?

  • Funkcja jednej zmiennej x
  • argument typu zmiennoprzecinkowego
  • wynik typu zmiennoprzecinkowego
double f(double x)
{
    return exp(x) - sin(x);
}

Wykres funkcji f
Wykres funkcji f

czyli szukamy rozwiązania problemu

$$\sin(x)=e^{x}$$

Uwaga

Kod funkcji musimy dodać przed main()

Co to znaczy „wynikiem jest/będzie”?

W miejscu tych komentarzy wydrukujemy podaną wartość

Teraz algorytm „zamkniemy w funkcji”

double pol(double A, double B, double eps)
{
    double C;
    do
    {
        C = ( A + B ) / 2.;
        if ( f(C) == 0 )
//      wynikiem jest C
        else if ( f(A) * f(C) > 0 )
            A = C;
        else
            B = C;
    }while ( fabs(A - B) > eps );
//      wynikiem będzie ( A + B ) / 2.;
}

Co to znaczy „wynikiem jest/będzie”?

W tym miejscu wstawimy polecenie return (z odpowiednim wyrażeniem)

double pol(double A, double B, double eps)
{
    double C;
    do
    {
        C = ( A + B ) / 2.;
        if ( f(C) == 0 )
            return C;//      wynikiem jest C
        else if ( f(A) * f(C) > 0 )
            A = C;
        else
            B = C;
    }while ( fabs(A - B) > eps );
	return ( A + B ) / 2.;// wynikiem będzie ( A + B ) / 2.;
}

Kod programu

#include <math.h>
#include <stdio.h>
double f(double x)
{
    return exp(x) - sin(x);
}

double pol(double A, double B, double eps)
{
    double C;
    do
    {
        C = ( A + B ) / 2.;
        if ( f(C) == 0 )
            return C;          // wynikiem jest C
        else if ( f(A) * f(C) > 0 )
            A = C;
        else
            B = C;
    }while ( fabs(A - B) > eps );
    return ( A + B ) / 2.;    // wynikiem będzie ( A + B ) / 2.;
}

int main(int argc, char **argv)
{
    double x;
    x = pol(1., 3., 0.00001);
    printf("miejscemn zerowym jest %f\n", x);
    printf( "wartość funkcji %f\n", f(x) );
    return 0;
}

Udoskonalenia kodu

  • Co zrobić gdy w pierwszym wywołaniu funkcji pol() nie jest spełniony warunek $f(A)*f(B)<0$?

Pojawiły się pomysły, żeby zaraz po wejściu do funkcji sprawdzić ten warunek i:

  1. Wypisać komunikat „Nie ma miejsc zerowych!”
  2. Żeby funkcja zwracała wartość $-1$.

Ale oba powyższe pomysły są do nieczego: co będzie gdy miejsce zerowe funkcji wypadnie w punkcie $-1$? A kto przeczyta tekst komunikatu?

Można tak

if ( f(A) * f(B) > 0)
    return INFINITY;

A po wyjściu z funkcji

x = pol(A, B, eps);
if (x == INFINITY)
    printf("Funkcja nie ma miejsc zerowych\n") // lub cokolwiek innego
Poprzedni
Następny