Obliczenia inżynierskie i naukowe - kody źródłowe

Część II - Szybkie

Poniżej przestawiamy wybrane kody źródłowe programów omawianych w drugiej części podręcznika Obliczenia inżynierskie i naukowe (PWN, 2011). Większość z nich jest dostępna na licencji Creative Commons BY-SA.

Listing 9.1 - harm.c. [Pobierz]

/*
**
** Listing 9.1 w książce "Obliczenia inżynierskie i naukowe", PWN 2011
** (C) Piotr Krzyżanowski, 2011
**
** Możesz używać tego kodu zgodnie z licencją Creative Commons BY-SA, 
** zob. http://creativecommons.org/licenses/by-sa/3.0/pl/
**
*/

/* 
Kompilacja: gcc -o harm harm.c
Uruchomienie: ./harm
*/

#include <stdio.h>
#define N 2012

int main(void)
{
	float x;
	unsigned int i;

	x = 0.0;
	for(i = 1; i <= N; i++) 
		x = x + 1.0/i;

	printf("Wartosc sumy x = 1 + 1/2 + .. + 1/%d jest rowna %g\n",  N, x);

	return(0);
}

Listing 9.2 - sinusy.c. [Pobierz]

/*
**
** Listing 9.2 w książce "Obliczenia inżynierskie i naukowe", PWN 2011
** (C) Piotr Krzyżanowski, 2011
**
** Możesz używać tego kodu zgodnie z licencją Creative Commons BY-SA, 
** zob. http://creativecommons.org/licenses/by-sa/3.0/pl/
**
*/

/* kompilacja: gcc  -o sinusy sinusy.c -lm */

#include <stdio.h> 
#include <stdlib.h> /* zawiera prototyp funkcji drand48() i srand48() */
#include <math.h>

#define N 15 /* ile liczb wydrukować */

int main(void)
{
int i;
double x, y[N];

srand48(time(NULL)); /* inicjalizacja generatora liczb losowych;
		nie używać, gdy chcemy mieć powtarzalne (sic!) wyniki */

for( i = 0; i < N; i++)
{
	x = 2.0*M_PI*drand48();
	y[i] = sin(x);
	fprintf(stderr, "(%3d) x = %10.5le | sin(x) = %10.5le\n", i, x, y[i]);
}

return(0);
}

Listing 9.3 - zapiszdane.c. [Pobierz]

/*
**
** Listing 9.3 w książce "Obliczenia inżynierskie i naukowe", PWN 2011
** (C) Piotr Krzyżanowski, 2011
**
** Możesz używać tego kodu zgodnie z licencją Creative Commons BY-SA, 
** zob. http://creativecommons.org/licenses/by-sa/3.0/pl/
**
*/

/* kompilacja: gcc -o zapiszdane zapiszdane.c -lm */

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

const int N = 10; 	/* liczba wierszy */
const int M = 5;	/* liczba kolumn */

#define IJ(i,j,N) (((i)-1) + ((j)-1)*(N))

int main(void)
{
FILE *plik;
double *T;
int i,j;

/* Faza 1: tworzymy tablicę liczb T */

if ((T = (double *) malloc(N*M*sizeof(double))) == NULL)
{
	fprintf(stderr, "Nie mozna przydzielic pamieci\n");
	return(-1);
}

for( j = 1; j <= M; j++)
	for( i = 1; i <= N; i++)
		T[IJ(i,j,N)] = exp(-i/(double)N -j);
		
/* Faza 2: wypisujemy dane z tablicy T do pliku tablica.dat */

if ((plik = fopen("tablica.dat","w")) == NULL)
{
	fprintf(stderr, "Nie mozna otworzyc pliku\n");
	return(-1);
}

fprintf(plik, "%8d %8d\n", N, M);
for( i = 1; i <= N; i++)
{
	for( j = 1; j <= M; j++)
		fprintf(plik, "%16.10E ", T[IJ(i,j,N)]);
	fprintf(plik, "\n");
}

/* Faza 3: sprzątanie */
ferror(plik);
fclose(plik);
free(T);
return(0);
}

