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. Spis treści


  1. Spis treści
  2. Wprowadzenie
  3. Budowa ogólna projektu
  4. Sposób kompilacji projektu
  5. Użytkowanie projektu
  6. Znane błędy i ograniczenia projektu
  7. Materiały źródłowe
  8. Budowa poszczególnych plików projektu
  9. Kod źródłowy
2. Wprowadzenie

Metoda Newtona pozwala na obliczanie przybliżonych wartości pierwiastków równania f(x)=0. Założenia tej metody są następujące: w przedziale , 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.

Projekt jest praktyczną realizacją tej metody. Pozwala on na policzenie pierwiastka z zadaną dokładnością. Wykorzystuje on sposób implementacji podany w pozycji 1 literatury.

3. Budowa ogólna projektu


Pliki projektu zostały podzielone i zapisane w kilku katalogach:

Budowa poszczególnych elementów plików została omówiona w punkcie 8 dokumentacji.

4. Sposób kompilacji projektu


Kolejne kroki potrzebne do kompilacji projektu:

Rezultatem działania komendy "make" powinien być plik wykonywalny "projekt" w podkatalogu "projekt".

5. Użytkowanie projektu


Program "projekt" po uruchomieniu wymaga trzech 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
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 "+", "-", "*", "/", "^".

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ń.

6. 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 3).

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ć).

Z uwagi na trudności z obliczaniem pochodnej funkcji zaleca się również podawać możliwie jak najprostsze wzory funkcji. Program w obecnej formie może nie liczyć poprawnie wyrażeń typu x^(-a) czy wyrażeń w nawiasach. Zaleca się z tego powodu sprawdzanie poprawności wzoru wypisywanej pochodnej. Rozbudowanie modułu obliczającego pochodną sprowadza się do rozszerzenia funkcji przygotuj_pochodna w module funkcje.h

7. Materiały źródłowe


  1. "Metody numeryczne" Zenon Fortuna, Nohdan Macukow, Janusz Wąsowski (opis i sposób implementacji metody Newtona)
8. 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
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
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
moja_liczba LICZBA Struktura, w której są przechowywane wzory funkcji i później pochodnej
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

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
delta double Wartość delty w metodzie Newtona
oldiks double Poprzednio wyliczona wartość x
wynik int Kod błędu, który jest zarazem kodem błędu programu

Algorytm:

  1. START
  2. wypisanie komunikatu i wczytanie wzoru funkcji do zmiennej wzór:
  3. printf("Wczytywanie wzoru funkcji     ");
    GetLine(stdin, wzor,1000); //pobieramy wzor funkcji z wejscia
    printf("\n");
  4. wypisanie komunikatu i wczytanie dokładności obliczeń do zmiennej dokładność (z założeniem, że jest ona dodatnia)
  5. printf("Wczytywanie dokladnosci       ");
    i=wczytaj_liczba(&dokladnosc,1);
    if (i!=0) return i;
    printf("\n");
  6. wypisanie komunikatu i wczytanie punktu startowego obliczeń obliczeń do zmiennej iks
  7. printf("Wczytywanie punktu startowego ");
    i=wczytaj_liczba(&iks,0);
    if (i!=0) return i;
    printf("\n");
  8. wypisanie komunikatu i wczytanie ilości kroków do zmiennej ile_kroków (z założeniem, że jest ona dodatnia)
  9. printf("Wczytywanie ilosci krokow     ");
    i=wczytaj_liczba(&oldiks,1);
    if (i!=0) return i;
    ile_krokow=oldiks;
    printf("\n");
  10. Wypisanie wczytanej dokładności, punktu startowego i ilości kroków
  11. printf("Wczytano dane: dokladnosc=%f, punkt startowy=%f, ile_krokow=%i\n",
        dokladnosc,iks,ile_krokow);
  12. Obliczenie wartości funkcji i wartości pochodnej dla zadanego x. W przypadku błędu wyjście z programu z odpowiednim kodem błędu
  13. /* Obliczanie pierwszego punktu */
    i=licz_funkcja_pochodna(iks);
    if (i!=0) return i;
  14. Pętla
  15. for (j=0;j<ile_krokow;j++)
    1. dla wartości funkcji == 0 wypisanie komunikatu i wyjście z programu:
    2. if (wart_funkcji==0) {
        printf("Pierwiastek osiagnieto dla x=%f przy kroku %i\n",iks,j);
        return 0;
      }
    3. Dla wartości pochodnej == 0 wypisanie komunikatu i wyjście z programu z kodem błędu:
    4. /* Pochodna = 0, a my musimy przez nia dzielic (obliczanie nowego iks. */
      if (wart_pochodnej==0)
      {
        printf("Blad: dla x=%f pochodna=0\n",iks);
        return 20;
      }
    5. Przypisanie zmiennej "oldiks" wartości zmiennej "iks"
    6. /* Stary punkt bedzie potrzebny do delty */
      oldiks=iks;
    7. Liczenie wartości nowego punktu x:
    8. /* Liczymy nowy punkt */
      iks=iks-(wart_funkcji/wart_pochodnej);
    9. Liczenie wartości funkcji i pochodnej w punkcie x. W przypadku błędu wypisanie komunikatu i wyjście z błędem z programu:
    10. i=licz_funkcja_pochodna(iks);
      if (i!=0) return i;
    11. Obliczanie dokładności i przypisanie jej do zmiennej "delta"
    12. /* Badanie dokladnosci */
      if (iks>1 || iks<-1) {
          /* dla modul z iks > 1 */
          delta=(iks-oldiks)/iks;
      } else {
          delta=(iks-oldiks);
      }
    13. Sprawdzenie, czy osiągnięto pierwiastek z wymaganą dokładnością. Jeżeli tak, wypisanie komunikatu i wyjście z programu
    14. /* modul z Delta <= dokladnosc i modul z iks <= 100*dokladnosc */
      if ((delta<=dokladnosc && delta>=(-dokladnosc)) &&
          (iks<(100*dokladnosc) && iks>-(100*dokladnosc))) {
          printf("Pierwiastek osiagnieto dla x=%f przy kroku %i\n",iks,j);
          return 0;
      }
  16. Wypisanie komunikatu o braku pierwiastka
  17. printf("Blad: nie znaleziono pierwiastka w %i krokach\n",ile_krokow);
    printf("\n");
  18. 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. GetLine(stdin, ciag,1000); //pobieramy linijke z wejscia
  4. wypisanie pobranej wartości
  5. dprintf("ciag = %s\n",ciag);
  6. 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
  7. i=wez_liczba(ciag,&wartosc);
    mojblad=wartosc;
    if (i!=0) {
            blad(i,wartosc,ciag,31);
            return i;
    }
  8. W przypadku, gdy liczba miała być dodatnia, a jest ujemna, wypisanie błędu i wyjście z kodem błędu
  9. if (dodatnia==1 && wartosc<0) {
            i=12;
            blad(i,wartosc,ciag,31);
            return i;
    }
  10. Przypisanie wyniku zmiennej liczba
  11. *liczba=wartosc;
  12. STOP
int licz_funkcja_pochodna(double iks)

