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 [A,B] f(A)f(B)<0. Zatem, funkcja ta zmienia znak w przedziale [A,B] (co najmniej raz) ma zatem (co najmniej jedno) miejsce zerowe w tym przedziale.
  2. Przedział [A,B] dzielimy na pół (wyznaczając odpowiednio punkt C).
  3. Odrzucamy ten z przedziałów [A,C], [C,B] 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 [A,B] będzie mniejsza od zadanej liczby ε.

Schemat blokowy

TAK
NIE
TAK
NIE
Start
C=(A+B)/2
f(a)*f(c)<0
B = C
A = C
fabs(A-B)> EPS
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)=ex

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