Listing 9.4 - wczytajdane.c. [Pobierz]

/*
**
** Listing 9.4 w książce "Obliczenia inżynierskie i naukowe", PWN 2011
** (C) Piotr Krzyżanowski, 2011
**
** Możesz używać tego kodu zgodnie z licencją Creative Commons BY-SA, 
** zob. http://creativecommons.org/licenses/by-sa/3.0/pl/
**
*/

/* kompilacja: gcc -o wczytajdane wczytajdane.c */
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#define IJ(i,j,N) (((i)-1) + ((j)-1)*(N))

int main(int argc, char** argv)
{
FILE *plik;
double *X; /* tu będzie wczytana macierz */
int N,M; /* zmienne na wymiary macierzy */
int i,j;

/* wczytujemy dane z pliku do tablicy - najpierw musimy ustalić jej wymiary */

if ( (plik = fopen(argv[1], "r")) == NULL )
{
	fprintf(stderr, "Nie można otworzyć pliku '%s'\n", argv[1]);
	return(-1);
}

fscanf(plik, "%d %d\n", &N, &M);

/* znając wymiary, alokujemy pamięć na macierz */

if ((X = (double *) malloc(N*M*sizeof(double))) == NULL)
{
	fprintf(stderr, "Nie można przydzielić pamięci\n");
	return(-1);
}

fprintf(stderr, "Wczytuje macierz %d x %d\n", N, M);

for( i = 1; i <= N; i++)
{
	for( j = 1; j <= M; j++)
		fscanf(plik, "%lE", &X[IJ(i,j,N)]);
}

/* ...i od tej pory możemy używać tablicy X, 
  wypełnionej danymi z pliku; ale my już kończymy program... */

fclose(plik);
free(X);
return(0);

}

Listing 9.5 - IJ.h. [Pobierz]

/*
**
** Listing 9.5 w książce "Obliczenia inżynierskie i naukowe", PWN 2011
** (C) Piotr Krzyżanowski, 2011
**
** Możesz swobodnie używać tego kodu
**
*/

/* makra dostępu do macierzy rozwiniętej kolumnami */
/* elementy indeksowane od "1" */
#define I(i) ((i)-1) /* wektor */
#define IJ(i,j,n) ((i)-1+((j)-1)*(n)) /* macierz n x m */
#define IJK(i,j,k,n,m) ((i)-1+((j)-1)*(n)+((k)-1)*(n*m)) /* macierz n x m x k */

Listing 9.6 - testblas.c. [Pobierz]

/*
**
** Listing 9.6 w książce "Obliczenia inżynierskie i naukowe", PWN 2011
** (C) Piotr Krzyżanowski, 2011
**
** Możesz używać tego kodu zgodnie z licencją Creative Commons BY-SA, 
** zob. http://creativecommons.org/licenses/by-sa/3.0/pl/
**
*/

/* Kompilacja:
	gcc -o testblas testblas.c -lblas -lgfortran -lm 
*/

#include <stdio.h>
#define N 3

extern double dnrm2_(int*,double*,int*); /* prototyp DNRM2 z BLAS */

int main(void)
{
	int n=N, incx=1;
	double x[N]= {3,0,4};
	
	printf("Norma zadanego wektora: %e\n", dnrm2_(&n, x, &incx));
	return(0);
}

Listing 9.7 - mx2.c. [Pobierz]

/*
**
** Listing 9.7 w książce "Obliczenia inżynierskie i naukowe", PWN 2011
** (C) Piotr Krzyżanowski, 2011
**
** Możesz używać tego kodu zgodnie z licencją Creative Commons BY-SA, 
** zob. http://creativecommons.org/licenses/by-sa/3.0/pl/
**
*/

#include <stdio.h>
#include <stdlib.h>
#include "mx2.h"

