Dokumentacja projektu
"Metoda Newtona. Metody zmodyfikowane dla pierwiastków wielokrotnych"


Autor Marcin Wiącek <marcin-wiacek@topnet.pl>
Grupa dziekańska 2P14
Prowadzący dr inż. Michał Borecki
Semestr zimowy 2001

1. Wprowadzenie


Opis użytej metody Newtona i ogólne wprowadzenie do projektu zostało podane w części opisującej funkcję main();

2. Sposób kompilacji projektu


Kolejne kroki potrzebne do kompilacji projektu:

Następnie skompilować projekt (np. używając kompilatora gcc)

3. Użytkowanie projektu


Program "projekt" po uruchomieniu wymaga czterech linijek danych wprowadzonych od użytkownika:

Dane te można wpisać w pliku, a następnie przekazać do projektu w następujący sposób:

./projekt < plik

Przykładowy plik może wyglądać następująco:

x^4-4*x^3-5*x^2-4*x+4+sin(x)+ln(10)
0.0005
3
50
Program ignoruje spacje wprowadzone przez użytkownika.

Znakiem oddzielającym części całkowite od ułamkowych w liczbach jest kropka.

Przy wprowadzaniu wzoru funkcji zmienną jest "x". Możliwe jest używanie następujących operatorów matematycznych "+", "-", "*", "/", "^", następujących stałych matematycznych "pi" i "e" oraz funkcji matematycznych "sin", "cos", "tan", "ctg", "ln".

Po przyjęciu danych i sprawdzeniu ich poprawności program przystępuje do obliczeń (wypisując dla kolejnych przybliżeń pierwiastka wartość funkcji i pochodnej), a następnie pokazuje wynik obliczeń.

4. Znane błędy i ograniczenia projektu


W przypadku, gdyby wynik działania projektu był różny od oczekiwanych, należy skompilować go z kodem używanym podczas sprawdzania poprawności jego działania (zostało to opisane w punkcie 2).

W przypadku, gdyby zaszła potrzeba skierowania komunikatów debugujących do pliku, należy użyć komendy "./projekt 2> plik" (jeżeli zachodzi konieczność zapisu do pliku normalnych komunikatów programu, używamy komendy "./projekt > plik").

Należy pamiętać, iż czasami występujące niezgodności mogą wynikać z tego, iż projekt przy obliczaniu kolejnych wartości stosuje przybliżoną dokładność (błędy mogą się sumować).

Od użytkownika nie jest wymagane podawanie przedziału obliczeń (zgodnie z założeniami metody) Jest to wygodne, gdyż nie musi on znać przebiegu zmienności funkcji, natomiast wymaga, aby ilość kroków, w których program ma szukać przybliżonego pierwiastka, była możliwie duża. Inaczej ciąg kolejnych pierwiastków może nie być wystarczająco "szybko" zbieżny do zera i projekt wykaże brak pierwiastka. Zostało to wyjanione dokładniej w opisie funkcji main();

Należy również pamiętać o podawaniu możliwie najmniejszej wartości dokładności, jeżeli zależy nam na możliwie dokładnym obliczeniu pierwiastka podanej funkcji.

5. Budowa poszczególnych plików projektu


Makrodefinicje i stałe
 
Nazwa Opis
dprintf funkcja wypisująca dane wyłącznie, gdy zdefiniowaną stałą DEBUG (w pliku config.h)
DEBUG Jej zdefiniowanie włącza kompilowanie kodu używanego przy pisaniu programu
przyrost Przyrost, dla którego ma być liczona pochodna funkcji zgodnie ze wzorem:

f'(x)=(f(x+przyrost)-f(x))/przyrost

Im mniejszy, tym dokładniej liczona pochodna

