Programowanie w C (index)


Programowanie w C (14) - wskaźniki do funkcji

ZADANIE 14.1

W katalogu domowym utworzyć podkatalog romberg. Utworzyć w nim plik Makefile i pozostałe pliki, po jednym dla każdej funkcji:


/*
* main.h
*
* Plik naglowkowy.
*/

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

#define DEBUG

#define abs(x)                  ((x) >= 0 ? (x) : -(x)) 
#define max(a,b)         ((a) < (b) ? (b) : (a))
#define min(a,b)         ((a) < (b) ? (a) : (b))

void nrerror(char error_text[]);
/* dla nrromb(), nrtrap() */

double trapzd(double (*f)(double x), double a, double b, int n);
/* kon pociagowy dla nrromb(), nrtrap() */

double nrtrap(double (*f)(double x), double a, double b,
int maxns, double aerr, double rerr);

double nrromb(double (*f)(double x), double a, double b, 
int maxns, double aerr, double rerr);

/*
* main.c
*
* Calkowanie w jednym wymiarze.
*/

#include "main.h"

double fun1(double x) 
{
return(sin(x));
}

int main(void) 
{
const double EPS = 1e-6; /* prawie granica dla 32-bitowych maszyn */
const int LKROKOW = 20;
double a, b, wynik;

/* Granice calki */
a = 1.0;
b = 2.0;

wynik = nrromb(fun1,a,b,LKROKOW,EPS,EPS);
printf(" METODA ROMBERGA\n");
printf("int(f(x),x= %f .. %f ) = %f\n", a, b, wynik);

wynik= nrtrap(fun1, a, b, LKROKOW, EPS, EPS);
printf(" METODA TRAPEZOW\n");
printf("int(f(x),x= %f .. %f ) = %f\n", a, b, wynik);
return 0;
}

/*
* nrerror.c
*
* Standardowa funkcja obslugi bledu wg Numerical Recipes.
*/

#include "main.h"

void nrerror(char error_text[]) 
{
fprintf(stderr, "Numerical Recipes run-time error...\n");
fprintf(stderr, "%s\n", error_text);
fprintf(stderr, "...now exiting to system...\n");
exit(1);
}

/*
* trapzd.c
*/

#include "main.h"

double trapzd(double (*f)(double x), double a, double b, int n) 
{ /*
* a, b - konce przedzialu calkowania
* n - bedzie 2^(n-1) przedzialow, n < 31
*/
double x, sum, del;
static double s;   /* pamiec o ostatniej wartosci calki */
static int it;     /* pamiec o liczbie nowych punktow w nastepnym 
                      wywolaniu funkcji trapzd() */
int j;

if (n == 1) {
    it = 1;
    /* s = 0.5 * (b-a) * ((*f)(a) + (*f)(b)); */
    s = 0.5 * (b-a) * (f(a) + f(b));
} else {
    del = (b-a)/(double)it;
    x = a + 0.5 * del;
    for(sum = 0.0, j = 1; j <= it; ++j, x += del) {
        /* sum += (*f)(x); */
        sum += f(x);
    }
    it *= 2;
    s = 0.5 * (s + sum * del);
}
return s;
}

/*
* nrtrap.c
*
* Calkowanie metoda trapezow.
*/

#include "main.h"

double nrtrap(double (*f)(double x), double a, double b,
int maxns, double aerr, double rerr) 
{
/*
* f() - funkcja calkowana
* a, b - konce przedzialu calkowania
* maxns - max number of steps, maxns < 31
* aerr - DESIRED ABSOLUTE ERROR IN THE ANSWER
* rerr - DESIRED RELATIVE ERROR IN THE ANSWER
*/
int j;
double s, olds;

olds = -1.0e30;           /* cokolwiek byle nie (f(a)+f(b))/2 */
for (j = 1; j <= maxns; ++j) {
    s = trapzd(f, a, b, j);
#ifdef DEBUG
    printf("nrtrap: petla %d, wynik= %f\n", j, s);
#endif
    if (abs(s-olds) <= max(aerr, rerr*abs(olds)))
        return(s);
    olds = s;
}
nrerror("TOO MANY ITERATIONS IN NRTRAP");
return olds;     /* na wypadek gdyby nrerror() nie konczyl pracy */
}

/*
* nrromb.c
*/

#include "main.h"