double *mx2alloc(int n, int m)
{
/* przydziela pamięć na macierz n x m liczb typu double */
	return((double *) malloc(n*m*sizeof(double)));
}

void mx2free( double *matrix )
{
/* zwalnia pamięć wskazywaną przez matrix */
	free(matrix);
}

void mx2rand( double *matrix, int n, int m)
{
/* generuje losową macierz n x m o wartościach z przedziału [0,1) */
int i,j;
for( j = 1; j <= m; j++)
	for( i = 1; i <= n; i++)
		matrix[IJ(i,j,n)] = drand48();
}

int mx2write( double *matrix, int n, int m, char *nazwapliku)
{
/* zapisuje (wierszami) macierz do pliku tekstowego;
   w pierwszej linii podajemy wymiary macierzy */
int i,j;
FILE *plik;

if ((plik = fopen(nazwapliku,"w")) == NULL)
{
	fprintf(stderr, "Nie mozna otworzyc pliku: %s\n", nazwapliku);
	return(-1);
}

fprintf(plik, "%8d %8d\n", n, m);
for( i = 1; i <= n; i++)
{
	for( j = 1; j <= m; j++)
		fprintf(plik, "%16.10E ", matrix[IJ(i,j,n)]);
	fprintf(plik, "\n");
}

fclose(plik);
return(0);
}

double mx2frobnorm(double *matrix, int n, int m)
{
/* 
Norma Frobeniusa macierzy dwuwymiarowej: $||A||_F = \sqrt{\sum_{i,j} A_{ij}^2}$ Wystarczy potraktować macierz jako długi wektor (a to już i tak zrobiliśmy), 
a potem obliczyć jego normę euklidesową, korzystając z DNRM2 z biblioteki BLAS 
*/
static int incx=1;
int size;
	size = n*m;
	return(dnrm2_(&size, matrix, &incx)); 
}

Listing 9.8 - mx2.h. [Pobierz]

/*
**
** Listing 9.8 w książce "Obliczenia inżynierskie i naukowe", PWN 2011
** (C) Piotr Krzyżanowski, 2011
**
** Możesz używać tego kodu zgodnie z licencją Creative Commons BY-SA, 
** zob. http://creativecommons.org/licenses/by-sa/3.0/pl/
**
*/

/* plik nagłówkowy dla biblioteczki macierzowej: macierze 2-wymiarowe */

#include "IJ.h" /* makro dostępu do elementów macierzy */

/* prototyp funkcji DNRM2 z BLAS */
extern double dnrm2_(int *, double *, int *);

/* prototypy definiowanych funkcji */

double *mx2alloc(int n, int m);
void mx2free( double *matrix );
void mx2rand( double *matrix, int n, int m);
int mx2write( double *matrix, int n, int m, char *nazwapliku);
double mx2frobnorm(double *matrix, int n, int m);

Listing 9.9 - testmx.c. [Pobierz]

/*
**
** Listing 9.9 w książce "Obliczenia inżynierskie i naukowe", PWN 2011
** (C) Piotr Krzyżanowski, 2011
**
** Możesz używać tego kodu zgodnie z licencją Creative Commons BY-SA, 
** zob. http://creativecommons.org/licenses/by-sa/3.0/pl/
**
*/

#include <stdio.h>
#include "mx2.h"

int main(void)
{
int N=10, M=5;
double *A;

A = mx2alloc(N,M);
mx2rand(A,N,M);
A[IJ(1,1,N)] = 1.0;
mx2write(A,N,M,"macierzA.dat");
printf("Norma Frobeniusa wygenerowanej macierzy = %e\n", 
	mx2frobnorm(A,N,M));
return(0);
}

Listing 9.10 - Makefile. [Pobierz]

##
## Listing 9.10 w książce "Obliczenia inżynierskie i naukowe", PWN 2011
## (C) Piotr Krzyżanowski, 2011
##
## Możesz swobodnie używać tego kodu
##

# Makefile dla programu testblas.c
CC = gcc
CFLAGS = -O3
CLIBS = -lblas -lgfortran -lm