Opis: funkcja obliczająca wartości funkcji i jej pochodnej dla zadanego xliczba

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. Wypisanie komunikatu
  3. printf("Liczenie pochodnej i wartosci funkcji dla x=%f\n",iks);
  4. Wypisanie komunikatu i rozłożenie podanego wzoru funkcji na elementy zrozumiałe dla programu. W przypadku błędu wypisanie komunikatu i wyjście z funkcji
  5. printf("Funkcja wejsciowa : %s\n",wzor);
    /* Rozkladamy ciag na male elementy */
    i=przygotuj_funkcja(wzor,&moja_liczba);
    if (i!=0) { //mamy blad
       blad(i,wart_funkcji,wzor,21);
       return i;
    }
  6. Obliczenie wartości funkcji dla zadanego iks. W przypadku błędu wypisanie komunikatu i wyjście z funkcji. Wypisanie wyniku
  7. /* Liczmy wartosc funkcji */
    i=wartosc_funkcji(&wart_funkcji,iks,&moja_liczba);
    if (i!=0) {
            blad(i,wart_funkcji,wzor,21);
            return i;
    } else {
            /* Wynik nie jest liczba */
            if (isinf(wart_funkcji)) {
                printf("wynik niewlasciwy \n");
            } else {
                printf("wynik %f \n",wart_funkcji);
            }
    }
  8. Przygotowanie pochodnej w postaci zrozumiałej dla programu ze wzoru funkcji
  9. /* Z wzoru funkcji robimy pochodna */
    i=przygotuj_pochodna(wzor,&moja_liczba);
    if (i!=0) {
            blad(i,wart_pochodnej,wzor,21);
            return i;
    }
  10. Wypisanie obliczonego wzoru pochodnej
  11. printf("Pochodna: ");    
    pisz_funkcja(&moja_liczba); //wypiszemy jej wzor
  12. Obliczenie wartości pochodnej dla zadanego iks. W przypadku błędu wypisanie komunikatu i wyjście z funkcji. Wypisanie wyniku
  13. /* Liczmy wartosc funkcji */
    i=wartosc_funkcji(&wart_funkcji,iks,&moja_liczba);
    if (i!=0) {
            blad(i,wart_funkcji,wzor,21);
            return i;
    } else {
            /* Wynik nie jest liczba */
            if (isinf(wart_funkcji)) {
                printf("wynik niewlasciwy \n");
            } else {
                printf("wynik %f \n",wart_funkcji);
            }
    }
  14. 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 lub jej pochodnej

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. Instrukcja wyboru:
  3. switch (i)
      case 0:
      1. wyjście z instrukcji
      2. break;
      case 1:
      1. wypisanie odpowiedniej ilości spacji tak, by kursor znalazł się na pod początkiem wzoru funkcji
      2. for (j=0;j<dodaj;j++) {printf(" ");}
      3. wypisanie odpowiedniej ilości spacji tak, by kursor znalazł się na pod w odpowiednim miejscu wzoru funkcji
      4. for (j=0;j<mojblad-1;j++) {printf(" ");}
      5. wypisanie znaku wskazującego miejsce błędu i wypisanie informacji
      6. printf("^\n");
        printf("Blad: za duzo nawiasow prawych\n");
      7. wyjście z instrukcji
      8. break;
      case 2:
      1. próba znalezenia i wypisanie znaku wskazującego miejsce błędu
      2. for (j=0;j<strlen(liczba)-1;j++) {
                if (!strcmp(liczba+j,"/0")) {
                    printf("                     ");
                    for (z=0;z<j;z++) {printf(" ");}
                    printf("^\n");
                }
        }
      3. wypisanie informacji dla użytkownika
      4. printf("Blad: dzielenie przez zero\n");
      5. wyjście z instrukcji
      6. break;
      case 3:
      1. wypisanie odpowiedniej ilości spacji tak, by kursor znalazł się na pod początkiem wzoru funkcji
      2. for (j=0;j<dodaj;j++) {printf(" ");}
      3. wypisanie odpowiedniej ilości spacji tak, by kursor znalazł się na pod w odpowiednim miejscu wzoru funkcji
      4. for (j=0;j<mojblad-1;j++) {printf(" ");}
      5. wypisanie znaku wskazującego miejsce błędu i wypisanie informacji
      6. printf("^\n");
        printf("Blad: w liczbie moze byc tylko jedna
            kropka czesci dziesietnej\n");
      7. wyjście z instrukcji
      8. break;
      case 4:
      1. wypisanie informacji
      2. printf("Blad: nieznana funkcja matematyczna \"%s\"\n",liczba);
      3. wyjście z instrukcji
      4. break;
      case 5:
      1. wypisanie odpowiedniej ilości spacji tak, by kursor znalazł się na pod początkiem wzoru funkcji
      2. for (j=0;j<dodaj;j++) {printf(" ");}
      3. wypisanie odpowiedniej ilości spacji tak, by kursor znalazł się na pod w odpowiednim miejscu wzoru funkcji
      4. for (j=0;j<mojblad-1;j++) {printf(" ");}
      5. wypisanie znaku wskazującego miejsce błędu i wypisanie informacji
      6. printf("^\n");
        printf("Blad: nie znam takiego operatora matematycznego\n");
      7. wyjście z instrukcji
      8. break;
      case 6:
      1. wypisanie informacji
      2. printf("Blad: za duzo elementow w dzialaniu (max %i)\n",
           MAX_ELEMENTOW);
      3. wyjście z instrukcji
      4. break;
      case 7:
      1. wypisanie informacji
      2. printf("Blad: Podane wyrazenie konczy sie znakiem
           dzialania (nawiasem) !\n");
      3. wyjście z instrukcji
      4. break;
      case 8:
      1. wypisanie informacji
      2. printf("Blad: jak obliczyc pochodna x^x ?\n");
      3. wyjście z instrukcji
      4. break;
      case 9:
      1. wypisanie informacji
      2. printf("Blad: funkcja ln jest zdefiniowana tylko dla
           wartosci dodatnich\n");
      3. wyjście z instrukcji
      4. break;
      case 10:
      1. wypisanie informacji
      2. printf("Blad: zbyt skomplikowana pochodna\n");
      3. wyjście z instrukcji
      4. break;
      case 11:
      1. wypisanie informacji
      2. printf("Blad: minus moze byc TYLKO na poczatku liczby\n");
      3. wyjście z instrukcji
      4. break;
      default:
      1. wypisanie informacji
      2. dprintf("BLAD w programie. Prosze raportowac
            (wartosc %i dla i)\n",i);
      3. wyjście z instrukcji
      4. break;
  4. 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.

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. warunek początkowy:
  3. zwracana=0;
  4. przypisywanie zmiennej zwracana wartości poziomu wagi
  5. while (wartosc>6) {wartosc=wartosc-6;zwracana++;};
  6. 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.

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. warunek początkowy:
  3. zwracana=wartosc;
  4. przypisywanie zmiennej zwracana wartości dzialania wagi
  5. while (zwracana>6) {zwracana=zwracana-6;};
  6. 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.

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. if (numer+1>MAX_ELEMENTOW) return 6; //za malo pamieci
  4. Przypisanie do struktur zmiennej mojaliczba nowego działania:
  5. mojaliczba->liczby[numer]=liczba;
    strcpy(mojaliczba->stringi[numer],string);
    mojaliczba->wagi[numer]=waga;
  6. Zwiększenie ilości elementów w strukturze "mojaliczba":
  7. mojaliczba->ile++;
  8. STOP
int usun_klocek(int numer, int ileusunac, LICZBA *mojaliczba)

Opis: Funkcja usuwa działania ze struktury mojaliczba.

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. if (numer-ileusunac>mojaliczba->ile) {
            dprintf("Blad w usun. Prosze raportowac\n");
            return 1;
    }
  4. Usuwanie elementów:
  5. for (i=numer;i<mojaliczba->ile-ileusunac+1;i++) {       
            mojaliczba->liczby[i]=mojaliczba->liczby[i+ileusunac];
            strcpy(mojaliczba->stringi[i],mojaliczba->stringi[i+ileusunac]);
            mojaliczba->wagi[i]=mojaliczba->wagi[i+ileusunac];
    }
  6. Zmniejszenie ilości elementów w strukturze mojaliczba:
  7. mojaliczba->ile=mojaliczba->ile-ileusunac;
  8. STOP
void pisz_funkcja(LICZBA *mojaliczba)

Opis: Funkcja wypisuje wzór funkcji ze struktury mojaliczba.

Zmienne:
Nazwa Typ Opis
*mojaliczba LICZBA Wypisujemy wzór funkcji tej struktury
i int Używana w pętli
poziom int poziom wag kolejnych działań

Algorytm:

  1. START
  2. Informacje debugujące:
  3. dprintf("wchodzi do pisz_funkcja\n");
        
    #ifdef DEBUG    
    /* Wypisuje calosc liczby */
    dprintf("lp liczby stringi wagi\n");
    for (i=0;i<mojaliczba->ile;i++) {
            dprintf("%i %f \"%s\" %i %i \n",i,mojaliczba->liczby[i],
                mojaliczba->stringi[i],mojaliczba->wagi[i],
                oblicz_dzialanie(mojaliczba->wagi[i]));
    }
    dprintf("\n");
    printf("funkcja : ");
    #endif
  4. pętla "dla każdego elementu struktury mojaliczba:
  5. for (i=0;i<mojaliczba->ile;i++) {
    1. Poziom tego działania jest większy niż poprzedniego, więc pisz nawias:
    2. if (oblicz_poziom(poziom)<oblicz_poziom(mojaliczba->wagi[i]))
         printf("(");
    3. Wypisz string/liczbę danego elementu:
    4. if (strcmp(mojaliczba->stringi[i],"")) {
          printf("%s",mojaliczba->stringi[i]);
      } else {
          printf("%f",mojaliczba->liczby[i]);
      }
    5. Jeżeli poziom tego działania jest mniejszy od poprzedniego, napisz nawias:
    6. if (oblicz_poziom(poziom)>oblicz_poziom(mojaliczba->wagi[i]))
         printf(")");
    7. przypisz zmiennej poziom wagę aktualnego działania:
    8. poziom=mojaliczba->wagi[i];
    9. wypisz znak działania aktualnego działania:
    10. switch (oblicz_dzialanie(poziom)) {
          case 1: printf("+"); break;
          case 2: printf("-"); break;
          case 3: printf("*"); break;
          case 4: printf("/"); break;
          case 5: printf("^"); break;
      }
  6. STOP
int przygotuj_funkcja(unsigned char *ciag, LICZBA *mojaliczba)

Opis: Rozkłada wzór funkcji podanej jako ciąg na elementy struktury mojaliczba.

Zmienne:
Nazwa Typ Opis
*ciag unsigned char Tutaj jest wzór w formie napisu
*mojaliczba LICZBA W tej strukturze umieścimy rozłożone działanie
poziom int Waga przygotowywanego działania
znaki[100] char Bufor na znaki podczas wczytywania tekstu z ciągu
wynik double Liczba podczas wczytywania liczby z ciągu
mnoznik double Mnożnik dla kolejnej cyfry liczby wczytywanej z ciągu
stan int Wewnętrzny stan funkcji
num int Numer sprawdzanego znaku
wynik int zwracany kod błędu

Algorytm:

  1. START
  2. Informacja debugująca i przypisanie warunków początkowych:
  3. dprintf("wchodzi do przygotuj_string\n");
    
    /* Warunki poczatkowe */
    znaki[0]=0;
    mojaliczba->wagi[0]=0;
    mojaliczba->ile=0;
  4. Pętla
  5. /* Znak 0x00 konczy ciag. Wykonujemy petle az do niego */    
    while (*ciag!=0x00) {
    1. Instukcja sprawdzania dla cyfr, znaków działań, itp.:
    2. if (stan==0) { //start i znaki dzialan, nawiasy
      1. Dla cyfr:
      2. if ((*ciag>='0' && *ciag<='9') || *ciag=='.') { //cyfry lub kropka
        1. Przypisanie stanu początkowego i zmiana stanu na sprawdzanie liczb
        2. wynik=0; mnoznik=1; //wartosc domyslne dla liczby
          znaki[0]=0; //czyscimy
          stan=1; //teraz bedziemy obrabiac liczbe
      3. dla znaków innych niż kropka i cyfra
      4. } else {
        1. dla znaków alfabetu:
        2. if ((*ciag>='a' && *ciag<='z') || /* znaki alfabetu */
             (*ciag>='A' && *ciag<='Z')) { /*     -"-        */
          1. Ustalenie warunków początkowych i zmiana stanu na sprawdzanie tekstów:
          2. znaki[0]=0; //czyscimy
            wynik=0; //czyscimy
            stan=2; //teraz bedziemy obrabiac ciag znakow
        3. Dla znaków innych niż znaki alfabetu:
        4. } else {
          1. W zależności od znaku:
          2. switch (*ciag) {
            1. Dla znaków działań:
            2. case '+': /* Znaki dzialan */
              case '-': /*      -"-      */
              case '*': /*      -"-      */
              case '/': /*      -"-      */
              case '^': /*      -"-      */
              1. Jeżeli jest to ostatni znak w ciągu, pokaż błąd:
              2.  //znak dzialania jest ostatni w ciagu
                if (*(ciag+1)==0x00) return 7;
              3. Dodaj działanie lub zwróć błąd, gdy nie ma na to pamięci:
              4. /* Tworzymy nowa pozycje */
                switch (*ciag) {
                  case '+':
                    if (dodaj_klocek(mojaliczba->ile,
                      znaki, wynik, ST_DODAWANIE+6*poziom, 
                      mojaliczba)!=0)
                       return 6; //za malo pamieci
                    break;
                  case '-':
                    if (dodaj_klocek(mojaliczba->ile,
                      znaki, wynik, ST_ODEJMOWANIE+6*poziom, 
                      mojaliczba)!=0)
                       return 6; //za malo pamieci
                    break;
                  case '*':
                    if (dodaj_klocek(mojaliczba->ile,
                      znaki, wynik, ST_MNOZENIE+6*poziom, 
                      mojaliczba)!=0)
                       return 6; //za malo pamieci
                    break;
                  case '/':
                    if (dodaj_klocek(mojaliczba->ile,
                      znaki, wynik, ST_DZIELENIE+6*poziom, 
                      mojaliczba)!=0)
                       return 6; //za malo pamieci
                    break;
                  case '^':
                    if (dodaj_klocek(mojaliczba->ile,
                      znaki, wynik, ST_POTEGOWANIE+6*poziom, 
                      mojaliczba)!=0)
                       return 6; //za malo pamieci
                    break;
                }
              5. Przejście do sprawdzania następnego znaku:
              6. ciag++;num++; //przechodzimy znak do przodu
            3. Dla otwarcia nawiasu:
            4. case '(': /* Otwieramy nawias */
              1. Jeżeli jest to ostatni znak w ciągu pokaż błąd:
              2.  //nawias jest ostatni w ciagu
                if (*(ciag+1)==0x00) return 7;
              3. Zwiększenie poziomu kolejnych działań:
              4. poziom++;
              5. Czyszczenie zmiennych potrzebne do następnego działania:
              6. mojaliczba->liczby[mojaliczba->ile]=0;
                strcpy(znaki,""); //czyscimy
                wynik=0; //czyscimy
              7. Przejście do sprawdzania następnego znaku:
              8. ciag++;num++; //przechodzimy znak do przodu
            5. Dla zamknięcia nawiasu:
            6. case ')': /* Zamykamy nawias */
              1. Jeżeli więcej nawiasów prawych niż lewych, zwróć błąd:
              2. /* Za duzo nawiasow prawych */
                if (poziom==0) {
                   mojaliczba->ile=num;
                   return 1;
                }
              3. Zmniejszenie poziomu kolejnych działań:
              4. poziom--;
              5. Przejście do sprawdzania następnego znaku:
              6. ciag++;num++; //przechodzimy znak do przodu
            7. Dla spacji:
            8. case ' ': /* Spacje po prostu ignorujemy */
              1. Przejście do sprawdzania następnego znaku:
              2. ciag++;num++; //przechodzimy znak do przodu
            9. Dla innych znaków:
            10. default: //nieznany znak
              1. Wyjście z błędem:
              2. mojaliczba->ile=num;
                return 5;
    3. Sprawdzanie liczb:
    4. if (stan==1) { //cyfry i kropka dziesietna
      1. Dla cyfr:
      2. /* Mamy cyfre */
        if (*ciag>='0' && *ciag<='9') {
        1. Odpowiednie zwiększenie liczby
        2. /* ... wiec dodajemy odpowiednio do naszej liczby */
          if (mnoznik>=1) { //liczby bez czesci ulamkowej
              mnoznik=mnoznik*10;
              wynik=wynik*10+(*ciag-'0');
          } else { //i z czescia ulamkowa
              wynik=wynik+mnoznik*(*ciag-'0');
              mnoznik=mnoznik*0.1;
          }
        3. Przejście do sprawdzania następnego znaku:
        4. ciag++;num++; //przechodzimy znak do przodu
      3. Dla znaków innych niż cyfry:
      4. } else {
        1. W zależności od znaku:
        2. switch (*ciag) {
          1. Dla kropki:
          2. case '.': /* Kropka wprowadza znaki dziesietne */
            1. Jeżeli nie była to liczba z częścią dziesiętną, zrobienie takiej. W przeciwnym razie zwrócenie błędu (kropka jest 2 raz w liczbie):
            2. if (mnoznik>0.9) {
                  mnoznik=0.1;
              } else {
                  /* Nie moze byc dwoch kropek w liczbie */
                  mojaliczba->ile=num;
                  return 3;
              }
            3. Przejście do sprawdzania następnego znaku:
            4. ciag++;num++; //przechodzimy znak do przodu
          3. Dla spacji:
          4. case ' ': /* Spacje po prostu ignorujemy */
            1. Przejście do sprawdzania następnego znaku:
            2. ciag++;num++; //przechodzimy znak do przodu
          5. Dla innych znaków:
          6. default:
            1. Zmiana stanu na 0
            2. stan=0;
    5. Sprawdzanie stringów:
    6. if (stan==2) { //znaki
      1. Dla małych znaków alfabetu:
      2. if (*ciag>='a' && *ciag<='z') { //male znaki
        1. Dodanie kolejnego znaku do zmiennej znaki:
        2. znaki[strlen(znaki)+1]=0; //zamykamy zwiekszony ciag znakiem 0
          znaki[strlen(znaki)]=*ciag;  //dodajemy znak
        3. Przejście do sprawdzania następnego znaku:
        4. ciag++;num++; //przechodzimy znak do przodu
      3. Dla innych:
      4. } else {
        1. Dla dużych znaków alfabetu:
        2. if (*ciag>='A' && *ciag<='Z') { //duze znaki
          1. Dodanie kolejnego znaku do zmiennej znaki:
          2. //zamykamy zwiekszony ciag znakiem 0
            znaki[strlen(znaki)+1]=0;
            //dodajemy+ konwersja na male litery
            znaki[strlen(znaki)]=*ciag-('A'-'a');
          3. Przejście do sprawdzania następnego znaku:
          4. ciag++;num++; //przechodzimy znak do przodu
        3. w przeciwnym razie:
        4. } else {
          1. Jeżeli aktualnie jest znak "(" w ciągu, dodajemy jako funkcję:
          2. if (*ciag=='(') { //dla funkcji typu cos(x)..
               if (dodaj_klocek(mojaliczba->ile, znaki, wynik,
               ST_FUNKCJA+6*poziom, mojaliczba)!=0)
                  return 6; //za malo pamieci
                                }
          3. Powrót go głównej pętli:
          4. stan=0; //do glownej petli
  6. dodanie ostatniego elementu do struktury mojaliczba:
  7. /* Po wyjsciu z petli cos tam zawsze zostalo niedokonczone. Wstawmy to */
    if (dodaj_klocek(mojaliczba->ile, znaki, wynik, 0 , mojaliczba)!=0)
       return 6; //za malo pamieci
  8. STOP
int wartosc_funkcji(double *zwroc_wartosc, double iks, LICZBA *mojaliczba)

Opis: Funkcja oblicza wartość funkcji podanej w mojaliczba dla x o wartości podanej w zmiennej iks.

Zmienne:
Nazwa Typ Opis
*mojaliczba LICZBA Obliczamy wartość funkcji tej struktury
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
wynik int zwracany kod błędu

Algorytm:

  1. START
  2. Informacje debugujące:
  3. dprintf("wchodzi do wartosc funkcji\n");
  4. przeglądanie kolejnych elementów struktury mojaliczba. Jeżeli w którejś użyto liczb "e" lub "pi", zamieniane są na ich odpowiedniki liczbowe. Podobnie "x" zamieniany na wartość x, dla której będzie liczona wartość funkcji:
  5. /* Zamieniamy napisy "pi" i "e" na odpowiadajace im stale matematyczne,
       jak rowniez zamiast iksa wstawiamy odpowiadajaca mu wartosc */
    for (i=0;iile;i++) {
       if (!strcmp(mojaliczba->stringi[i],"pi")) { //liczba PI
          mojaliczba->liczby[i]=M_PI;
          strcpy(mojaliczba->stringi[i],"");
       }    
       if (!strcmp(mojaliczba->stringi[i],"e")) { //liczba Eulera
          mojaliczba->liczby[i]=M_E;
          strcpy(mojaliczba->stringi[i],"");
       }    
       if (!strcmp(mojaliczba->stringi[i],"x")) { //iks
          mojaliczba->liczby[i]=iks;
    
          strcpy(mojaliczba->stringi[i],"");
       }    
    }
  6. Pętla wykonująca dopóty, dopóki mamy jakieś działania w strukturze mojaliczba:
  7. /* Dopoki waga dzialania!=0. Czyli dopoki mamy dzialania */    
    while (mojaliczba->ile!=0) {
    1. Warunek początkowy:
    2. j=mojaliczba->wagi[0];num=0; //warunki poczatkowe
    3. Szukamy działania o najwyższej wadze. Jego numer przypisujemy do num:
    4. /* szukamy dzialania o najwyzszej wadze */
      for (i=0;iile;i++) {
          if (mojaliczba->wagi[i]>j) {j=mojaliczba->wagi[i];num=i;}
      }
    5. Zmiennej j przypisujemy wartość działania (bez jego poziomu):
    6. j=oblicz_dzialanie(j);
    7. Instrukcja wyboru:
    8. switch (j) {
      1. Dla działań liczbowych:
      2. case 1: /* Dodawanie   */
        case 2: /* odejmowanie */
        case 3: /* mnozenie    */
        case 4: /* dzielenie   */
        case 5: /* potegowanie */
        1. Drugi człon działania jest napisem. Czyli jest błędny (x, pi i e były wcześniej zamieniane na liczby):
        2. //jakis dziwny string
          if (strcmp(mojaliczba->stringi[num+1],"")) {
             strcpy(napis,mojaliczba->stringi[num+1]);
             return 4;
          }
        3. Obliczenie działania (przy dzieleniu sprawdzamy, czy nie dzielimy przez 0):
        4. switch (j) {
              case 1:mojaliczba->liczby[num]=mojaliczba->liczby[num]+
                     mojaliczba->liczby[num+1];break;
              case 2:mojaliczba->liczby[num]=mojaliczba->liczby[num]-
                     mojaliczba->liczby[num+1];break;
              case 3:mojaliczba->liczby[num]=mojaliczba->liczby[num]*
                     mojaliczba->liczby[num+1];break;
              case 4:if (mojaliczba->liczby[num+1]==0) return 2;
                     mojaliczba->liczby[num]=mojaliczba->liczby[num]/
                     mojaliczba->liczby[num+1];
                     break;
              case 5:mojaliczba->liczby[num]=pow(mojaliczba->liczby[num],
                     mojaliczba->liczby[num+1]);
          }
        5. przypisanie wagi 2 członu działania 1 członowi:
        6. mojaliczba->wagi[num]=mojaliczba->wagi[num+1];
      3. Dla funkcji:
      4. case 6: //funkcje matematyczne
        1. Jeżeli mamy "ln":
        2. if (!strcmp(mojaliczba->stringi[num],"ln")) {
          1. Obliczenie:
          2. mojaliczba->liczby[num]=log(mojaliczba->liczby[num+1]);
          3. Jeśli wartość logarytmu nie była zdefiniowana, zwracamy błąd:
          4. if (isnan(mojaliczba->liczby[num])) return 9;
          5. Czyszczenie drugiej części działania:
          6. strcpy(mojaliczba->stringi[num],"");
          7. przypisanie wagi 2 członu działania 1 członowi:
          8. mojaliczba->wagi[num]=mojaliczba->wagi[num+1];
        3. W przeciwnym razie:
        4. } else {
          1. Zwrócenie błędu (w zmiennej napis znajduje się błędna funkcja):
          2. strcpy(napis,mojaliczba->stringi[num]);
            return 4;
    9. Usuwamy drugą część działania:
    10. usun_klocek(num+1,1,mojaliczba);
  8. Przypisujemy obliczoną wartość funkcji do zmiennej *zwroc_wartosc:
  9. *zwroc_wartosc=mojaliczba->liczby[0];
  10. STOP
int przygotuj_pochodna(unsigned char *ciag, LICZBA *mojaliczba)

Opis: Funkcja ze wzoru funkcji podanej z zmiennej *ciag tworzy pochodną i zapisują ją w strukturze mojaliczba.

Zmienne:
Nazwa Typ Opis
*mojaliczba LICZBA Tutaj zapiszemy pochodną
*ciag unsigned char Tutaj dostajemy wzór funkcji
mojaliczba2 LICZBA Tutaj umieścimy funkcję zapisaną jako elementy struktury LICZBA
i int Używana w pętli
poziom int poziom wag kolejnych działań
wynik int Zwracany kod błędu

Algorytm:

  1. START
  2. Rozkładamy wzór funkcji na postać zrozumiałą dla programu. Zwracamy błąd, jeśli wystąpił:
  3. /* Rozkladamy ciag na elementy "pierwsze" */    
    i=przygotuj_funkcja(ciag,&mojaliczba2);
    if (i!=0) return i;
  4. Warunki początkowe w strukturze mojaliczba:
  5. /* Wyczyscmy */
    mojaliczba->ile=0;
    mojaliczba->wagi[0]=0;
  6. Informacja debugująca:
  7. dprintf("wchodzi do pochodna\n");
  8. przeglądanie kolejnych elementów struktury mojaliczba2. Jeżeli w którejś użyto liczb "e" lub "pi", zamieniane są na ich odpowiedniki liczbowe.
  9. /* Zamieniamy napisy "pi" i "e" na odpowiadajace im stale matematyczne */
    for (i=0;iile;i++) {
       if (!strcmp(mojaliczba2->stringi[i],"pi")) { //liczba PI
          mojaliczba2->liczby[i]=M_PI;
          strcpy(mojaliczba2->stringi[i],"");
       }    
       if (!strcmp(mojaliczba2->stringi[i],"e")) { //liczba Eulera
          mojaliczba2->liczby[i]=M_E;
          strcpy(mojaliczba2->stringi[i],"");
       }    
    }
  10. Czyszczenie:
  11. i=0;
  12. Pętla wykonująca się, dopóki zmienna i nie jest równa ilości elementów struktury mojaliczba2:
  13. //musimy z i dojsc do konca wzoru funkcji
    while (i!=mojaliczba2.ile) {
    1. W zależności od kolejnego działania w strukturze mojaliczba2:
    2. switch(oblicz_dzialanie(mojaliczba2.wagi[i])) {
      1. Jeżeli mamy ostatni element i dla dodawania/odejmowania:
      2. case 0: // koniec
        case 1: // dodawanie
        case 2: // odejmowanie
        1. Jeżeli mamy napis (musi to być x), dodajemy policzoną pochodną=1 Zwracamy błąd, jeżeli jest za mało pamięci:
        2. if (strcmp(mojaliczba2.stringi[i],"")) {
             /* Jezeli mamy x, potega = 1 */
             if (dodaj_klocek(mojaliczba->ile,"",1,
                 oblicz_dzialanie(mojaliczba2.wagi[i])+poziom*6,
                 mojaliczba)!=0) return 6; //za malo pamieci
          }
        3. Informacja debugująca:
        4. #ifdef DEBUG
                  pisz_funkcja(mojaliczba);
          #endif
      3. Dla mnożenia:
      4. case 3: //mnozenie
        1. Sprawdzenie, czy w następnym działaniu i tym jest napis (x) czy nie. Policzenie pochodnej (dla x*x pochodna=2*x, dla x*liczba=liczba, dla liczba*x=liczba). Jeżeli jest za mało pamięci, zwrócenie błędu:
        2. //mamy string na tej pozycji
          if (strcmp(mojaliczba2.stringi[i+1],"")) {
             if (strcmp(mojaliczba2.stringi[i],"")) {
                /* x*x. Pochodna = 2*x */
                if (dodaj_klocek(mojaliczba->ile,"",2,
                    ST_MNOZENIE+poziom*6,mojaliczba)!=0)
                  return 6;  //za malo pamieci
                if (dodaj_klocek(mojaliczba->ile,"x",0,
                    ST_DODAWANIE+poziom*6,mojaliczba)!=0)
                  return 6; //za malo pamieci
             } else {
                /* liczba*x. Pochodna = liczba */
                if (dodaj_klocek(mojaliczba->ile,"",
                    mojaliczba2.liczby[i],ST_DODAWANIE+poziom*6,
                    mojaliczba)!=0)
                  return 6; //za malo pamieci
             }
          } else {
             if (strcmp(mojaliczba2.stringi[i],"")) { //jest string.
                /* x*liczba. Pochodna=liczba */
                if (dodaj_klocek(mojaliczba->ile,"",
                   mojaliczba2.liczby[i+1],ST_DODAWANIE+poziom*6,
                   mojaliczba)!=0)
                  return 6; //za malo pamieci
                }
          }
        3. Zwiększenie wartości i (w mnożeniu od razu sprawdziliśmy też następne działanie):
        4. i++;
        5. W zależności od kolejnego działania (teraz aktualnego):
        6. switch (oblicz_dzialanie(mojaliczba2.wagi[i])) {
          1. dla odejmowania:
          2. case ST_ODEJMOWANIE:
            1. Przeniesienie aktualnego działania do poprzedniego:
            2. mojaliczba->wagi[mojaliczba->ile-1]=
                  oblicz_dzialanie(mojaliczba2.wagi[i])+poziom*6;
          3. Dla mnożenia:
          4. case ST_MNOZENIE:
            1. Zwracamy błąd (dwa mnożenia pod rząd są zbyt skomplikowane na razie dla modułu):
            2. return 10; //zbyt skomplikowane ;-)
          5. Dla potęgowania:
          6. case ST_POTEGOWANIE:
            1. Przypisujemy mnożenie poprzedniemu działaniu:
            2. mojaliczba->wagi[mojaliczba->ile-1]=
                 ST_MNOZENIE+poziom*6;
            3. Ustawiamy, żeby funkcja jeszcze raz przeliczyła to działanie (sytuacje typu liczba*x^potega):
            4. i--;
          7. Dla funkcji matematycznej:
          8. case ST_FUNKCJA
            1. Zwracamy błąd (działania typu cos*cos*funkcja są zbyt skomplikowane na razie dla modułu):
            2. return 10; //zbyt skomplikowane ;-)
        7. Informacja debugująca:
        8. #ifdef DEBUG
                  pisz_funkcja(mojaliczba);
          #endif
      5. Dla dzielenia:
      6. case 4: //dzielenie
        1. Liczenie pochodnej:
        2. /* Mamy 1/2. Pochodna = (1'*2-1*2')/2^2 */
                          
          /* Pochodna 1 wyrazenia */
          if (strcmp(mojaliczba2.stringi[i],"")) { //czy x na tej pozycji
             if (dodaj_klocek(mojaliczba->ile,"",1,
                ST_MNOZENIE+(poziom+1)*6,mojaliczba)!=0)
                   return 6; //za malo pamieci
          } else {
              if (dodaj_klocek(mojaliczba->ile,"",0,
                ST_MNOZENIE+(poziom+1)*6,mojaliczba)!=0)
                  return 6; //za malo pamieci
          }
          
          /* 2 wyrazenie */
          if (dodaj_klocek(mojaliczba->ile,
              mojaliczba2.stringi[i+1],mojaliczba2.liczby[i+1],
              ST_ODEJMOWANIE+(poziom+1)*6,mojaliczba)!=0)
             return 6; //za malo pamieci
                          
          /* pierwsze wyrazenie */
          if (dodaj_klocek(mojaliczba->ile,"",mojaliczba2.liczby[i],
              ST_MNOZENIE+(poziom+1)*6,mojaliczba)!=0)
             return 6; //za malo pamieci
                          
          /* Pochodna drugiego */
          //czy x na tej pozycji
          if (strcmp(mojaliczba2.stringi[i+1],"")) { 
             if (dodaj_klocek(mojaliczba->ile,"",1,
                ST_DZIELENIE+poziom*6,mojaliczba)!=0)
              return 6; //za malo pamieci
          } else {
             if (dodaj_klocek(mojaliczba->ile,"",0,
                ST_DZIELENIE+poziom*6,mojaliczba)!=0)
              return 6; //za malo pamieci
          }
          
          /* 2 wyrazenie */
          if (dodaj_klocek(mojaliczba->ile,mojaliczba->stringi[i+1],
              mojaliczba2.liczby[i+1],ST_POTEGOWANIE+poziom*6,
            mojaliczba)!=0)
              return 6; //za malo pamieci
          
          /* kwadrat */
          if (dodaj_klocek(mojaliczba->ile,"",2,
             ST_DODAWANIE+poziom*6,mojaliczba)!=0)
            return 6; //za malo pamieci
          
          
        3. Zwiększenie wartości i (w dzieleniu od razu sprawdziliśmy też następne działanie):
        4. i++;
        5. Informacja debugująca:
        6. #ifdef DEBUG
                  pisz_funkcja(mojaliczba);
          #endif
      7. Dla potęgowania:
      8. case 5: //potegowanie
        1. Sprawdzenie, czy w tym i następnym działaniu jest string czy nie. Obliczenie pochodnej. Zwrócenie błędu, jeżeli za mało pamięci lub pochodna x^x:
        2. if (strcmp(mojaliczba2.stringi[i],"")) { //mamy string
             if (strcmp(mojaliczba2.stringi[i+1],"")) {
                /* x^x */
                return 8; //jak obliczac x^x ? ;-)
             } else {
                /* x^liczba. Pochodna = liczba*x^(liczba-1) */
                if (dodaj_klocek(mojaliczba->ile,"",
                   mojaliczba2.liczby[i+1],ST_MNOZENIE+poziom*6,
                   mojaliczba)!=0)
                      return 6;
                if (dodaj_klocek(mojaliczba->ile,"x",0,
                   ST_POTEGOWANIE+poziom*6,mojaliczba)!=0) return 6;
                if (dodaj_klocek(mojaliczba->ile,"",
                   mojaliczba2.liczby[i+1]-1,ST_DODAWANIE+poziom*6,
                   mojaliczba)!=0)
                      return 6;
             }
          } else {
             if (strcmp(mojaliczba2.stringi[i+1],"")) {
                /* liczba^x. Potega= liczba^x*ln(liczba) */
                if (dodaj_klocek(mojaliczba->ile,"",
                   mojaliczba2.liczby[i],ST_POTEGOWANIE+poziom*6,
                   mojaliczba)!=0) return 6;
                if (dodaj_klocek(mojaliczba->ile,"x",0,
                   ST_MNOZENIE+poziom*6,mojaliczba)!=0) return 6;
                if (dodaj_klocek(mojaliczba->ile,"ln",0,
                   ST_FUNKCJA+(poziom+1)*6,mojaliczba)!=0) return 6;
                if (dodaj_klocek(mojaliczba->ile,"",
                   mojaliczba2.liczby[i],ST_DODAWANIE+poziom*6,
                   mojaliczba)!=0) return 6;
              }
          }
        3. Zwiększenie wartości i (w dzieleniu od razu sprawdziliśmy też następne działanie):
        4. i++;
        5. W zależności od kolejnego działania (teraz aktualnego):
        6. switch (oblicz_dzialanie(mojaliczba2.wagi[i])) {
          1. dla odejmowania:
          2. case ST_ODEJMOWANIE:
            1. Przeniesienie aktualnego działania do poprzedniego:
            2. mojaliczba->wagi[mojaliczba->ile-1]=
                  oblicz_dzialanie(mojaliczba2.wagi[i])+poziom*6;
          3. Dla mnożenia:
          4. case ST_MNOZENIE:
            1. Zwracamy błąd (potęgowanie i mnożenie pod rząd są zbyt skomplikowane na razie dla modułu):
            2. return 10; //zbyt skomplikowane ;-)
          5. Dla potęgowania:
          6. case ST_POTEGOWANIE:
            1. Zwracamy błąd (dwa potęgowania pod rząd są zbyt skomplikowane dla modułu):
            2. return 10; //zbyt skomplikowane ;-)
          7. Dla funkcji matematycznej:
          8. case ST_FUNKCJA
            1. Zwracamy błąd (działania typu cos^cos^funkcja są zbyt skomplikowane na razie dla modułu):
            2. return 10; //zbyt skomplikowane ;-)
        7. Informacja debugująca:
        8. #ifdef DEBUG
                  pisz_funkcja(mojaliczba);
          #endif
      9. Dla funkcja matematycznych:
      10. case 6: // funkcje
        1. Dla logarytmu naturalnego:
        2. if (!strcmp(mojaliczba2.stringi[i],"ln"))       {
          1. Obliczenie wartości pochodnej (zwrócenie błędu, gdy za mało pamięci):
          2.                                                      
            /* pochodna (1/x)*x' */
            if (dodaj_klocek(mojaliczba->ile,"",1,
                ST_DZIELENIE+(poziom+1)*6,mojaliczba)!=0) return 6;
            if (strcmp(mojaliczba2.stringi[i+1],"")) { //czy x
               if (dodaj_klocek(mojaliczba->ile,"x",0,
                  ST_MNOZENIE+poziom*6,mojaliczba)!=0) return 6;
            } else {
               if (dodaj_klocek(mojaliczba->ile,"",
                  mojaliczba2.liczby[i+1],ST_MNOZENIE+poziom*6,
                  mojaliczba)!=0) return 6;
            }
            if (strcmp(mojaliczba2.stringi[i+1],"")) { //czy x
               if (dodaj_klocek(mojaliczba->ile,"",1,
                  ST_DODAWANIE+poziom*6,mojaliczba)!=0) return 6;
            } else {
               if (dodaj_klocek(mojaliczba->ile,"",0,
                  ST_DODAWANIE+poziom*6,mojaliczba)!=0) return 6;
            }
          3. Zwiększenie wartości i (wszak od razu sprawdziliśmy też następne działanie):
          4. i++;
        3. ...dla innych funkcji zwrócenie błędu:
        4. } else return 4; //nieznana funkcja
    3. Przejście do następnego działania:
    4. i++;
  14. Dodajemy jedno puste dodawania na wypadek, gdyby w petli nic nie dodano (wszak cos powinno byc w dzialaniu - niech to będzie w skrajnym przypadku "+0"):
  15. if (dodaj_klocek(mojaliczba->ile,"",0,0,mojaliczba)!=0) return 6;
  16. Informacja debugująca:
  17. #ifdef DEBUG
            pisz_funkcja(mojaliczba);
    #endif
  18. 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

Algorytm:

  1. START
  2. Pętla
  3. /* Znak 0x00 konczy ciag. Wykonujemy petle az do niego */    
    while (*ciag!=0x00) {
    1. Dla cyfr:
    2. if ((*ciag>='0' && *ciag<='9')) { //cyfry
      1. Zwiększenie naszej liczby:
      2. /* ... wiec dodajemy odpowiednio do naszej liczby */
        if (mnoznik>=1) { //liczby bez czesci ulamkowej
           mnoznik=mnoznik*10;
           wynik=wynik*10+(*ciag-'0');
        } else { //i z czescia ulamkowa
           wynik=wynik+mnoznik*(*ciag-'0');
           mnoznik=mnoznik*0.1;
        }
      3. Przejście do sprawdzania następnego znaku:
      4. ciag++;num++; //przechodzimy znak do przodu
    3. dla znaków innych niż cyfra
    4. } else {
      1. W zależności od znaku:
      2. switch (*ciag) {
        1. Dla minusa:
        2. case '-':
          1. Jeżeli już był minus, pokaż błąd:
          2. if (num!=0) return 11; //minus nie na poczatku
          3. Ustawiamy flagę, że liczba jest ujemna:
          4. minus=1;
          5. Przejście do sprawdzania następnego znaku:
          6. ciag++;num++; //przechodzimy znak do przodu
        3. Dla kropki:
        4. case '.': /* Kropka wprowadza znaki dziesietne */
          1. Jeżeli nie była to liczba z częścią dziesiętną, zrobienie takiej. W przeciwnym razie zwrócenie błędu (kropka jest 2 raz w liczbie):
          2. if (mnoznik>0.9) {
                mnoznik=0.1;
            } else {
                /* Nie moze byc dwoch kropek w liczbie */
                *wartosc=num;
                return 3;
            }
          3. Przejście do sprawdzania następnego znaku:
          4. ciag++;num++; //przechodzimy znak do przodu
        5. Dla spacji:
        6. case ' ': /* Spacje po prostu ignorujemy */
          1. Przejście do sprawdzania następnego znaku:
          2. ciag++;num++; //przechodzimy znak do przodu
        7. Dla innych znaków:
        8. default:
          1. Wyjście z błędem
          2. return 5;
  4. Przypisanie do zmiennej *wartosc uzyskanego wyniku:
  5. *wartosc=wynik;
    if (minus==1) *wartosc=-wynik;
  6. STOP
9. Kod źródłowy

Informacja: w stosunku do kodu źródłowego zapisanego w plikach w niektórych miejsach zastosowano łamane linii niezgodne z notacją języka C (ze względu na ograniczoną szerokość wydruku).

projekt.c:

/* Plik glowny projektu.
   
   Rozprowadzany na licencji GNU GPL.
   
   Autor:   Marcin Wiacek <marcin-wiacek@topnet.pl>
   Grupa:   2P14
   Semestr: zimowy 2001
   
*/

/* Definicje uzywanych bibliotek */
#include <stdio.h>
#include <math.h>
#include <string.h>

#include "funkcje.h"
#include "config.h"

double wart_funkcji,wart_pochodnej; //wartosci funkcji i pochodnej
LICZBA moja_liczba; //tutaj zapiszemy pochodna i funkcje
char wzor[1000]; //wzor funkcji od uzytkownika
int mojblad; // tutaj bedzie zapisywany blad zwracany przez funkcje z funkcje.c

/* Generalnie tutaj sa zebrane prawie wszystkie bledy numeryczne i skladniowe */
void blad(int i, double value, char liczba[1000], int dodaj) {
    int j,z;
    
    switch (i) {
        case 0:
            break;
        case 1:
            for (j=0;j<dodaj;j++) {printf(" ");}
            for (j=0;j<mojblad-1;j++) {printf(" ");}
            printf("^\n");
            printf("Blad: za duzo nawiasow prawych\n");
            break;
        case 2:
            for (j=0;j<strlen(liczba)-1;j++) {
                if (!strcmp(liczba+j,"/0")) {
                    printf("                     ");
                    for (z=0;z<j;z++) {printf(" ");}
                    printf("^\n");
                }
            }
            printf("Blad: dzielenie przez zero\n");
            break;
        case 3:
            for (j=0;j<dodaj;j++) {printf(" ");}
            for (j=0;j<mojblad-1;j++) {printf(" ");}
            printf("^\n");
            printf("Blad: w liczbie moze byc tylko jedna kropka czesci 
                  dziesietnej\n");
            break;
        case 4:
            printf("Blad: nieznana funkcja matematyczna \"%s\"\n",liczba);
            break;
        case 5:
            for (j=0;j<dodaj;j++) {printf(" ");}
            for (j=0;j<mojblad-1;j++) {printf(" ");}
            printf("^\n");
            printf("Blad: nie znam takiego operatora matematycznego\n");
            break;
        case 6:
            printf("Blad: za duzo elementow w dzialaniu (max %i)\n",MAX_ELEMENTOW);
            break;
        case 7:
            printf("Blad: Podane wyrazenie konczy sie znakiem dzialania
                (nawiasem) !\n");
            break;
        case 8:
            printf("Blad: jak obliczyc pochodna x^x ?\n");
            break;      
        case 9:
            printf("Blad: funkcja ln jest zdefiniowana tylko dla
                  wartosci dodatnich\n");
            break;      
        case 10:
            printf("Blad: zbyt skomplikowana pochodna\n");
            break;      
        case 11:
            printf("Blad: minus moze byc TYLKO na poczatku liczby\n");
            break;      
        case 12:
            printf("Blad: dopuszczam tylko dodatnie liczby\n");
            break;      
        default:
            dprintf("BLAD w programie. Prosze raportowac (wartosc %i dla i)\n",i);
            break;
    }
}

/* Liczenie wartosci funkcji i pochodnej i przyporzadkowanie do wart_funkcji
   i wart_pochodnej. Parametrem jest iks, dla ktorego jest to liczone */
int licz_funkcja_pochodna(double iks) {

    int i;

    printf("Liczenie pochodnej i wartosci funkcji dla x=%f\n",iks);
    
    printf("Funkcja wejsciowa : %s\n",wzor);
    /* Rozkladamy ciag na male elementy */
    i=przygotuj_funkcja(wzor,&moja_liczba);
    if (i!=0) { //mamy blad
        blad(i,wart_funkcji,wzor,21);
        return i;
    }
    /* Liczmy wartosc funkcji */
    i=wartosc_funkcji(&wart_funkcji,iks,&moja_liczba);
    if (i!=0) {
        blad(i,wart_funkcji,wzor,21);
        return i;
    } else {
        /* Wynik nie jest liczba */
        if (isinf(wart_funkcji)) {
            printf("wynik niewlasciwy \n");
        } else {
            printf("wynik %f \n",wart_funkcji);
        }
    }

    /* Z wzoru funkcji robimy pochodna */
    i=przygotuj_pochodna(wzor,&moja_liczba);
    if (i!=0) {
        blad(i,wart_pochodnej,wzor,21);
        return i;
    }
    printf("Pochodna: ");    
    pisz_funkcja(&moja_liczba); //wypiszemy jej wzor
    /* i policzymy wartosc */
    i=wartosc_funkcji(&wart_pochodnej,iks,&moja_liczba);
    if (i!=0) {
        blad(i,wart_pochodnej,wzor,21);
        return i;
    } else {
        /* Wynik nie jest liczba */
        if (isinf(wart_pochodnej)) {
            printf("wynik niewlasciwy \n");
        } else {
            printf("wynik %f \n",wart_pochodnej);
        }
    }

    return 0;
}

/* Pobieramy linie z pliku "File". Funkcja z (my)gnokii */
int GetLine(FILE *File, char *Line, int count) {

  char *ptr;

  if (fgets(Line, count, File)) {
    ptr=Line+strlen(Line)-1;

    while ( (*ptr == '\n' || *ptr == '\r') && ptr>=Line)
      *ptr--='\0';

      return strlen(Line);
  }
  else
    return -1;
}

/* Wczytuje liczbe z pliku */
int wczytaj_liczba(double *liczba, int dodatnia) {
    char ciag[1000]; //tutaj wczytujemy kolejna linijke
    double wartosc; //wartosc liczby
    int i; //kod bledu
    
    GetLine(stdin, ciag,1000); //pobieramy linijke z wejscia

    dprintf("ciag = %s\n",ciag);

    i=wez_liczba(ciag,&wartosc);
    mojblad=wartosc;
    if (i!=0) {
        blad(i,wartosc,ciag,31);
        return i;
    }
    if (dodatnia==1 && wartosc<0) {
        i=12;
        blad(i,wartosc,ciag,31);
        return i;
    }
    *liczba=wartosc;
    
    return 0;
}

int main()
{
    int i,j;
    double oldiks; //stara wartosc iksa
    double delta; //wartosc delty

    int ile_krokow=50;       // ile maksymalnie krokow
    double iks=2;            // punkt startowy
    double dokladnosc=0.005; // zadana dokladnosc obliczen

    printf("Wczytywanie wzoru funkcji     ");
    GetLine(stdin, wzor,1000); //pobieramy wzor funkcji z wejscia
    printf("\n");

    printf("Wczytywanie dokladnosci       ");
    i=wczytaj_liczba(&dokladnosc,1);
    if (i!=0) return i;
    printf("\n");
    
    printf("Wczytywanie punktu startowego ");
    i=wczytaj_liczba(&iks,0);
    if (i!=0) return i;
    printf("\n");
    
    printf("Wczytywanie ilosci krokow     ");
    i=wczytaj_liczba(&oldiks,1);
    if (i!=0) return i;
    ile_krokow=oldiks;
    printf("\n");
    
    printf("Wczytano dane: dokladnosc=%f, punkt startowy=%f, ile_krokow=%i\n",
        dokladnosc,iks,ile_krokow);

    /* Obliczanie pierwszego punktu */
    i=licz_funkcja_pochodna(iks);
    if (i!=0) return i;
    
    for (j=0;j<ile_krokow;j++) {

        if (wart_funkcji==0) {
            printf("Pierwiastek osiagnieto dla x=%f przy kroku %i\n",iks,j);
            return 0;
        }

        /* Pochodna = 0, a my musimy przez nia dzielic (obliczanie nowego iks. */
        if (wart_pochodnej==0)
        {
            printf("Blad: dla x=%f pochodna=0\n",iks);
            return 20;
        }

        /* Stary punkt bedzie potrzebny do delty */
        oldiks=iks;

        /* Liczymy nowy punkt */
        iks=iks-(wart_funkcji/wart_pochodnej);
        i=licz_funkcja_pochodna(iks);
        if (i!=0) return i;

        /* Badanie dokladnosci */
        if (iks>1 || iks<-1) {
            /* dla modul z iks > 1 */
            delta=(iks-oldiks)/iks;
        } else {
            delta=(iks-oldiks);
        }

        /* modul z Delta <= dokladnosc i modul z iks <= 100*dokladnosc */
        if ((delta<=dokladnosc && delta>=(-dokladnosc)) &&
            (iks<(100*dokladnosc) && iks>-(100*dokladnosc))) {
            printf("Pierwiastek osiagnieto dla x=%f przy kroku %i\n",iks,j);
            return 0;
        }
    }
    printf("Blad: nie znaleziono pierwiastka w %i krokach\n",ile_krokow);
    printf("\n");

    return 0;
}
funkcje.c
/* Biblioteka projektu zawierajaca funkcje pozwalajace
   wykonywac rozne ciekawe rzeczy z wzorami funkcji podanymi
   w postaci ciagu znakow.
   
   Rozprowadzana na licencji GNU GPL.
   
   Autor:   Marcin Wiacek <marcin-wiacek@topnet.pl>
   Grupa:   2P14
   Semestr: zimowy 2001
   
*/

/* Definicje uzywanych bibliotek */
#include <stdio.h>
#include <math.h>
#include <string.h>

#include "funkcje.h"
#include "config.h"

char napis[100];

/* Funkcja oblicza poziom wartosci wagi podanej jako "wartosc" */
int oblicz_poziom(int wartosc) {
    int zwracana; //wartosc zwracana

    zwracana=0;
    while (wartosc>6) {wartosc=wartosc-6;zwracana++;};

    return zwracana;
}

/* Funkcja podaje dzialanie zawarte w wadze podanej jako "wartosc" */
int oblicz_dzialanie(int wartosc) {
    int zwracana; //wartosc zwracana

    zwracana=wartosc;
    while (zwracana>6) {zwracana=zwracana-6;};

    return zwracana;
}

/* Dodaje jedno podane dzialanie do struktury "mojaliczba" */
int dodaj_klocek(int numer, unsigned char *string, double liczba,
                 int waga, LICZBA *mojaliczba) {
    if (numer+1>MAX_ELEMENTOW) return 6; //za malo pamieci
    
    mojaliczba->liczby[numer]=liczba;
    strcpy(mojaliczba->stringi[numer],string);
    mojaliczba->wagi[numer]=waga;
    mojaliczba->ile++;
    
    return 0;
}

/* Usuwa ze struktury "mojaliczba" dzialania od numeru "numer".
   "ileusunac" okresla, ile dzialan usunac */
int usun_klocek(int numer, int ileusunac, LICZBA *mojaliczba) {
    int i;

    if (numer-ileusunac>mojaliczba->ile) {
        dprintf("Blad w usun. Prosze raportowac\n");
        return 1;
    }
        
    for (i=numer;i<mojaliczba->ile-ileusunac+1;i++) {   
        mojaliczba->liczby[i]=mojaliczba->liczby[i+ileusunac];
        strcpy(mojaliczba->stringi[i],mojaliczba->stringi[i+ileusunac]);
        mojaliczba->wagi[i]=mojaliczba->wagi[i+ileusunac];
    }
    mojaliczba->ile=mojaliczba->ile-ileusunac;
    
    return 0;
}

/* Funkcja wypisuje wzor funkcji podanej jako "mojaliczba" */
void pisz_funkcja(LICZBA *mojaliczba)
{
    int i;        //zmienna do petli
    int poziom=1; //tutaj zapisujemy poziom kolejnych wag

    dprintf("wchodzi do pisz_funkcja\n");
    
#ifdef DEBUG    
    /* Wypisuje calosc liczby */
    dprintf("lp liczby stringi wagi\n");
    for (i=0;i<mojaliczba->ile;i++) {
        dprintf("%i %f \"%s\" %i %i \n",i,mojaliczba->liczby[i],
              mojaliczba->stringi[i],
              mojaliczba->wagi[i],oblicz_dzialanie(mojaliczba->wagi[i]));
    }
    dprintf("\n");
    printf("funkcja : ");
#endif

    for (i=0;i<mojaliczba->ile;i++) {

        if (oblicz_poziom(poziom)<oblicz_poziom(mojaliczba->wagi[i])) printf("(");
        
        if (strcmp(mojaliczba->stringi[i],"")) {
            printf("%s",mojaliczba->stringi[i]);
        } else {
            printf("%f",mojaliczba->liczby[i]);
        }

        if (oblicz_poziom(poziom)>oblicz_poziom(mojaliczba->wagi[i])) printf(")");

        poziom=mojaliczba->wagi[i];
        
        switch (oblicz_dzialanie(poziom)) {
            case 1: printf("+"); break;
            case 2: printf("-"); break;
            case 3: printf("*"); break;
            case 4: printf("/"); break;
            case 5: printf("^"); break;
        }
    }
    
    printf("\n");
}

/* Funkcja rozklada dzialanie podane jako ciag na jak najmniejsze elementy.
   Zwraca 0, gdy ciag jest dla niej poprawny (lub odpowiednie kody bledow)
   W przypadku bledu w zmiennej ile w strukturze mojaliczba
   znajduje sie numer blednego znaku w podanym ciagu */
int przygotuj_funkcja(unsigned char *ciag, LICZBA *mojaliczba)
{
    int poziom=0;

    char znaki[100]; //przy parsowaniu ciagu znakow

    double wynik=0; //jezeli parsujemy liczbe - tutaj jest jej aktualna wartosc
    double mnoznik=1; //mnoznik dla kolejnej cyfry liczby
    
    int stan=0; // zmienna okreslajaca stan parsowania:
                // 0-glowna petla,1-liczba,2-napis
    
    int num=0;  // numer kolejnego obrabianego znaku

    dprintf("wchodzi do przygotuj_string\n");

    /* Warunki poczatkowe */
    znaki[0]=0;
    mojaliczba->wagi[0]=0;
    mojaliczba->ile=0;

    /* Znak 0x00 konczy ciag. Wykonujemy petle az do niego */    
    while (*ciag!=0x00) {
        if (stan==0) { //start i znaki dzialan, nawiasy
            if ((*ciag>='0' && *ciag<='9') || *ciag=='.') { //cyfry lub kropka
                wynik=0; mnoznik=1; //wartosc domyslne dla liczby
                znaki[0]=0; //czyscimy
                stan=1; //teraz bedziemy obrabiac liczbe
            } else {
                if ((*ciag>='a' && *ciag<='z') || /* znaki alfabetu */
                    (*ciag>='A' && *ciag<='Z')) { /*     -"-        */
                    znaki[0]=0; //czyscimy
                    wynik=0; //czyscimy
                    stan=2; //teraz bedziemy obrabiac ciag znakow
                } else {
                    switch (*ciag) {
                        case '+': /* Znaki dzialan */
                        case '-': /*      -"-      */
                        case '*': /*      -"-      */
                        case '/': /*      -"-      */
                        case '^': /*      -"-      */
                            //znak dzialania jest ostatni w ciagu
                            if (*(ciag+1)==0x00) return 7; 
                            /* Tworzymy nowa pozycje */
                            switch (*ciag) {
                                case '+':
                                    if (dodaj_klocek(mojaliczba->ile, znaki
                                        wynik, ST_DODAWANIE+6*poziom, mojaliczba)!=0)
                                          return 6; //za malo pamieci
                                    break;
                                case '-':
                                    if (dodaj_klocek(mojaliczba->ile, znaki, 
                                        wynik, ST_ODEJMOWANIE+6*poziom,
                                        mojaliczba)!=0)
                                          return 6; //za malo pamieci
                                    break;
                                case '*':
                                    if (dodaj_klocek(mojaliczba->ile, znaki, 
                                        wynik, ST_MNOZENIE+6*poziom, mojaliczba)!=0)
                                          return 6; //za malo pamieci
                                    break;
                                case '/':
                                    if (dodaj_klocek(mojaliczba->ile, znaki, 
                                        wynik, ST_DZIELENIE+6*poziom, mojaliczba)!=0)
                                          return 6; //za malo pamieci
                                    break;
                                case '^':
                                    if (dodaj_klocek(mojaliczba->ile, znaki, 
                                        wynik, ST_POTEGOWANIE+6*poziom,
                                        mojaliczba)!=0)
                                          return 6; //za malo pamieci
                                    break;
                            }
                            ciag++;num++; //przechodzimy znak do przodu
                            break;
                        case '(': /* Otwieramy nawias */
                            //nawias jest ostatni w ciagu
                            if (*(ciag+1)==0x00) return 7; 
                            poziom++;
                            mojaliczba->liczby[mojaliczba->ile]=0; //czyscimy
                            strcpy(znaki,""); //czyscimy
                            wynik=0; //czyscimy
                            ciag++;num++; //przechodzimy znak do przodu
                            break;
                        case ')': /* Zamykamy nawias */
                            if (poziom==0) { /* Za duzo nawiasow prawych */
                                mojaliczba->ile=num;
                                return 1;
                            }
                            poziom--;
                            ciag++;num++; //przechodzimy znak do przodu
                            break;                      
                        case ' ': /* Spacje po prostu ignorujemy */
                            ciag++;num++; //przechodzimy znak do przodu
                            break;
                        default: //nieznany znak
                            mojaliczba->ile=num;
                            return 5;
                    }
                }
            }
        }
        if (stan==1) { //cyfry i kropka dziesietna
            /* Mamy cyfre */
            if (*ciag>='0' && *ciag<='9') {
                /* ... wiec dodajemy odpowiednio do naszej liczby */
                if (mnoznik>=1) { //liczby bez czesci ulamkowej
                    mnoznik=mnoznik*10;
                    wynik=wynik*10+(*ciag-'0');
                } else { //i z czescia ulamkowa
                    wynik=wynik+mnoznik*(*ciag-'0');
                    mnoznik=mnoznik*0.1;
                }
                ciag++;num++; //przechodzimy znak do przodu
            } else {
                switch (*ciag) {
                    case '.': /* Kropka wprowadza znaki dziesietne */
                        if (mnoznik>0.9) {
                            mnoznik=0.1;
                        } else {
                            /* Nie moze byc dwoch kropek w liczbie */
                            mojaliczba->ile=num;
                            return 3;
                        }
                        ciag++;num++; //przechodzimy znak do przodu
                        break;
                    case ' ':
                        ciag++;num++; //przechodzimy znak do przodu
                        break;
                    default: //nieznany znak w liczbie
                             //- wracamy do glownej petli
                        stan=0;
                }
            }
        }
        if (stan==2) { //znaki
            if (*ciag>='a' && *ciag<='z') { //male znaki
                znaki[strlen(znaki)+1]=0; //zamykamy zwiekszony ciag znakiem 0
                znaki[strlen(znaki)]=*ciag;  //dodajemy znak
                ciag++;num++; //przechodzimy znak do przodu
            } else {
                if (*ciag>='A' && *ciag<='Z') { //duze znaki
                    //zamykamy zwiekszony ciag znakiem 0
                    znaki[strlen(znaki)+1]=0; 
                    //dodajemy+ konwersja na male litery
                    znaki[strlen(znaki)]=*ciag-('A'-'a'); 
                    ciag++;num++; //przechodzimy znak do przodu
                } else {
                    if (*ciag=='(') { //dla funkcji typu cos(x)..
                        if (dodaj_klocek(mojaliczba->ile, znaki, wynik,
                            ST_FUNKCJA+6*poziom, mojaliczba)!=0)
                              return 6; //za malo pamieci
                    }
                    stan=0; //do glownej petli
                }   
            } 
        }
    }
    
    /* Po wyjsciu z petli cos tam zawsze zostalo niedokonczone. Wstawmy to */
    if (dodaj_klocek(mojaliczba->ile, znaki, wynik, 0 , mojaliczba)!=0)
        return 6; //za malo pamieci

#ifdef DEBUG
    pisz_funkcja(mojaliczba);
#endif    

    return 0;
}

/* Oblicza wartosc funkcji podanej w strukturze "moja liczba" dla x o wartosci
   "iks". Wynik zwracany w "zwroc_wartosc" */
int wartosc_funkcji(double *zwroc_wartosc, double iks, LICZBA *mojaliczba)
{
    int i,j; //petle
    int num; //okresla numer obrabianego dzialania

    dprintf("wchodzi do wartosc funkcji\n");

    /* Zamieniamy napisy "pi" i "e" na odpowiadajace im stale matematyczne,
       jak rowniez zamiast iksa wstawiamy odpowiadajaca mu wartosc */
    for (i=0;i<mojaliczba->ile;i++) {
        if (!strcmp(mojaliczba->stringi[i],"pi")) { //liczba PI
            mojaliczba->liczby[i]=M_PI;
            strcpy(mojaliczba->stringi[i],"");
        }    
        if (!strcmp(mojaliczba->stringi[i],"e")) { //liczba Eulera
            mojaliczba->liczby[i]=M_E;
            strcpy(mojaliczba->stringi[i],"");
        }    
        if (!strcmp(mojaliczba->stringi[i],"x")) { //iks
            mojaliczba->liczby[i]=iks;
            strcpy(mojaliczba->stringi[i],"");
        }    
    }

    /* Dopoki waga dzialania!=0. Czyli dopoki mamy dzialania */    
    while (mojaliczba->ile!=0) {
        j=mojaliczba->wagi[0];num=0; //warunki poczatkowe
        /* szukamy dzialania o najwyzszej wadze */
        for (i=0;i<mojaliczba->ile;i++) {
            if (mojaliczba->wagi[i]>j) {j=mojaliczba->wagi[i];num=i;}
        }
        j=oblicz_dzialanie(j);
        switch (j) {
            case 1: /* Dodawanie   */
            case 2: /* odejmowanie */
            case 3: /* mnozenie    */
            case 4: /* dzielenie   */
            case 5: /* potegowanie */
                //jakis dziwny string
                if (strcmp(mojaliczba->stringi[num+1],"")) { 
                    strcpy(napis,mojaliczba->stringi[num+1]);
                    return 4;
                }
                switch (j) {
                    case 1:mojaliczba->liczby[num]=mojaliczba->liczby[num]+
                           mojaliczba->liczby[num+1];break;
                    case 2:mojaliczba->liczby[num]=mojaliczba->liczby[num]-
                           mojaliczba->liczby[num+1];break;
                    case 3:mojaliczba->liczby[num]=mojaliczba->liczby[num]*
                           mojaliczba->liczby[num+1];break;
                    case 4:if (mojaliczba->liczby[num+1]==0) return 2;
                           mojaliczba->liczby[num]=mojaliczba->liczby[num]/
                           mojaliczba->liczby[num+1];
                           break;
                    case 5:mojaliczba->liczby[num]=pow(mojaliczba->liczby[num],
                           mojaliczba->liczby[num+1]);
                }
                mojaliczba->wagi[num]=mojaliczba->wagi[num+1];          
                break;
            case 6: //funkcje matematyczne
                if (!strcmp(mojaliczba->stringi[num],"ln")) {
                    mojaliczba->liczby[num]=log(mojaliczba->liczby[num+1]);
                    if (isnan(mojaliczba->liczby[num])) return 9;
                    strcpy(mojaliczba->stringi[num],"");
                    mojaliczba->wagi[num]=mojaliczba->wagi[num+1];              
                } else {
                    strcpy(napis,mojaliczba->stringi[num]);
                    return 4;
                }
        }
        usun_klocek(num+1,1,mojaliczba);
    }

    *zwroc_wartosc=mojaliczba->liczby[0];    

    return 0;
}

/* We wzoru funkcji podanej jako "ciag" probuje utworzyc pochodna
   i zapisac ja od razu w strukturze "mojaliczba" */
int przygotuj_pochodna(unsigned char *ciag, LICZBA *mojaliczba)
{
    LICZBA mojaliczba2;
    int poziom=0;
    int i;

    /* Rozkladamy ciag na elementy "pierwsze" */    
    i=przygotuj_funkcja(ciag,&mojaliczba2);
    if (i!=0) return i;
        
    /* Wyczyscmy */
    mojaliczba->ile=0;
    mojaliczba->wagi[0]=0;
    
    dprintf("wchodzi do pochodna\n");

    /* Zamieniamy napisy "pi" i "e" na odpowiadajace im stale matematyczne */
    for (i=0;i<mojaliczba2.ile;i++) {
        if (!strcmp(mojaliczba2.stringi[i],"pi")) { //liczba PI
            mojaliczba2.liczby[i]=M_PI;
            strcpy(mojaliczba2.stringi[i],"");
        }    
        if (!strcmp(mojaliczba2.stringi[i],"e")) { //liczba Eulera
            mojaliczba2.liczby[i]=M_E;
            strcpy(mojaliczba2.stringi[i],"");
        }    
    }

    i=0;
    while (i!=mojaliczba2.ile) { //musimy z i dojsc do konca wzoru funkcji
        switch(oblicz_dzialanie(mojaliczba2.wagi[i])) {
            case 0: // koniec
            case 1: // dodawanie
            case 2: // odejmowanie
                if (strcmp(mojaliczba2.stringi[i],"")) {
                    /* Jezeli mamy x, potega = 1 */
                    if (dodaj_klocek(mojaliczba->ile,"",1,
                        oblicz_dzialanie(mojaliczba2.wagi[i])+poziom*6,
                        mojaliczba)!=0) return 6; //za malo pamieci
                }
#ifdef DEBUG
                pisz_funkcja(mojaliczba);
#endif
                break;
            case 3: //mnozenie
                //mamy string na tej pozycji
                if (strcmp(mojaliczba2.stringi[i+1],"")) { 
                    if (strcmp(mojaliczba2.stringi[i],"")) {
                        /* x*x. Pochodna = 2*x */
                        if (dodaj_klocek(mojaliczba->ile,"",2,
                           ST_MNOZENIE+poziom*6,mojaliczba)!=0)
                             return 6;  //za malo pamieci
                        if (dodaj_klocek(mojaliczba->ile,"x",0,
                           ST_DODAWANIE+poziom*6,mojaliczba)!=0)
                             return 6; //za malo pamieci
                    } else {
                        /* liczba*x. Pochodna = liczba */
                        if (dodaj_klocek(mojaliczba->ile,"",
                           mojaliczba2.liczby[i],ST_DODAWANIE+poziom*6,
                           mojaliczba)!=0) return 6; //za malo pamieci
                    }
                } else {
                    if (strcmp(mojaliczba2.stringi[i],"")) { //jest string.
                        /* x*liczba. Pochodna=liczba */
                        if (dodaj_klocek(mojaliczba->ile,"",
                            mojaliczba2.liczby[i+1],
                            ST_DODAWANIE+poziom*6,mojaliczba)!=0) 
                              return 6; //za malo pamieci
                    }
                }
                i++;
                switch (oblicz_dzialanie(mojaliczba2.wagi[i])) {
                    case ST_DODAWANIE:
                        break;
                    case ST_ODEJMOWANIE:
                        mojaliczba->wagi[mojaliczba->ile-1]=
                          oblicz_dzialanie(mojaliczba2.wagi[i])+poziom*6;
                        break;
                    case ST_MNOZENIE:
                        return 10; //zbyt skomplikowane ;-)
                    case ST_POTEGOWANIE:
                        mojaliczba->wagi[mojaliczba->ile-1]=
                           ST_MNOZENIE+poziom*6;
                        i--;
                        break;
                    case ST_FUNKCJA:
                        return 10;
                }
#ifdef DEBUG
                pisz_funkcja(mojaliczba);
#endif
                break;
            case 4: //dzielenie
                /* Mamy 1/2. Pochodna = (1'*2-1*2')/2^2 */
                
                /* Pochodna 1 wyrazenia */
                if (strcmp(mojaliczba2.stringi[i],"")) { //czy x na tej pozycji
                    if (dodaj_klocek(mojaliczba->ile,"",1,
                       ST_MNOZENIE+(poziom+1)*6,mojaliczba)!=0)
                          return 6; //za malo pamieci
                } else {
                    if (dodaj_klocek(mojaliczba->ile,"",0,
                       ST_MNOZENIE+(poziom+1)*6,mojaliczba)!=0)
                          return 6; //za malo pamieci
                }

                /* 2 wyrazenie */
                if (dodaj_klocek(mojaliczba->ile,mojaliczba2.stringi[i+1],
                    mojaliczba2.liczby[i+1],ST_ODEJMOWANIE+(poziom+1)*6,
                    mojaliczba)!=0) return 6; //za malo pamieci
                
                /* pierwsze wyrazenie */
                if (dodaj_klocek(mojaliczba->ile,"",mojaliczba2.liczby[i],
                   ST_MNOZENIE+(poziom+1)*6,mojaliczba)!=0)
                      return 6; //za malo pamieci
                
                /* Pochodna drugiego */
                //czy x na tej pozycji
                if (strcmp(mojaliczba2.stringi[i+1],"")) { 
                    if (dodaj_klocek(mojaliczba->ile,"",1,
                       ST_DZIELENIE+poziom*6,mojaliczba)!=0)
                         return 6; //za malo pamieci
                } else {
                    if (dodaj_klocek(mojaliczba->ile,"",0,
                       ST_DZIELENIE+poziom*6,mojaliczba)!=0)
                         return 6; //za malo pamieci
                }

                /* 2 wyrazenie */
                if (dodaj_klocek(mojaliczba->ile,mojaliczba->stringi[i+1],
                    mojaliczba2.liczby[i+1],ST_POTEGOWANIE+poziom*6,
                    mojaliczba)!=0) return 6; //za malo pamieci

                /* kwadrat */
                if (dodaj_klocek(mojaliczba->ile,"",2,ST_DODAWANIE+poziom*6,
                   mojaliczba)!=0) return 6; //za malo pamieci
                
                i++;
#ifdef DEBUG
                pisz_funkcja(mojaliczba);
#endif
                break;
            case 5: //potegowanie
                if (strcmp(mojaliczba2.stringi[i],"")) { //mamy string
                    if (strcmp(mojaliczba2.stringi[i+1],"")) {
                        /* x^x */
                        return 8; //jak obliczac x^x ? ;-)
                    } else {
                        /* x^liczba. Pochodna = liczba*x^(liczba-1) */
                        if (dodaj_klocek(mojaliczba->ile,"",
                           mojaliczba2.liczby[i+1],ST_MNOZENIE+poziom*6,
                           mojaliczba)!=0) return 6;
                        if (dodaj_klocek(mojaliczba->ile,"x",0,
                           ST_POTEGOWANIE+poziom*6,mojaliczba)!=0) return 6;
                        if (dodaj_klocek(mojaliczba->ile,"",
                           mojaliczba2.liczby[i+1]-1,ST_DODAWANIE+poziom*6,
                           mojaliczba)!=0) return 6;
                    }
                } else {
                    if (strcmp(mojaliczba2.stringi[i+1],"")) {
                        /* liczba^x. Potega= liczba^x*ln(liczba) */
                        if (dodaj_klocek(mojaliczba->ile,"",
                           mojaliczba2.liczby[i],ST_POTEGOWANIE+poziom*6,
                           mojaliczba)!=0) return 6;
                        if (dodaj_klocek(mojaliczba->ile,"x",0,
                           ST_MNOZENIE+poziom*6,mojaliczba)!=0) return 6;
                        if (dodaj_klocek(mojaliczba->ile,"ln",0,
                           ST_FUNKCJA+(poziom+1)*6,mojaliczba)!=0) return 6;
                        if (dodaj_klocek(mojaliczba->ile,"",
                           mojaliczba2.liczby[i],
                           ST_DODAWANIE+poziom*6,mojaliczba)!=0) return 6;
                    }
                }
                i++;
                switch (oblicz_dzialanie(mojaliczba2.wagi[i])) {
                    case ST_DODAWANIE:
                        break;
                    case ST_ODEJMOWANIE:
                        mojaliczba->wagi[mojaliczba->ile-1]=
                           oblicz_dzialanie(mojaliczba2.wagi[i])+poziom*6;
                        break;
                    case ST_MNOZENIE:
                        return 10; //zbyt skomplikowane ;-)
                    case ST_POTEGOWANIE:
                        return 10;
                    case ST_FUNKCJA:
                        return 10;
                }
#ifdef DEBUG
                pisz_funkcja(mojaliczba);
#endif
                break;
            case 6: // funkcje
                if (!strcmp(mojaliczba2.stringi[i],"ln"))       {
                    /* pochodna (1/x)*x' */
                    if (dodaj_klocek(mojaliczba->ile,"",1,
                        ST_DZIELENIE+(poziom+1)*6,mojaliczba)!=0) return 6;
                    if (strcmp(mojaliczba2.stringi[i+1],"")) { //czy x
                        if (dodaj_klocek(mojaliczba->ile,"x",0,
                           ST_MNOZENIE+poziom*6,mojaliczba)!=0) return 6;
                    } else {
                        if (dodaj_klocek(mojaliczba->ile,"",
                           mojaliczba2.liczby[i+1],ST_MNOZENIE+poziom*6,
                           mojaliczba)!=0) return 6;
                    }
                    if (strcmp(mojaliczba2.stringi[i+1],"")) { //czy x
                        if (dodaj_klocek(mojaliczba->ile,"",1,
                           ST_DODAWANIE+poziom*6,mojaliczba)!=0) return 6;
                    } else {
                        if (dodaj_klocek(mojaliczba->ile,"",0,
                           ST_DODAWANIE+poziom*6,mojaliczba)!=0) return 6;
                    }
                    i++;                    
                } else return 4; //nieznana funkcja
        }
        i++;
    }

    if (dodaj_klocek(mojaliczba->ile,"",0,0,mojaliczba)!=0) return 6;

#ifdef DEBUG        
    pisz_funkcja(mojaliczba);
#endif    

    return 0;
}

/* Z ciagu "ciag" wyciaga liczbe rzeczywista */
int wez_liczba(unsigned char *ciag, double *wartosc)
{
    double wynik=0; //aktualna wartosc liczby
    double mnoznik=1; //mnoznik dla kolejnej cyfry liczby
    int num=0; //ktory znak "ciagu" parsujemy
    int minus=0; //czy liczba ujemna

    /* Znak 0x00 konczy ciag. Wykonujemy petle az do niego */    
    while (*ciag!=0x00) {
        /* Mamy cyfre */
        if (*ciag>='0' && *ciag<='9') {
            /* ... wiec dodajemy odpowiednio do naszej liczby */
            if (mnoznik>=1) { //liczby bez czesci ulamkowej
                mnoznik=mnoznik*10;
                wynik=wynik*10+(*ciag-'0');
            } else { //i z czescia ulamkowa
                wynik=wynik+mnoznik*(*ciag-'0');
                mnoznik=mnoznik*0.1;
            }
            ciag++;num++;
        } else {
            switch (*ciag) {
                case '-':
                    if (num!=0) return 11; //minus nie na poczatku
                    minus=1;
                    ciag++;num++;
                    break;
                case '.': /* Kropka wprowadza znaki dziesietne */
                    if (mnoznik>0.9) {
                        mnoznik=0.1;
                    } else {
                        /* Nie moze byc dwoch kropek w liczbie */
                        *wartosc=num;
                        return 3;
                    }
                    ciag++;num++;
                    break;
                case ' ':
                    ciag++;num++;
                    break;
                default: //nieznany znak w liczbie
                    return 5;
            }
        }
    }
    
    *wartosc=wynik;
    if (minus==1) *wartosc=-wynik;

    return 0;
}
funkcje.h
/* Plik naglowkowy projektu z PROG
   
   Rozprowadzany na licencji GNU GPL.
   
   Autor:   Marcin Wiacek 
   Grupa:   2P14
   Semestr: zimowy 2001
   
*/

#include "config.h"

/* Definicja nowej funkcji wypisujacej tekst
   tylko przy zdefiniowanej stalej DEBUG */
#ifndef DEBUG
    #define dprintf(a...) do { } while (0)
#else
    #define dprintf(a...) do { fprintf(stderr, a); fflush(stderr); } while (0) 
#endif

/* Definicja stalych uzywanych przy wagach */
#define ST_DODAWANIE   1
#define ST_ODEJMOWANIE 2
#define ST_MNOZENIE    3
#define ST_DZIELENIE   4
#define ST_POTEGOWANIE 5
#define ST_FUNKCJA     6

/* Struktura zawierajaca struktury potrzebne do rozkladania i
   obliczania funkcji i pochodnych */
typedef struct {
    /* Tablice sluzace do przechowywania rozlozonego na elementy pierwsze */
    /* dzialania - liczb, napisow i wag ich dzialan */
    double liczby[MAX_ELEMENTOW];
    char stringi[MAX_ELEMENTOW][100];
    int wagi[MAX_ELEMENTOW];

    /* Po uzyciu przygotuj_funkcja zmienna okresla, ile "klockow"
       zawiera dzialanie */
    int ile;
} LICZBA;

extern char napis[100];

/* Deklaracje publicznych funkcji */
void pisz_funkcja(LICZBA *mojaliczba);
int wartosc_funkcji(double *zwroc_wartosc, double iks, LICZBA *mojaliczba);
int przygotuj_funkcja(unsigned char *ciag, LICZBA *mojaliczba);
int przygotuj_pochodna(unsigned char *ciag, LICZBA *mojaliczba);
int wez_liczba(unsigned char *ciag, double *wartosc);
config.h
/* Plik konfiguracyjny projektu z PROG
   
   Rozprowadzany na licencji GNU GPL.
   
   Autor:   Marcin Wiacek 
   Grupa:   2P14
   Semestr: zimowy 2001
   
*/

/* Definiowac tylko przy sprawdzaniu poprawnosci dzialania programu */
//#define DEBUG


/* Tutaj definiujemy, ile klockow (liczb, funkcji, itp.) moze zawierac
   dzialanie obrabiane przez przygotuj_string, wartosc_funkcji */
#define MAX_ELEMENTOW 100
Makefile.global
# Opcje dla Makefile z projektu

RM               = /bin/rm -f  # czym usuwamy pliki
INCLUDEDIR       = lib/include # katalog z plikami naglowkowymi
CONFIGINCLUDEDIR = .           # katalog z plikiem naglowkowym config.h
CC               = gcc         # uzywany kompilator
CFLAGS           = -O2 -Wall   # opcje kompilatora

#wewnetrzny kod

OBJS =  $(TOPDIR)/lib/funkcje.o \
        $(TOPDIR)/projekt/projekt.o

all: $(TOPDIR)/projekt/projekt

$(TOPDIR)/projekt/projekt: $(OBJS)

clean:
        $(RM) $(OBJS) $(TOPDIR)/projekt/projekt
        
.PHONY: all clean

CFLAGS += -I$(TOPDIR)/$(INCLUDEDIR) -I$(TOPDIR)/$(CONFIGINCLUDEDIR)
Makefile z głównego katalogu projektu (w innych należy tylko zmienić ścieżkę w linii z TOPDIR na "TOPDIR=.."):
# Makefile dla projektu z PROG
# Autor:   Marcin Wiacek 
# Grupa:   2P14
# Semestr: zimowy 2001

TOPDIR=.

# dodajemy Makefile z globalna konfiguracja
include $(TOPDIR)/Makefile.global