double nrromb(double (*f)(double x), double a, double b, 
int maxns, double aerr, double rerr) 
{ /*
* f() - funkcja calkowana (1-dim)
* a, b - konce przedzialu calkowania
* int maxns - max number of steps
* double aerr - DESIRED ABSOLUTE ERROR IN THE ANSWER
* double rerr - DESIRED RELATIVE ERROR IN THE ANSWER
*/
int j, k;
double olds;   /* s to bedzie t[0] */
double t[32];       /* bo 2^31 to granica int na PC */
double pot4[32];  /* potegi liczby 4 */

olds = -1.0e30;           /* cokolwiek byle nie (f(a)+f(b))/2 */
for (j = 0; j < maxns; ++j) {  /* petla po wierszach */
    t[j] = trapzd(f, a, b, j+1);
#ifdef DEBUG
    printf("nrromb: petla nr %d\n", j);
    printf("T[0,%d]= %f\n", j, t[j]);
#endif
    if (j == 0)
        pot4[j] = 1.0;
    else 
        pot4[j]= pot4[j-1]*4.0;
    for(k= j-1; k >= 0; --k) {  /* budowanie nowego wiersza */
        t[k]= t[k+1]+(t[k+1]-t[k])/(pot4[j-k]-1.0);
#ifdef DEBUG
    printf("T[%d,%d]= %f\n", (j-k), k, t[k]);
#endif
    }
    if (abs(t[0]-olds) <= max(aerr, rerr*abs(olds)))
        return(t[0]);
    olds = t[0];
}
nrerror("TOO MANY ITERATIONS IN NRROMB");
return olds;  /* na wypadek gdyby nrerror() nie konczyl pracy */
}

Dopisać brakujące funkcje, skompilować i uruchomić program.

ZADANIE 14.2

W katalogu domowym utworzyć podkatalog bisekcja. Utworzyć w nim plik Makefile i bisekcja.c postaci:


/*
* bisekcja.c
*
* Program do znajdowania miejsc zerowych funkcji metoda bisekcji.
*/

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

#define DEBUG
#define abs(x)                  ((x) >= 0 ? (x) : -(x))

double fun1(double x);
void wypisz(double fx, double x);

int main(void) 
{
const int LKROKOW = 20;
const double EPS = 1.0e-5;
int i;
double x1, x2, xp, fx1, fx2, fxp, df;

x1 = .1;
x2 = 5.3;
fx1 = fun1(x1);
fx2 = fun1(x2);

#ifdef DEBUG
    printf("lewy   ");
    wypisz(fx1, x1);
    printf("prawy   ");
    wypisz(fx2, x2);
#endif

if (fx1*fx2 >= 0) {
    printf("Powinny byc rozne znaki na koncach przedzialu\n");
    return 1;
}
for (i = 0; i < LKROKOW; ++i) {
    xp = (x1+x2)*0.5;
    fxp = fun1(xp);
    df = (fx2-fx1)/(x2-x1);
#ifdef DEBUG
    printf("petla %d   ", i);
    wypisz(fxp, xp);
#endif
    if (abs(fxp) > EPS*abs(df)) { 
        if (fxp*fx1 < 0) {
            x2 = xp;
            fx2 = fxp;
        } else if (fxp*fx1 == 0) {
            printf("Rozwiazanie:\n");
            wypisz(fxp, xp);
            return 0;
        } else {
            x1 = xp;
            fx1 = fxp;
        }
    } else {
        printf("Rozwiazanie:\n");
        wypisz(fxp, xp);
        return 0;
    }
}
printf("Za malo petli\n");
return 1;
}

double fun1(double x) 
{
return sin(x);
}

void wypisz(double fx, double x) 
{
printf("f(x)= %f   x= %f\n", fx, x);
return;
}

Skompilować i uruchomić program.

Umieścić kod związany z bisekcją w osobnej funkcji. Do obsługi błędów wykorzystać funkcję nrerror(). Przykładowy plik main.h może mieć postać:


/*
* main.h
*
* Plik naglowkowy.
*/

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

#define DEBUG
#define abs(x)                  ((x) >= 0 ? (x) : -(x)) 

void nrerror(char error_text[]);

double bisekcja(double (*f)(double x), double a, double b, 
    int maxns, double epsilon);

ZADANIE 14.3

Zmienić interfejs funkcji z poprzednich zadań tak, aby był zgodny z funkcjami z biblioteki GSL.


Programowanie w C (index)