testblas: testblas.c 
	$(CC) $(CFLAGS) -o $@ $< $(CLIBS)

Listing 9.13 - Makefile-umfpack. [Pobierz]

##
## Listing 9.13 i 10.11 w książce "Obliczenia inżynierskie i naukowe", PWN 2011
## (C) Piotr Krzyżanowski, 2011
##
## Możesz używać tego kodu zgodnie z licencją Creative Commons BY-SA, 
## zob. http://creativecommons.org/licenses/by-sa/3.0/pl/
##

# Zapisz ten plik pod nazwą "Makefile"!

#
# "uniwersalny" Makefile przystosowany do kompilacji pliku testumfpacksolve.c
# z listingu 10.10
#

#--------- definicja konkretnego zadania (projektu) ---------
PROJECT = testumfpacksolve

#--------- ogólne definicje ---------
CC = gcc
CFLAGS = -O3 -funroll-loops -static
CLIBS = -lumfpack -lamd -llapack -lblas -lgfortran -lm
CINCDIR = -I/usr/include/suitesparse -I..

#--------- pliki źródłowe i pośrednie -----------	
OBJS = mmread.o mmio.o $(PROJECT).o

#--------- ogólne reguły ---------
%.o: %.c Makefile $(HEADERS)
	$(CC) $(CFLAGS) $(CINCDIR) -c $< -o $@ 

#--------- główne zadanie ---------
$(PROJECT): $(OBJS)
	$(CC) $(CFLAGS) $(CLIBDIR) -o $@ $(OBJS) $(CLIBS) -lrt

#--------- praktyczne zadania ogólne ---------
clean:
	rm $(OBJS) $(PROJECT)

Listing 10.1 - sinusy-gsl.c. [Pobierz]

/*
**
** Listing 10.1 w książce "Obliczenia inżynierskie i naukowe", PWN 2011
** (C) Piotr Krzyżanowski, 2011
**
** Możesz używać tego kodu zgodnie z licencją Creative Commons BY-SA, 
** zob. http://creativecommons.org/licenses/by-sa/3.0/pl/
**
*/

/* Kompilacja: 
	gcc -o sinusy-gsl sinusy-gsl.c -lgsl -lgslcblas -lm
*/
#include <stdio.h> 
#include <gsl/gsl_rng.h> /* zawiera prototypy funkcji losowych GSL */
#include <math.h>

#define N 15 /* ile liczb wydrukować */

int main(void)
{
int i;
double x,y;
gsl_rng *rng; /* wskaźnik do generatora, którego będziemy używać */

gsl_rng_env_setup(); 	/* inicjalizacja domyślnego generatora 
			gsl_rng_default i jego ziarna,
			na podstawie zmiennych środowiskowych 
			GSL_RNG_TYPE i GSL_RNG_SEED. 
			Domyślnie GSL_RNG_TYPE=gsl_rng_mt19937
			oraz GSL_RNG_SEED=0 */ 
			
rng = gsl_rng_alloc(gsl_rng_default); /* utworzenie instancji rng 
			generatora liczb losowych domyślnego typu */

gsl_rng_set(rng, time(NULL)); /* zasianie wygenerowanego generatora 
			bieżącą wartością czasu systemowego */

for( i = 0; i < N; i++)
{
	x = 2.0*M_PI*gsl_rng_uniform(rng);
	y = sin(x);
	fprintf(stderr, "(%3d) x = %10.5le sin(x) = %10.5le\n", i, x, y);
}

gsl_rng_free(rng); /* usuwamy niepotrzebny już generator */

return(0);
}

Listing 10.2 - testgslint.c. [Pobierz]

/*
**
** Listing 10.2 w książce "Obliczenia inżynierskie i naukowe", PWN 2011
** (C) Piotr Krzyżanowski, 2011
**
** Możesz używać tego kodu zgodnie z licencją Creative Commons BY-SA, 
** zob. http://creativecommons.org/licenses/by-sa/3.0/pl/
**
*/