MAX_ELEMENTOW Ilość elementów w każdej strukturze LICZBA
ST_DODAWANIE Używana przy liczeniu wag w strukturze LICZBA. Definiuje dodawanie
ST_ODEJMOWANIE Używana przy liczeniu wag w strukturze LICZBA. Definiuje odejmowanie
ST_MNOZENIE Używana przy liczeniu wag w strukturze LICZBA. Definiuje mnożenie
ST_DZIELENIE Używana przy liczeniu wag w strukturze LICZBA. Definiuje dzielenie
ST_POTEGOWANIE Używana przy liczeniu wag w strukturze LICZBA. Definiuje potęgowanie
ST_FUNKCJA Używana przy liczeniu wag w strukturze LICZBA. Definiuje funkcje matematyczne

Struktury danych

LICZBA

Opis: struktura przechowująca opis funkcji (pochodnej) w postaci zrozumiałej dla programu. Szerzej jej zastosowanie zostało opisane w funkcji wartosc_funkcji;
 
Nazwa Typ Opis
liczby[MAX_ELEMENTOW] double Przechowuje liczby kolejnych elementów funkcji
stringi[MAX_ELEMENTOW][100] char Przechowuje napisy kolejnych elementów funkcji
wagi[MAX_ELEMENTOW] int Przechowuje wagi kolejnych elementów funkcji
ile int Ilość elementów działania przechowywanych w liczby, stringi i wagi

Zmienne globalne
Nazwa Typ Opis
wart_funkcji double Wartość funkcji wyliczona dla konkretnego x
wart_pochodnej double Wartość pochodnej funkcji wyliczona dla konkretnego x
wzor[1000] char Wzór funkcji wczytanej od użytkownika
mojblad int Błąd zwracane prze funkcje z funkcje.c

Funkcje

int main()

Opis: główna funkcja programu. W funkcji tej zawarty jest kod związany bezpośrednio z implementacją metody Newtona.

Zmienne:
Nazwa Typ Opis
j int Używana w pętli
i int Używana przy zwracaniu wartości błędu przez funkcje licz_funkcja_pochodna i wczytaj_liczba
ile_krokow int W ilu krokach program ma próbować znaleźć pierwiastek
iks double Aktualna wartość przybliżenia pierwiastka
dokladnosc double Dokladność, z jaką ma być znaleziony pierwiastek
wynik int Kod błędu, który jest zarazem kodem błędu programu

Wprowadzenie do metody Newtona:

Jest to metoda pozwalająca na obliczanie przybliżonych wartości pierwiastków (zarówno o parzystej i nieparzystej wielokrotności) równania f(x)=0.

Założenia tej metody są następujące: w przedziale <a;b>, w którym położony jest pierwiastek, funkcja f(x) ma na krańcach różne znaki oraz pierwsza i druga pochodna mają stałe znaki.

Kolejne przybliżenia pierwiastków są wtedy równe:

xn+1 = xn - f(xn)/f'(xn)

Projekt jest praktyczną realizacją tej metody. Pozwala on na policzenie pierwiastka z zadaną dokładnością.

Wykorzystuje on jeden z trzech sposobów implementacji podanych w książce  "Metody numeryczne" Zenona Fortuny, Bohdana Macukowa i Janusza Wąsowskiego.

Zgodnie z nią nie jest potrzebne sprawdzanie założeń metody.

Wystarczy liczenie kolejnych (ewentualnych) przybliżeń zgodnie z podanym wzorem i sprawdzanie dla każdego, czy jest już poszukiwanym pierwiastkiem (przy czym pod pojęciem pierwiastka równania rozumiemy liczbę, dla której wartość funkcji f(x) jest mniejsza od podanej przez użytkownika dokładności).

Aby program nie wpadł w pętlę nieskończoną, można podać, dla ilu maksymalnie przybliżeń program ma sprawdzać, czy są pierwiastkami. Jest to bardzo wygodne, gdyż użytkownik nie musi znać przebiegu zmienności f(x). Aby mieć jednak pewność, iż rzeczywiście nie pominęliśmy pierwiastka, należy podawać maksymalnie dużą ilość kroków.

Zostało to zrealizowane ogólnie w następujący sposób:

  1. wczytanie parametrów początkowych
  2. jeżeli jest to możliwe, liczenie kolejnego przybliżenia zgodnie w powyższym wzorem.
  3. sprawdzanie, czy osiągnięto pierwiastek
  4. powrót do punktu 2, jeżeli policzyliśmy dotąd mniej przybliżeń niż podał użytkownik
