Wyznaczanie numeryczne ekstremów funkcji

0

Witam!
Mam problem z napisaniem pewnego programiku. Rzecz wydaje się banalna, ale jako, że jestem początkujący w pisaniu programów w języku C to ma do was pytanie. Mam za zadanie wyznaczyć numerycznie ekstrema funkcji f(x)=(cosx)^2+2sinx+2 w zadanym przez użytkownika przedziale. Napisałem kod, który wyznacza, ale tylko jedno ekstremum z podanego przedziału (a może ich być kilka). Zrobiłem to za pomocą metody bisekcji. Ma ktoś jakiś pomysł jak zrobić by program wyszukał wszystkie ekstrema? Myślałem coś o pętlach, ale nie wiem gdzie ją wsadzić:P

Oto kod:

 #include <stdio.h>
#include <stdlib.h>
#include <math.h>

int main()
{
  float a, b, c;                                                                                 // zadeklarowanie wartości liczby pi
  printf("Witaj!\n Ten program pomoze Ci w wyznaczeniu ekstremow funkcji f(x)=(cos(x))^2+2sin(x)+2 w wybranym przez Ciebie przedziale.\nPodaj pierwszy kraniec przedzialu, po czym nacisnij Enter...\n");
  scanf("%f" , &a);                                                                               //liczba a jest pierwszym krańcem przedziału podanego przez użytkownika
  printf("Podaj drugi kraniec przedzialu, po czym nacisnij klawisz Enter...\n");
  scanf("%f" , &b);                                                                               //liczba b jest drugim krańcem przedziału podanego przez użytkownika
  if (a>b)                                                                                       //sprawdzamy, czy użytkownik nie podał nieprawidłowych wartości przedziałów
     printf("Blad. Pierwszy kraniec przedzialu nie moze mieć wiekszej wartosci od drugiego kranca.");
  else
  if ((-2*cos(a)*(sin(a)-1))*(-2*cos(b)*(sin(b)-1))<0 || fabs(b-a)>M_PI)
  {
      while (fabs(b-a)>0.0001)
      {
            c = (a+b)/2;
            if ((-2*cos(a)*(sin(a)-1))*(-2*cos(c)*(sin(c)-1))<0)
               b = c;
            else
            if ((-2*cos(b)*(sin(b)-1))*(-2*cos(c)*(sin(c)-1))<0)
               a = c;
               }
            printf("%f\n", (a+b)/2);

  }
  else 
  printf("Brak ekstremow w podanym przedziale.\n");
  system("PAUSE");  
  return 0;
}

Z góry mówię, że nie proszę was o gotowy kod, ale chociaż o naprowadzenie na to jak rozwiązać problem. Może macie inny pomysł niż metoda bisekcji? Nurtuje mnie też wyrażenie "wyznaczyć numerycznie", czyli jakim sposobem?

Pozdrawiam i czekam na pomysły:)

0

Najprościej to chyba metodą złotego podziału.

http://pl.wikipedia.org/wiki/Metoda_z%C5%82otego_podzia%C5%82u

Nawet kod jest.

0

No tak tylko, że metoda złotego środka też znajdę maksymalnie jeden przedział;/ Może jakiś inny pomysł?

0

Huh? Przecież Ty nie szukasz przedziału. Szukasz minimum w przedziale. Kluczem jest podać właściwy przedział, optymalizacja globalna jest raczej trudna, o ile nie bardzo trudna. Nie sądzę żeby istniała prosta numeryczna metoda szukania wszystkich ekstremów wszystkich możliwych funkcji na zadanym przedziale.

Można pewnie zrobić sobie pochodną, szukać jej miejsc zerowych, potem sprawdzać drugą pochodną i tym sposobem wyznaczać ekstrema...

0

Jak wyzej dobra wydaje sie metoda podobna do analitycznej formy obliczania ekstremow, choc moze byc troche trudna w zapisie. Teoretycznie jest jeszcze 1 sposob ale malo wydajny. Skoro masz przedzial to mozesz liczyc sobie wartosc funkcji w poczatku przedzialu przyjac za max i z zadanym krokiem liczyc wartosci funkcji dalej az dojdziesz do konca przedzialu. Tylko przy dlugosci przedzialu 3 i dokladnosci 0.001 masz juz 3000 porownan. Wiec niezbyt wydajne rozwiazanie.

Wartosc funkcji w punkcie x najlatwiej policzyc schematem hornera. Bardzo prosty w implementacji.

0
kuka1992 napisał(a)

No tak tylko, że metoda złotego środka też znajdę maksymalnie jeden przedział;/ Może jakiś inny pomysł?

Sorka troche zmęczony byłem i durnoty wypisałem. Oczywiście chodziło mi o to że sposobem złotego podziału też znajdę jedno ekstremum. Polecenie mam : "Wyznaczyć numerycznie ekstrema funkcji f(x) w zadanym przez użytkownika przedziale. f(x) = (cosx)^2 + 2sinx+2 ". Więc według polecenia jakoś muszę znaleźć te wszystkie ekstrema, ale na razie potrafię znaleźć jedno w podanym przedziale, chociaż w tym przedziale jest ich więcej;/

0

Możesz łatwo znaleźć wszystkie ekstrema z pewną założoną dokładnością d.
Startujesz z punktu a, i w pętli dodajesz ułamek wartości do x i patrzysz czy pochodna zmieniła w tym punkcie swój znak.
Jeśli w znalezionym przedziale (od xi do xi + d) pochodna zmieniła znak to szukasz w nim ekstremum standardową metodą.
Ale na pewno są bardziej optymalne sposoby.

0

Trzeba jeszcze wziąć pod uwagę końce przedziału - w zadaniu jest mowa o ekstremach, a nie o ekstremach lokalnych.

0
vpiotr napisał(a)

Możesz łatwo znaleźć wszystkie ekstrema z pewną założoną dokładnością d.
Startujesz z punktu a, i w pętli dodajesz ułamek wartości do x i patrzysz czy pochodna zmieniła w tym punkcie swój znak.
Jeśli w znalezionym przedziale (od xi do xi + d) pochodna zmieniła znak to szukasz w nim ekstremum standardową metodą.
Ale na pewno są bardziej optymalne sposoby.

Dzięki vpiotr. Program działa jak należy;D Właśnie brakowało mi tej pętli dzielącej cały przedział na mniejsze przedziały. Teraz znajduje mi wszystkie ekstrema. Tylko zastanawiam się, jak by tu zaimplementować jeszcze funkcję, żeby sprawdzał czy wyszukane ekstremum jest maksimum, czy minimum. Może jakiś pomysł?

0

Jeżeli wybierzesz złe d to i tak możesz trafić na więcej niż jedno ekstremum...

Aby określić co jest min a co max: http://pl.wikipedia.org/wiki/[...]istnienia_ekstremum_lokalnego

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0