#include <stdio.h>
#include <math.h>
#include <gsl/gsl_integration.h>

double F(double X, void * param) /* wrapper dla funkcji sin(x)/x */
{
	return(sin(X)/X);
}


int main(void)
{
	gsl_function f; /* argument z funkcją podcałkową */

	double A,ABSERR,B, EPSABS,EPSREL,RESULT;
	int IER,NEVAL;

	gsl_integration_workspace *workspace;

	int KEY, LIMIT; 

	/* przygotowujemy argument z funkcją podcałkową */
	f.function = &F;
	
	A = 0.0E0; B = 10*M_PI; /* przedział całkowania */
	EPSABS = 0.0E0; EPSREL = 1.0E-3; /* tolerancja błędu */

	/* parametry specyficzne dla QAG */
	KEY = 1; /* tzn. użyj minimalnej liczby punktów kwadratury bazowej */
	LIMIT = 100; /* maksymalny podział przedziału całkowania */
	workspace  = gsl_integration_workspace_alloc(LIMIT);
	
	/* całkujemy: QAG! */

	IER = gsl_integration_qag(&f, A, B, EPSABS, EPSREL, 
					LIMIT, KEY, workspace, &RESULT, &ABSERR);

	if (IER != 0)
		fprintf(stderr,"GSL_QAG: Kłopoty z całkowaniem\n");
	fprintf(stderr,"Całka: %g Est. błąd: %g IER: %d\n", RESULT, ABSERR,  IER);

	gsl_integration_workspace_free(workspace);
	
}

Listing 10.4 - sinusy-acml.c. [Pobierz]

/*
**
** Listing 10.4 w książce "Obliczenia inżynierskie i naukowe", PWN 2011
** (C) Piotr Krzyżanowski, 2011
**
** Możesz używać tego kodu zgodnie z licencją Creative Commons BY-SA, 
** zob. http://creativecommons.org/licenses/by-sa/3.0/pl/
**
*/

/* Kompilacja wersji dla x86 (tzn. 32-bitowej): 
	gcc -static -o sinusy-acml sinusy-acml.c \
	 -I $HOME/Software/acml4.3.0/gfortran32/include \
	 -L $HOME/Software/acml4.3.0/gfortran32/lib \
	 -lacml -lgfortran -lm -lrt
Kompilacja wersji dla x86-64 (tzn. 64-bitowej): 
	gcc -static -o sinusy-acml sinusy-acml.c \
	 -D ACML_MV \
	 -I $HOME/Software/acml4.3.0/gfortran64/lib \
	 -L $HOME/Software/acml4.3.0/gfortran64/lib \
	 -lacml_mv -lacml -lgfortran -lm -lrt
*/
#include <stdio.h> 
#include <stdlib.h> 
#include <acml.h> /* zawiera prototypy funkcji losowych ACML */
#ifdef ACML_MV
	#include <acml_mv.h>/* zawiera prototypy funkcji wektorowych ACML */
#endif
#include <math.h>

/* stałe opisujące paramtery generatora Mersenne Twister (MT) w ACML */
#define DRAND_MT_CODE 2 /* kod generatora */
#define DRAND_MT_LSEED 624 /* rozmiar tablicy z ziarnem */
#define DRAND_MT_LSTATE 20 /* rozmiar tablicy stanu */

#define N 15 /* ile liczb wydrukować */

