Rysowanie wykresów funkcji

0

Napisałem program oparty na ONP, który wyświetla wykres funkcji opisanej wzorem podanym przez użytkownika. Większość funkcji rysuje dobrze, ale jest problem z funkcją secans(odwrotność cosinusa).

Miałem problem z określaniem dziedziny funkcji. Otóż wykres powinien wyglądać tak:
http://img25.imageshack.us/my.php?image=wykresi.jpg
a wyglądał tak
http://img27.imageshack.us/my.php?image=wykres2q.jpg

Sposób określania, czy dany argument należy do dziedziny polegał na wykorzystaniu wyjątków:

if ONP.el[i]='sec' then
            begin
             try
              a:=zamien(StrToFloat(zdejmij));
              n:=1/cos(a);
             except
              niedziedzina:=True;
              exit;
             end;
             dodaj(FloatToStr(sec(a)),0);
            end

ONP to record, w którym tablica ONP.el zawiera elementy zapisu w ONP

Zamien to funkcja, która zamienia jednostki kątów, w zależności od wyboru użytkownika(stopnie, radiany, gradusy)

Zdejmij, to funkcja, która zdejmuje najwyższy element ze stosu i zwraca jego zawartość

Niedziedzina zwraca True, jeśli dany argument nie należy do dziedziny

Procedura dodaj dodaje wybrany element do stosu(pierwszy argument to wartosc, drugi to priorytet operatora - ten sam stos jest wykorzystywany do konwersji na ONP)

Teoretycznie, okresowo powinien pojawiać się błąd polegający na próbie dzielenia przez zero. W części odpowiedzialnej za rysowanie, jeśli obliczany jest pierwszy argument lub jeśli poprzedni argument nie należy do dziedziny, to kursor jest przesuwany do wyliczonego punktu. Jeśli argument nie należy do dziedziny, to nic się nie dzieje. Jeśli do niej należy, to rysowana jest linia do tego punktu.
Niestety nie działało to jak powinno, prawdopodobnie ze względu na to, że dokładność wykresu jest skończona i cos(x) zawsze trochę różnił się od zera. Dodałem więc następujący kod:

for j := P to K do
                if (Round(1/d*a)*d)=(Round(1/d*(Pi/2+j*Pi))*d) then
                 begin
                   niedziedzina:=True;
                   exit;
                 end

gdzie:
P to początek układu współrzędnych
K to koniec układu współrzędnych
d = (K-P)/Image1.Width

W radianach, x=Pi/2+k*Pi <=> cos(x)=0(k jest dowolną liczbą całkowitą).

Na pierwszy rzut oka działało, ale pojawił się nowy problem.
Przy odpowiednim przybliżeniu wykres wyglądał poprawnie:
http://img25.imageshack.us/my.php?image=secans.png
ale po oddaleniu już nie:
http://img25.imageshack.us/my.php?image=secans2.png
Ramiona powinny dążyć do nieskończoności. Wydaje mi się, że problem znów polega na przybliżaniu wartości. Zamieszczam kod odpowiedzialny za rysowanie, może to coś pomoże.

ostatni:=False;
if funkcje.il<>0 then
 for m := 1 to funkcje.il do
  begin
   Poczatek:=True;
   Image1.Canvas.Pen.Color:=funkcje.item[m].kolor;
   Image1.Canvas.Pen.Width:=funkcje.item[m].grubosc;
   ostatni:=True;
   blad:=False;
   for x := 0 to Image1.Width do
     if not(blad) then
     begin
       konwersja(funkcje.item[m].wzor);
       y:=oblicz(True,d*(x-sx));
       if Poczatek or ostatni then
           begin
            Image1.Canvas.MoveTo(x,-Round((1/d)*(y))+sy);
            Poczatek:=False;
           end else
     if not(niedziedzina) then Image1.Canvas.LineTo(x,-Round((1/d)*(y))+sy);
     ostatni:=niedziedzina;

     end;

Ostatni określa czy poprzedni argument należał do dziedziny.

Jednocześnie można wyświetlać wiele różnych funkcji. Funkcje to record, w którym funkcje.il określa ilość zapisanych funkcji, funkcje.item to tablica, która przechowywuje wzory funkcji.

Blad zwraca true, jeśli wystąpi jakiś błąd niezwiązany z wyznaczaniem dziedziny funkcji.

Konwersja to funkcja, która konwertuje wyrażenie na zapis ONP i zapisuje je do recordu ONP.

Oblicz to funkcja, która oblicza wartość wyrażenia z recordu ONP. Pierwszy argument określa, czy wyrażenie jest funkcją, drugi to wartość argumentu.

Poczatek zwraca True, jeśli obliczana jest wartość dla pierwszego argumentu.

sx to współrzędna x środka układu(sx=Image1.Width div 2)

sy to współrzędna y środka układu(sy=Image1.Height div 2)

Czy ktoś wie jak można to rozwiązać?

0

nie analizowałem dokładnie tego programu ale wydaje mi się, że problem tkwi w liczbach zmiennoprzecinkowych. Nie jestes w stanie dokładnie określić punktu, w którym jest asymptota jeśli operujesz liczbami zmiennoprzecinkowymi. Na kolejnych 2 zdjęciach tak jakbyś zauważył ten problem ... wykresy się ucinają jak widać i to też moim zdaniem jest problem liczb zmiennoprzecinkowych. Dobierz mniejszy krok i urwie Ci się w innym miejscu ale też się urwie.

Rada : chyba jej nie ma ;) Swego czasu używałem do rysowania wykresów programu gnuplot i wydaje mi się, że on tak samo robił ... sprawdź to

0

Dzięki za odpowiedź. Próbowałem zmniejszyć krok, ale niewiele to daje. Przy dziesięciokrotnym zmniejszeniu ramiona są trochę dłuższe, ale i tak szybko się urywają. Przy stukrotnym zmniejszeniu jest tylko trochę lepiej, ale wykres rysuje się strasznie długo - za długo.

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