Szczegółowy algorytm:
  1. START
  2. wczytanie danych do zmiennych wzór, dokladnosc, iks, ile_krokow.
  3. wart_funkcji=wartości funkcji dla podanego iks (wykorzystując funkcję licz_funkcja_pochodna). Jeżeli wystąpił błąd, wyjście z programu.
  4. wart_pochodnej=i wartości pochodnej funkcji dla podanego iks (wykorzystując funkcję licz_funkcja_pochodna). Jeżeli wystąpił błąd, wyjście z programu.
    1. sprawdzenie, czy osiągnięto pierwiastkek. Jeżeli tak, wypisanie komunikatu i wyjście z programu.
    2. jeżeli wartość pochodnej funkcji (zmienna wart_pochodnej)==0, wypisanie komunikatu i wyjście z programu
    3. obliczenie nowego przybliżenia pierwiastka zgodnie ze wzorem iks = iks - wart_funkcji/wart_pochodnej (zgodnie ze wzorem z metody Newtona: xn+1 = xn - f(xn)/f'(xn)).
    4. wart_funkcji=wartości funkcji dla podanego iks (wykorzystując funkcję licz_funkcja_pochodna). Jeżeli wystąpił błąd, wyjście z programu.
    5. wart_pochodnej=i wartości pochodnej funkcji dla podanego iks (wykorzystując funkcję licz_funkcja_pochodna). Jeżeli wystąpił błąd, wyjście z programu.
    6. zwiększenie j
    7. powrót do kroku 1, jeżeli j<=ile_kroków.
  5. Wypisanie komunikatu o braku pierwiastka
  6. STOP
int wczytaj_liczba(double *liczba, int dodatnia)

Opis: funkcja wczytująca liczbę z pliku stdin do zmiennej liczba

Zmienne:
Nazwa Typ Opis
ciag[1000] char Bufor na wczytanie linii
wartosc double Wczytana wartość liczby
i int Miejsce na kod błędu zwracany z funkcji wez_liczba
*liczba double Zmienna pozwalająca zwrócić liczbę na zewnątrz
dodatnia int Jeżeli jest równa 1, zwracane są tylko liczby dodatnie
wynik int zwracany kod błędu

Algorytm:

  1. START
  2. Pobranie linii o maksymalnej długości 1000 znaków z stdin do zmiennej ciag
  3. przekształcenie pobranego ciągu znaków na liczbę typu double i zapisanie jej w zmiennej wartosc. W przypadku błędu wypisanie komunikatu i wyjście z kodem błędu
  4. W przypadku, gdy liczba miała być dodatnia, a jest ujemna, wypisanie błędu i wyjście z kodem błędu
  5. Przypisanie wyniku zmiennej liczba
  6. STOP
int licz_funkcja_pochodna(double iks)

Opis: funkcja obliczająca wartości funkcji i jej pochodnej dla zadanego iks i przypisująca je do zmiennych globalnych wart_funkcji i wart_pochodnej.

Zmienne:
Nazwa Typ Opis
iks double Wartość x, dla której liczona jest wartość funkcji i pochodnej
i int Używana do zwracania kodów błędów
wynik int zwracany kod błędu

Algorytm:

  1. START
  2. Obliczenie wartości funkcji dla zadanego iks. W przypadku błędu wypisanie komunikatu i wyjście z funkcji. Wypisanie wyniku
  3. Obliczenie wartości pochodnej dla zadanego iks. W przypadku błędu wypisanie komunikatu i wyjście z funkcji. Wypisanie wyniku
  4. STOP
void blad(int i, double value, char liczba[1000], int dodaj)

Opis: funkcja wypisująca błędy napotkane przez program przy obliczaniu (wzoru) funkcji, jej pochodnej albo wczytywaniu liczby (tzn. są do niej przekazywane kody błędów z funkcji wartosc_funkcji, wartosc_pochodnej i wez_liczba)

Zmienne:
Nazwa Typ Opis
j,z int Używane w pętlach
i int Kod błędu, który będzie komentowany
liczba[1000] char W tej zmiennej jest zawarty pierwotny wzór funkcji podany przez użytkownika
dodaj int Ile znaków spacji ma być napisane, gdy program wskazuje konkretne błędne miejsce we wzorze funkcji

Algorytm:

  1. START
  2. jeżeli i==1, wypisanie informacji o zbyt dużej ilości prawych nawiasów i wskazanie miejsca błędu we wzorze funkcji.
  3. jeżeli i==2, wypisanie informacji o dzieleniu przez zero i wskazanie miejsca błędu (jeżeli jest to możliwe) we wzorze funkcji
  4. jeżeli i==3, wypisanie informacji, że w liczbie może być tylko jedna kropka części dziesiętnej i wskazanie miejsca błędu we wzorze funkcji
  5. jeżeli i==4, wypisanie informacji o nieznanej funkcji matematycznej we wzorze funkcji
  6. jeżeli i==5, wypisanie informacji o nieznanym operatorze matematycznym. Wskazanie nieznanego znaku we wzorze funkcji.
  7. jeżeli i==6, wypisanie informacji o zbyt małej ilości pamięci.
  8. jeżeli i==7, informacja, że ostatnim znakiem we wzorze funkcji jest nawias lub znak działania
  9. jeżeli i==9, informacja, iż funkcja ln jest zdefiniowana tylko dla liczb dodatnich
  10. jeżeli i==11, informacja, iż minus może się znaleźć tylko na początku liczby
  11. jeżeli i>11 lub i==8, wypisanie informacji o błędzie.
  12. STOP
int oblicz_poziom(int wartosc)

Opis: Funkcji należy podać wartość wagi działania zapisanego w tablicy wagi struktury LICZBA. Funkcja zwróci poziom zagłębienia danej wagi. Jest wykorzystywana w wartosc_funkcji

Zmienne:
Nazwa Typ Opis
i int Waga, dla której będzie liczony poziom
zwracana int Wartość zwracana
wynik int zwracany poziom wagi

Algorytm:

  1. START
  2. przypisywanie zmiennej zwracana wartości poziomu wagi
  3. STOP
int oblicz_dzialanie(int wartosc)

Opis: Funkcji należy podać wartość wagi działania zapisanego w tablicy wagi struktury LICZBA. Funkcja zwróci kod działania danej wagi. Jest wykorzystywana w wartosc_funkcji

Zmienne:
Nazwa Typ Opis
i int Waga, dla której będzie liczone działanie
zwracana int Wartość zwracana
wynik int zwracany kod działania wagi

Algorytm:

  1. START
  2. przypisywanie zmiennej zwracana wartości dzialania wagi
  3. STOP
int dodaj_klocek(int numer, unsigned char *string, double liczba, int waga, LICZBA *mojaliczba)

Opis: Funkcja dodaje jedno działanie na pozycji "numer" do struktury mojaliczba. Jest wykorzystywana w wartosc_funkcji

Zmienne:
Nazwa Typ Opis
numer int Pozycja, na której będzie wstawione działanie
*string unsigned char Ciąg znakowy działania
liczba double Liczba działania
waga int Waga działania
*mojaliczba LICZBA W tej strukturze będzie przeprowadzona operacja dodawania
wynik int zwracany kod błędu

Algorytm:

  1. START
  2. Sprawdzenie, czy w zmiennej "mojaliczba" jest miejsce na nowy element:
  3. Przypisanie do struktur zmiennej mojaliczba nowego działania:
  4. Zwiększenie ilości elementów w strukturze "mojaliczba":
  5. STOP
int usun_klocek(int numer, int ileusunac, LICZBA *mojaliczba)

Opis: Funkcja usuwa działania ze struktury mojaliczba. Jest wykorzystywana w wartosc_funkcji

Zmienne:
Nazwa Typ Opis
numer int Pozycja, od której będą usuwane działania
ileusunac int Ile kolejnych działań usunąć
i int Używana w pętli
*mojaliczba LICZBA W tej strukturze będzie przeprowadzona operacja odejmowania
wynik int zwracany kod błędu

Algorytm:

  1. START
  2. Sprawdzenie, czy użytkownik nie chce usunąć za dużo działań:
  3. Usuwanie elementów:
  4. Zmniejszenie ilości elementów w strukturze mojaliczba:
  5. STOP
int wartosc_funkcji(unsigned char *ciag, double *zwroc_wartosc, double iks)

Opis: Funkcja oblicza wartość funkcji o wzorze podanym w ciąg dla x o wartości podanej w zmiennej iks.

Zmienne:
Nazwa Typ Opis
*ciag unsigned char Wzór funkcji
mojaliczba LICZBA wzór przechowywany w postaci zrozumiałej dla programu
i,j int Używane w pętlach
iks int x, dla którego obliczamy wartość funkcji
*zwroc_wartosc double Tutaj jest wzracana wartość funkcji
num int Numer "obrabianego" działania w strukturze mojaliczba
poziom int Poziom "obrabianego" działania w strukturze mojaliczba
wynik double Zmienna pomocnicza przechowująca liczbę pobraną ze struktury mojaliczba
mnoznik double Mnożnik dla liczby pobranej ze struktury mojaliczba
znaki[100] char Bufor pomocniczy na ciąg znaków ze struktury mojaliczba

W poniższym opisie przyjęto, iż:

W myśl powyższych definicji można przyjąć, iż wzór funkcji to ciąg znaków składający się z liczb i napisów przedzielanych działaniami. Aby móc obliczyć wartość danej funkcji dla podanego iks, należy (opis jest uproszczony i pokazuje ogólny zarys algorytmu - bez sprawdzania błędów, etc.):
  1. rozłożyć wzór funkcji na liczby i napisy oraz działania i zapisać je w odpowiedniej kolejności. Zostało to zrealizowane w ten sposób, iż:
    1. wartości liczb i napisów są zapisane dla kolejnych argumentów działań w tablicach liczby i stringi zmiennej mojaliczba (jest to struktura LICZBA).
    2. każde działanie zostało natomiast zapamiętane w tablicy wagi tejże zmiennej mojaliczba. Przy obliczaniu wagi działania wykonywane są następujące czynności:
      1. jeżeli jest to działanie (, wartość zmiennej pomocniczej poziom jest zwiększana o 1.
      2. jeżeli jest to działanie ), wartość zmiennej pomocniczej poziom jest zmniejszana o 1.
      3. jeżeli ostatnim argumentem działania był "napis" i obecne działanie to (, przypisuje mu się wagę 6. W przeciwnym razie: działaniom + - ^ zostają tam przypisane odpowiednio wartości 1 - 5:
        1. +: 1
        2. -: 2
        3. *: 3
        4. /: 4
        5. ^: 5
      4. Do obliczonej wagi dodaje się wartość zmiennej pomocniczej poziom * 6.
  2. ostatniemu elementowi w tablicy wagi w zmiennej mojaliczba przypisuje się wartość 0
  3. wartość napisów "x", "pi" i "e" zamienić na odpowiedającą wartość iks oraz stałych matematycznych
Następnie wykonywana jest pętla dopóki waga pierwszego elementu tablicy wagu w zmiennej mojaliczba jest różna od 0:
  1. wyszukiwana jest najwyższa waga w tablicy waga w zmiennej mojaliczba. Numer takiego elementu jest przypisywany do zmiennej pomocniczej num.
  2. wykonywane jest działanie między elementami num i num+1 w tablicy liczby i stringi zmiennej mojaliczba. Wynik działania jest przypisywany do elementu num tablicy liczby zmiennej mojaliczba. Wartość elementu num+1 w tablicy wagi jest przypisywana elementowi num. Wszystkie elementy od elementu num+2 w tablicy liczby i znaki są kopiowane do elementu num+1.
Przykład:

wzór

5*ln(x)+2-e

jest rozłożony następująco:
 
liczby znaki wagi
5 3
ln 6+6*1=12
x 1
2 2
e 0

Po zamianie zmiennej iks (iks przykładowo==3) i e tablice wyglądają następująco:
 
liczby znaki wagi
5 3
ln 6+6*1=12
3 1
2 2
2,7 0

Po wykonaniu pierwszego działania tablice wyglądają następująco:
 
liczby znaki wagi
5 3
1,0986 1
2 2
2,7 0

drugiego:
 
liczby znaki wagi
5,49306 1
2 2
2,7 0

itd.

Szczegółowy algorytm:

  1. START
  2. przypisanie warunków początkowych do zmiennych
  3. jeżeli stan==0:
    1. jeżeli aktualny znak w zmiennej *ciag to cyfra:
      1. przypisanie warunków początkowych dla zmiennych wynik, mnoznik, znaki
      2. stan=1
    2. jeżeli aktualny znak w zmiennej *ciag jest znakiem alfabetu:
      1. przypisanie warunków początkowych dla zmiennych wynik, znaki
      2. stan=2
    3. jeżeli aktualny znak w zmiennej *ciag to znak działania (+ - * / ^):
      1. jeżeli jest to ostatni znak zmiennej *ciag, wyjdz z błędem
      2. dodaj nowe działanie do struktury mojaliczba. Jeżeli jest tam za mało pamięci, wyjdź z błędem.
      3. przejdź do następnego znaku w strukturze ciag
    4. jeżeli aktualny znak w zmiennej *ciag to znak otwarcia nawiasu:
      1. jeżeli jest to ostatni znak zmiennej *ciag, wyjdz z błędem
      2. zwiększ zmienną poziom

      3. wyczyść kolejny element w strukturze mojaliczba i ustaw warunek początkowy dla zmiennej wynik
      4. przejdź do następnego znaku w strukturze ciag
    5. jeżeli aktualny znak w zmiennej *ciag to znak zamknięcia nawiasu:
      1. jeżeli poziom==0, wyjdz z błędem
      2. zmniejsz zmienną  poziom
      3. przejdź do następnego znaku w zmiennej ciag
    6. jeżeli aktualny znak w zmiennej *ciag to spacja:
      1. przejdź do następnego znaku w zmiennej ciag
    7. jeżeli aktualny znak w zmiennej *ciag nie jest spacją, znakiem otwarcia/zamknięcia nawiasu, znakiem działania, cyfrą i znakiem alfabetu:
      1. wyjdź z błędem
  4. jeżeli stan==1:
    1. jeżeli aktualny znak w zmiennej *ciag to cyfra:
      1. jeżeli mnoznik>=1 (liczba bez części ułamkowej):
        1. mnoznik=mnoznik*10
        2. wynik=wynik*10+(*ciag-'0')
      2. jezeli mnoznik<1 (liczba z częścią ułamkową):
        1. wynik=wynik+mnoznik*(*ciag-'0')
        2. mnoznik=mnoznik*0.1
      3. przejdź do następnego znaku w strukturze ciag
    2. jeżeli aktualny znak w zmiennej *ciag to kropka:
      1. jeżeli mnoznik>0.9:
        1. mnoznik=0.1
      2. jeżeli mnożnik <0.9:
        1. wyjdź z błędem
      3. przejdź do następnego znaku w strukturze ciag
    3. jeżeli aktualny znak w zmiennej *ciag to spacja:
      1. przejdź do następnego znaku w zmiennej ciag
    4. jeżeli aktualny znak w zmiennej *ciag nie jest spacją, cyfrą i kropką:
      1. stan==0
  5. jeżeli stan==2:
    1. jeżeli aktualny znak w zmiennej *ciag jest znakiem alfabetu:
      1. dodaj znak ze zmiennej *ciag do zmiennej znaki. Wielką literę zamień na małą.
      2. przejdź do następnego znaku w zmiennej ciag
    2. jeżeli aktualny znak w zmiennej *ciag jest znakiem otwarcia nawiasu:
      1. dodaj działanie do struktury mojaliczba
    3. jeżeli aktualny znak w zmiennej *ciag nie jest znakiem alfabetu:
      1. stan==0
  6. wróc do 3, jeżeli aktualny znak w zmiennej *ciag nie jest równy 0x00
  7. dodaj działanie do struktury mojaliczba
  8. i=0;
  9. jeżeli !strcmp(mojaliczba.stringi[i],"pi"):
    1. przypisz do mojaliczba.liczby[i] wartośc stałej PI
    2. wyczyść mojaliczba.stringi[i]
  10. jeżeli !strcmp(mojaliczba.stringi[i],"e"):
    1. przypisz do mojaliczba.liczby[i] wartośc stałej E
    2. wyczyść mojaliczba.stringi[i]
  11. jeżeli !strcmp(mojaliczba.stringi[i],"x"):
    1. przypisz do mojaliczba.liczby[i] wartośc zmiennej iks
    2. wyczyść mojaliczba.stringi[i]
  12. wróć do 9, jeżeli i<mojaliczba.ile
  13. do num przypisz indeks najwyższej wagi ze struktury mojaliczba, do j wartość tej wagi
  14. do j przypisz działanie wagi zapisanej w j
  15. jeżeli j==ST_DODAWANIE || j==ST_ODEJMOWANIE || j==ST_MNOZENIE || j==ST_DZIELENIE || j==ST_POTEGOWANIE:
    1. jeżeli strcmp(mojaliczba.stringi[num+1],"") wyjdź z błędem
    2. do mojaliczba.liczby[num] przypisz wynik działania dwuagrumentowego między mojaliczba.liczby[num] i mojaliczba.liczby[num+1]. Przy dzieleniu przez 0 wyjdź z błędem
    3. mojaliczba.wagi[num]=mojaliczba.wagi[num+1];
  16. jeżeli j==ST_DZIALANIE:
    1. jeżeli (!strcmp(mojaliczba.stringi[num],"ln")):
      1. mojaliczba.liczby[num]=log(mojaliczba.liczby[num+1]);
      2. jeżeli mojaliczba.liczby[num] jest niewłaściwa, wyjdź z błędem
      3. strcpy(mojaliczba.stringi[num],"");
      4. mojaliczba.wagi[num]=mojaliczba.wagi[num+1];
    2. jeżeli !strcmp(mojaliczba.stringi[num],"sin") || !strcmp(mojaliczba.stringi[num],"cos") || !strcmp(mojaliczba.stringi[num],"tan") || !strcmp(mojaliczba.stringi[num],"ctg"):
      1. do mojaliczba.liczby[num] przypisz wynik funkcji zapisanej w mojaliczba.liczby[num+1]. Dla ctg: jeżeli mojaliczba.liczby[num+1]==0, zwróć błąd
      2. jeżeli mojaliczba.liczby[num] jest niewłaściwa, wyjdź z błędem
      3. strcpy(mojaliczba.stringi[num],"");
      4. mojaliczba.wagi[num]=mojaliczba.wagi[num+1];
    3. jeżeli mojaliczba.stringi[num] różne od "sin", "cos", "tan", "ctg", "ln", zwróć błąd
  17. usuń działanie na pozycji n+1 ze struktury mojaliczba. Zmniejsz mojaliczba.ile.
  18. wróć do 13, jeżeli mojaliczba.ile!=0
  19. *zwroc_wartosc=mojaliczba.liczby[0];
  20. STOP
int wartosc_pochodnej(unsigned char *ciag, double *zwroc_wartosc, double iks)

Opis: Funkcja oblicza wartość pochodnej funkcji o wzorze podanym w ciąg dla x o wartości podanej w zmiennej iks.

Zmienne:
Nazwa Typ Opis
*ciag unsigned char Wzór funkcji
i int Używana do zwracania kodu błędu
iks int x, dla którego obliczamy wartość funkcji
*zwroc_wartosc double Tutaj jest wzracana wartość funkcji
wynik, wynik2 double Zmienne pomocnicze na wartości funkcji

Ogólny algorytm:

Liczenie pochodnej odbywa się z przyrostu różnicowego:

f'(x)=(f(x+dx)-f(x))/dx

Szczegółowy algorytm:

  1. START
  2. Obliczenie wartości funkcji dla x = iks+przyrost i przypisanie jej do zmiennej wynik. W przypadku wystąpienia błędu wyjście z funkcji z kodem błędu.
  3. Obliczenie wartości funkcji dla x = iks i przypisanie jej do zmiennej wynik2. W przypadku wystąpienia błędu wyjście z funkcji z kodem błędu.
  4. *zwroc_wartosc=(wynik-wynik2)/przyrost;
  5. STOP
int wez_liczba(unsigned char *ciag, double *wartosc)

Opis: Z ciągu *ciag wyciąga liczbę rzeczywistą i zapisuje w zmiennej *wartosc.

Zmienne:
Nazwa Typ Opis
*ciag unsigned char Z tego ciągu wyciągamy liczbę
*wartosc double Wartość zwracana
wynik double Liczba podczas wczytywania liczby z ciągu
mnoznik double Mnożnik dla kolejnej cyfry liczby wczytywanej z ciągu
num int Numer sprawdzanego znaku w ciągu znaków
minus int Czy jest już liczba ujemna (wartość 1) czy nie (wartość!=1)
wynik int zwracany kod błędu

Ogólny algorytm:

Dla każdego znaku w ciągu znaków ciag sprawdzane jest, czy może się znaleźć w prawidłowo napisanej liczbie (tzn. dopuszczona jest dowolna ilość cyfr, dokładnie jeden znak kropki, spacje oraz (wyłącznie jako pierwszy znak) dokładnie raz znak minus). Zgodnie z nimi odpowiednio modyfikowana jest wartość liczby wynik.

Szczegółowy algorytm:

  1. START
  2. jeżeli aktualny znak w zmiennej *ciag to cyfra:
    1. jeżeli mnoznik>=1 (liczba bez części ułamkowej):
      1. mnoznik=mnoznik*10
      2. wynik=wynik*10+(*ciag-'0')
    2. jezeli mnoznik<1 (liczba z częścią ułamkową):
      1. wynik=wynik+mnoznik*(*ciag-'0')
      2. mnoznik=mnoznik*0.1
    3. przejdź do następnego znaku w strukturze ciag. Zwiększ num
  3. jeżeli aktualny znak w zmiennej *ciag to minus:
    1. jeżeli num!=0 wyjdź z błędem
    2. minus=1
    3. przejdź do następnego znaku w strukturze ciag. Zwiększ num
  4. jeżeli aktualny znak w zmiennej *ciag to kropka:
    1. jeżeli mnoznik>0.9:
      1. mnoznik=0.1
    2. jeżeli mnożnik <0.9:
      1. wyjdź z błędem
    3. przejdź do następnego znaku w strukturze ciag. Zwiększ num
  5. jeżeli aktualny znak w zmiennej *ciag to spacja:
    1. przejdź do następnego znaku w zmiennej ciag. Zwiększ num
  6. jeżeli aktualny znak w zmiennej *ciag nie jest spacją, cyfrą i kropką i minusem:
    1. wyjdź z błędem
  7. jeżeli aktualny znak w zmiennej *ciąg !=0x00, wróć do 2
  8. *wartosc=wynik;
  9. jeżeli minus==1 *wartosc=-wynik;
  10. STOP
6. Testowanie projektu

Projekt został przetestowany na różnych zestawach danych (przykładowe dwa są zawarte w katalogu /Docs).

Podczas testowania zwracano uwagę na eliminację błędów numerycznych oraz na odporność na różnego rodzaju niewłaściwe dane. Usunięto wszelkie znalezione usterki.

Wiele procedur zawiera obecnie różne informacje debugujące pozwalające kontrolować poprawność ich działania. Aby je uaktywnić, należy w pliku config.h usunąć komentarz z linii "#define DEBUG" i skompilować projekt ponownie.