int main(void)
{
int i;
double x[N],y[N];

/* zmienne wymagane do inicjalizacji generatora liczb losowych */
int drand_lseed = DRAND_MT_LSEED; 
int drand_seed[DRAND_MT_LSEED];
int drand_lstate = DRAND_MT_LSTATE;
int drand_state[DRAND_MT_LSTATE];
int drand_info;

/* inicjalizacja ziarna generatora MT */
for(i=0; i < DRAND_MT_LSEED; i++)
	drand_seed[i] = rand();
	
/* inicjalizacja generatora bazowego */
drandinitialize(DRAND_MT_CODE, 1, drand_seed, &drand_lseed, 
		drand_state, &drand_lstate, &drand_info);

/* generujemy od razu N liczb losowych! */
dranduniform(N, 0.0, 2.0*M_PI, drand_state, x, &drand_info); 

#ifdef ACML_MV
	vrda_sin(N, x, y); /* wektorowa instrukcja sin() */
#else
	for( i = 0; i < N; i++)
	{
		y[i] = sin(x[i]);
	}
#endif

for( i = 0; i < N; i++)
	fprintf(stderr, "(%3d) x = %10.5le sin(x) = %10.5le\n", i, x[i], y[i]);

return(0);
}

Listing 10.5 - blaslapack.h. [Pobierz]

/*
**
** Listing 10.5 w książce "Obliczenia inżynierskie i naukowe", PWN 2011
** (C) Piotr Krzyżanowski, 2011
**
** Możesz używać tego kodu zgodnie z licencją Creative Commons BY-SA, 
** zob. http://creativecommons.org/licenses/by-sa/3.0/pl/
**
*/

/* przydatne pliki nagłówkowe dla procedur BLAS i LAPACK-a */

#include <stdlib.h>
#include "IJ.h" /* makra dostępu do macierzy i wektorów - zob. listing 9.5 */

/* przydatne stałe */
static int BLASONE = 1, BLASMONE = -1, BLASZERO = 0;

/* BLAS Level 1 */
extern double dnrm2_(int* N, double* X, int* INCX);

/* BLAS Level 2 */
extern void dgemv_( char * TRANS, int * M, int * N, \
	double * ALPHA, double * A,  int * LDA, double * X,  int * INCX, \
	double * BETA, double * Y, int * INCY );

/* BLAS Level 3 */
extern void dgemm_(char * TRANSA,char * TRANSB, int * M, int * N, int * K, \
	double * ALPHA, double * A,  int * LDA,  double * B,  int * LDB, \
	double * BETA, double * C, int * LDC );

/* LAPACK */
extern void dgesv_( int * N, int * NRHS, double * A, int * LDA, \
	int * IPIV, double * B, int * LDB, int * INFO );
extern void dsysv_(char *, int *, int *, double *, int *, \
	int *, double *, int *, double *, int *, int *);
extern void dgels_( char * TRANS,  int * M, int * N, int * NRHS, \
	double * A, int * LDA, double * B, int * LDB, \
	int * WORK, double * LWORK, int * INFO);

Listing 10.6 - testdgemv.c. [Pobierz]

/*
**
** Listing 10.6 w książce "Obliczenia inżynierskie i naukowe", PWN 2011
** (C) Piotr Krzyżanowski, 2011
**
** Możesz używać tego kodu zgodnie z licencją Creative Commons BY-SA, 
** zob. http://creativecommons.org/licenses/by-sa/3.0/pl/
**
*/

#include <stdio.h>
#include "blaslapack.h"

int main()
{
	int N = 5, i, j;
	double *A, *x, *y;
	
	/* generujemy przykładową macierz N x N jako odwrotną macierz Laplasjanu */
	A = (double *)malloc(N*N*sizeof(double));
	for (j = 1; j <= N; j++)
	{
		for (i = 1; i <= j; i++)
			A[IJ(i,j,N)] = i;
		for (i = j+1; i <= N; i++)
			A[IJ(i,j,N)] = j;			
	}
	
	/* tworzymy wektory x i y, inicjalizujemy x */
	x = (double *)malloc(N*sizeof(double));
	y = (double *)malloc(N*sizeof(double));
	for (i = 1; i <= N; i++)
		x[I(i)] = (double)i;

	/* obliczamy y = 5*A*x, korzystając z procedury BLAS Level 2: 
	DGEMV dla zadania y = 5*A*x + 0*y */

	{
		char TRANS = 'N'; double ALPHA = 5.0, BETA = 0.0;

		dgemv_(&TRANS, &N, &N, &ALPHA, A,  &N,  x,  &BLASONE, 
			&BETA, y, &BLASONE );
	}
	
	for (i = 1; i <= N; i++)
		printf("%E\n",y[I(i)]);
	
	return(0);
}

Listing 10.10 - testumfpacksolve.c. [Pobierz]

/*
**
** Listing 10.10 w książce "Obliczenia inżynierskie i naukowe", PWN 2011
** (C) Piotr Krzyżanowski, 2011
**
*/

#include <stdio.h>
#include <malloc.h>
#include "umfpack.h"

#define CHECK(status) 	{if (status != 0) \
	{ fprintf(stderr, "==> An error occured. Aborting program!\n"); \
	 return(-1);}}

/* procedura wczytująca macierz do formatu AIJ indeksowanego od zera */
int mmreadsparse(char *filename, int* N, int* M, int* nz, int** I, int** J,
double** Val );

int main(int argc, char** argv)
{
int M, N, nz; /* wymiary macierzy i liczba niezerowych elementów */  
int *Ap, *Ai; double *Av; /* tu będziemy przechowywać macierz w formacie CSC */
int *I, *J; double *Val; /* tu będziemy przechowywać macierz w formacie AIJ */

double *x, *b; /* wektory prawej strony i rozwiązania */
int i;

/* zmienne używane przez procedury UMFPACK */
double Control[UMFPACK_CONTROL], Info[UMFPACK_INFO];
void *Symbolic, *Numeric;
int status; /* kod zakończenia procedury: różny od zera oznacza kłopoty */

/* ustawiamy parametry sterujące UMFPACKa */
umfpack_di_defaults(Control);    
Control[UMFPACK_PRL] = 2; /* poziom szczegółowości diagnostyki */
umfpack_di_report_control(Control);

if (argc < 2) /* sposób użycia programu */
{
	fprintf(stderr,"Wywołanie: %s PlikMacierzy [PlikPrawejStrony [PlikRozwiązania]]\n", argv[0]);
	return(-1);
}
/* wczytujemy macierz w formacie MatrixMarket do formatu AIJ*/
if (mmreadsparse(argv[1], &N, &M, &nz, &I, &J, &Val ) != 0)
	return(-1);

/* Transformujemy macierz z formatu AIJ do formatu CSC */
Ap = (int *) malloc((N+1) * sizeof(int)); /* N+1, a nie N: to ważne!! */
Ai = (int *) malloc(nz * sizeof(int));
Av = (double *) malloc(nz * sizeof(double));
umfpack_di_triplet_to_col(N,N,nz, I,J,Val, Ap,Ai,Av,(int *)NULL );

umfpack_di_report_matrix(N,N, Ap, Ai, Av, 1, Control);
umfpack_di_report_triplet(N,N,nz, I, J, Val, Control);

/* zwalniamy pamięć zajmowaną przez niepotrzebne zmienne pomocnicze */
free(I); free(J); free(Val);
 
/* faktoryzacja symboliczna, reordering */
status = umfpack_di_symbolic(N, N, Ap, Ai, Av, &Symbolic, Control, Info); 
umfpack_di_report_status(Control,status);
CHECK(status);

/* faktoryzacja numeryczna */
status = umfpack_di_numeric(Ap, Ai, Av, Symbolic, &Numeric, Control, Info); 
umfpack_di_report_status(Control,status);
CHECK(status);

/* szykujemy wektory rozwiązania i prawej strony */
x = (double *)calloc(N,sizeof(double));
b = (double *)calloc(N,sizeof(double));  /* calloc zeruje alokowaną pamięć */

/* wczytujemy wektor prawej strony (o ile jest podany) w formacie MatrixMarket*/
if (argc > 2) 
{
	int Nrhs, Mrhs;
	
	if (mmreadsparse(argv[2], &Nrhs, &Mrhs, &nz, &I, &J, &Val) != 0)
		return(-1);
	else
		fprintf(stderr,"Wczytano prawą stronę : %dx%d\n", Nrhs, Mrhs);
	if (Mrhs > 1)
	{
		fprintf(stderr,"Oczekiwano jednego wektora prawej strony!\n");
		return(-1);
	}
	
	/* zapisujemy go do wektora b */
	for (i = 1; i <= nz; i++)
		b[I[i]] += Val[i];

	/* zwalniamy pamięć zajmowaną przez niepotrzebne zmienne pomocnicze */
	free(I); free(J); free(Val);
}

/* rozwiązanie układu Ax=b */
status = umfpack_di_solve(UMFPACK_A, Ap, Ai, Av, x, b, Numeric, Control, Info); 
umfpack_di_report_status(Control,status);
CHECK(status);

/* statystyki */
umfpack_di_report_info(Control,Info);

/* sprzątanie */
umfpack_di_free_symbolic(&Symbolic);
umfpack_di_free_numeric(&Numeric);

/* ... korzystamy z wyznaczonego rozwiązania x .... */
/* zapisujemy je do pliku (tekstowego), o ile było takie życzenie */
if (argc > 3) 
{
	FILE *plik;
	if ((plik = fopen( argv[3], "w")) == NULL)
	{
		fprintf(stderr, "Nie mozna zapisac pliku %s\n", argv[3]);
		return(-1);
	}
	for (i = 0; i < N; i++)
		fprintf(plik, "%26.10e \n", x[i]);
	fclose(plik);	
}

/* zwalniamy pamięć zajmowaną przez niepotrzebne zmienne */
free(Ap); free(Ai); free(Av); free(x); free(b);

return(0);
}

Listing 11.1 - timer.c. [Pobierz]

/*
**
** Listing 11.1 w książce "Obliczenia inżynierskie i naukowe", PWN 2011
** (C) Piotr Krzyżanowski, 2011
**
** Możesz używać tego kodu zgodnie z licencją Creative Commons BY-SA, 
** zob. http://creativecommons.org/licenses/by-sa/3.0/pl/
**
*/

/* Stoper w C, mierzący czas na trzy różne sposoby, 
za pomocą funkcji clock(), times(), clock_gettime(). 
Sposób użycia:
	tic();
	... instrukcje ...
	czas = toc();
*/

#include <stdio.h>
#include <unistd.h>	/* zawiera pewne stałe systemowe */
#include <sys/times.h> 	/* zawiera funkcję times() */
#include <time.h> 	/* zawiera funkcję clock_gettime() i clock() */

static clock_t start_clk, stop_clk; /* dla clock() */
static struct tms start_tms, stop_tms; /* dla times() */
static struct timespec start_tmsp, stop_tmsp; /* dla clock_gettime() */

double tic(void)
{
	fprintf(stderr, ">>>> Stoper START\n");
	
	start_clk = clock();
	times(&start_tms);
	clock_gettime(CLOCK_REALTIME, &start_tmsp);
	
	return(0.0);
}

double toc(void)
{
double cpu_timer_clk;
double cpu_timer_total;
double cpu_timer_real;

	stop_clk = clock();
	times(&stop_tms);
	clock_gettime(CLOCK_REALTIME, &stop_tmsp);
	
	cpu_timer_total = (stop_tms.tms_utime-start_tms.tms_utime) *
			(1.0/sysconf(_SC_CLK_TCK));
	cpu_timer_clk = (stop_clk-start_clk) *
			(1.0/CLOCKS_PER_SEC);
	cpu_timer_real = stop_tmsp.tv_sec-start_tmsp.tv_sec +
			1e-9*(stop_tmsp.tv_nsec-start_tmsp.tv_nsec);
	
	fprintf(stderr, "<<<< Stoper STOP: %g (TOTAL CPU) %g (CLOCK) %g (REAL) sekund\n", 
			cpu_timer_total, cpu_timer_clk, cpu_timer_real);
	
	return(cpu_timer_real);
}
© Piotr Krzyżanowski, 2009-2011.