7 Commits

Author SHA1 Message Date
2c7511da52 Fix vector printing 2020-03-22 13:40:39 +01:00
50081506f3 Finale Anpassungen 2020-03-22 13:33:37 +01:00
ebaf6a77f2 Kommentare, Formatierung, Fixes und Vereinfachungen 2020-03-20 11:39:29 +01:00
bfa5fb3ce8 Finish 2020-03-17 20:39:21 +01:00
20e98a1105 SolveFuction_gauss_jacobi_working 2020-03-10 19:51:15 +01:00
8bd26b9a9c jacobi and gauss solve function working 2020-03-10 19:43:16 +01:00
077a54af18 More basic structure for solve 2020-02-24 15:20:02 +01:00
6 changed files with 297 additions and 238 deletions

Binary file not shown.

View File

@@ -1,3 +1,3 @@
@echo off @echo off
gcc -Wall -g -lm -std=c99 main.c -o main.exe gcc -Wall -g -std=c99 %1.c -o %1.exe
@echo on @echo on

View File

@@ -1 +0,0 @@
gcc -Wall -g -std=c99 -lm main.c -o main

BIN
main

Binary file not shown.

529
main.c
View File

@@ -1,3 +1,9 @@
/**
* Implementierung des Programmentwurfs aus Programmieren 1
*
* Autoren: Simon Bestler und Johannes Freitag
* Das dritte Gruppenmitglied hat nicht am Projekt mitgewirkt und den Studiengang verlassen (Simeon Burk).
*/
#include <stdbool.h> #include <stdbool.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@@ -5,376 +11,427 @@
#include <time.h> #include <time.h>
#include <math.h> #include <math.h>
/**
* Hilfsmakro für {@code STR(X)}
*/
#define _STR(X) #X #define _STR(X) #X
/**
* Makro das den gegebenen Wert in einen String convertiert
*/
#define STR(X) _STR(X) #define STR(X) _STR(X)
/**
* Die maximal erlaubte Länge eines Dateipfads
*/
#define MAX_FILE_PATH_LENGTH FILENAME_MAX #define MAX_FILE_PATH_LENGTH FILENAME_MAX
/**
* Formatierungsvorlage um den Dateipfad einzulesen.
* Die hier verwendete ANSI-C-kompatible Formatierung wird von der CodeBlocks MinGW-Version nicht unterstützt. In neueren Versionen von MinGW und allen anderen getesteten Compilern funktioniert das verwendete Format.
* Für CodeBlocks kann alternativ "%s" verwendet werden. Diese Formatierung ist aufgrund der nicht gegebenen Länge allerdings fehleranfällig.
*/
#define FILE_PATH_PATTERN "%" STR(MAX_FILE_PATH_LENGTH) "[^\n]"
/**
* Die maximal erlaubte Größe einer Matrix
*/
#define MAX_MATRIX_SIZE 500 #define MAX_MATRIX_SIZE 500
/**
* Die maximale Anzahl von verketteten doubles in den Dateien
*/
#define MAX_MATRIX_IN_FILE_SIZE (MAX_MATRIX_SIZE + 2) #define MAX_MATRIX_IN_FILE_SIZE (MAX_MATRIX_SIZE + 2)
/**
* Maximale Zahl der Iterationsschritte
*/
#define MAX_ITERATION_STEPS 100 #define MAX_ITERATION_STEPS 100
/**
* Die Struktur zur Speicherung von Matrizen. Speicherplatz für die Daten muss dynamisch als Pointer-Array allokiert werden.
*/
typedef struct { typedef struct {
int n; int n;
double** data; double** data;
} Matrix; } Matrix;
/**
* Erstellt eine neue Matrix-Struktur der Größe 0 mittels dynamischer Speicher-Allokation.
* @return Ein Zeiger auf die neue Struktur.
*/
Matrix* createMatrix(void); Matrix* createMatrix(void);
/**
* Gibt den Speicherplatz einer dynamisch allokierten Matrix wieder frei.
*/
void freeMatrix(Matrix* matrix); void freeMatrix(Matrix* matrix);
/**
* Füllt eine Matrix mit {@code rows} Zeilen.
*/
void createMatrixRows(Matrix* matrix, int rows); void createMatrixRows(Matrix* matrix, int rows);
/**
* Schreibt eine Matrix in die Konsole.
*/
void printMatrix(Matrix* matrix); void printMatrix(Matrix* matrix);
/**
* Die Struktur zur Speicherung von Vektoren. Speicherplatz für die Daten muss dynamisch allokiert werden.
*/
typedef struct { typedef struct {
int n; int n;
double* data; double* data;
} Vector; } Vector;
/**
* Erstellt eine neue Vektor-Struktur der Größe 0 mittels dynamischer Speicher-Allokation.
* @see initVector
* @return Ein Zeiger auf die neue Struktur
*/
Vector* createVector(void); Vector* createVector(void);
/**
* Allokiert den Speicher für einen {@code size} großen Vektor.
* @param vector ein Zeiger auf einen nicht initialisierten Vektor
* @param size die Größe des Vektors
*/
void initVector(Vector* vector, int size); void initVector(Vector* vector, int size);
/**
* Gibt den Speicherplatz eines dynamisch allokierten Vektors wieder frei.
* @param vector ein Zeiger auf den freizugebenden Vektor
*/
void freeVector(Vector* vector); void freeVector(Vector* vector);
/**
* Schreibt einen Vektor in die Konsole.
* @param vector ein Zeiger auf den Vektor
*/
void printVector(Vector* vector); void printVector(Vector* vector);
/**
* Die Auflistung aller erlaubten Berechnungs-Algorithmen.
*/
typedef enum { typedef enum {
JACOBI = 0, GAUSS_SEIDEL = 1 JACOBI = 0, GAUSS_SEIDEL = 1
} Method; } Method;
/**
* Beseitigt nicht eingelesene Daten aus der Konsoleneingabe.
*/
void flushStdin(void); void flushStdin(void);
/**
* Hauptfunktion die eine Matrix und zwei Vektoren aus der gegebenen Datei lädt und in den durch Zeiger gegebenen Strukturen speichert.
* @param filename Dateipfad zu der Datei. Unter Windows immer absolut, unter Linux auch relativ.
* @param A Ein Zeiger auf eine leere Matrix
* @param b Ein Zeiger auf einen leeren Vektor
* @param x Ein Zeiger auf einen leeren Vektor
* @return Gibt an ob die Daten erfolgreich geladen wurden
*/
bool load(const char* filename, Matrix* A, Vector* b, Vector* x); bool load(const char* filename, Matrix* A, Vector* b, Vector* x);
/**
* Hauptfunktion die das durch eine Matrix und einen Vektor gegebene LGS mit einem bestimmten Startwert löst.
* @param mmethod Der Algorithmus, der zur Lösung verwendet werden soll.
* @param A Die Koeffizienten der Unbekannten gegeben als Zeiger auf die Matrix
* @param b Die konstanten Glieder der Gleichungen gegeben als Zeiger auf den Vektor
* @param x Ein Zeiger auf einen Vektor mit Startwerten
* @param e Die Genauigkeit, auf die die Lösung bestimmt werden soll
* @return {@code NULL} bei Fehlern. Ansonsten ein Vektor-Array der Größe {@code MAX_ITERATION_STEPS + 1}. Das Array beginnt mit dem Startwert und endet vorzeitig mit einem Vektor der Größe {@code 0}.
*/
Vector* solve(Method method, Matrix* A, Vector* b, Vector* x, double e); Vector* solve(Method method, Matrix* A, Vector* b, Vector* x, double e);
Vector* solveJacobi(Matrix* A, Vector* b, Vector* x, double e);
Vector* solveGaussSeidel(Matrix* A, Vector* b, Vector* x, double e);
/**
* Liest ein double-Array aus der gegebenen Datei.
* @param file Ein Zeiger auf die Datei
* @param matrixLine Ein double-Array der Länge {@code maxCols} oder größer
* @param maxCols die maximal zu lesende Anzahl an doubles
* @return Die Anzahl der gelesenen doubles. Negativ wenn ein Fehler aufgetreten ist
*/
int readMatrixLine(FILE* file, double* matrixLine, int maxCols); int readMatrixLine(FILE* file, double* matrixLine, int maxCols);
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
char filePath[MAX_FILE_PATH_LENGTH]; char filePath[MAX_FILE_PATH_LENGTH + 1]; // char-Array zum Speichern des Dateipfads (1 char mehr für '\0')
if(argc >= 2) { // If arguments specified if(argc >= 2) { // Wenn Argumente übergeben wurden
strncpy(filePath, argv[1], MAX_FILE_PATH_LENGTH); // use first argument as filePath strncpy(filePath, argv[1], MAX_FILE_PATH_LENGTH); // Das erste Argument wird (auf MAX_FILE_PATH_LENGTH gekürzt) in filePath kopiert
} else { // Otherwise read from stdin } else {
puts("Please enter the path of the file you'd like to open"); puts("Please enter the path of the file you'd like to open");
int result = scanf("%" STR(MAX_FILE_PATH_LENGTH) "[^\n]", filePath); int result = scanf(FILE_PATH_PATTERN, filePath); // Liest MAX_FILE_PATH_LENGTH Zeichen aus der Konsole bis zum ersten Zeilenumbruch
if(result == EOF || result == 0 || filePath[0] == 0) { // If an error occured or no text has been entered -> exit if(result == EOF || result == 0 || filePath[0] == 0) { // Wenn Nichts gelesen werden konnte wird das Programm erfolgreich beendet
return 0; return 0;
} }
if(result != 1) { if(result != 1) { // Wenn ein Fehler beim Lesen aufgetreten ist wird das Programm mit Fehlermeldung beendet
fputs("Couldn't read file path - stopping\n", stderr); fputs("Couldn't read file path - stopping\n", stderr);
return 1; return 1;
} }
flushStdin(); flushStdin(); // Die Konsoleneingabe wird bereinigt
} }
// Speicherallokation für die Matrix und die Vektoren
Matrix* matrix = createMatrix(); Matrix* matrix = createMatrix();
Vector* b = createVector(); Vector* b = createVector();
Vector* x = createVector(); Vector* x = createVector();
int returnCode = 0; int returnCode = 0; // Variable um den Rückgabewert an das Programmende zu liefern
while(true) { while(true) { // Endlosschleife, die durch Erfolg oder Fehler beendet wird
if(load(filePath, matrix, b, x)) { if(load(filePath, matrix, b, x)) { // Versucht die Daten zu laden
// Debug outputs
puts("Data successfully loaded\nMatrix A:");
printMatrix(matrix);
puts("Vector b:");
printVector(b);
puts("Vector x:");
printVector(x);
puts("Please enter the algorithm to use:\n\t0: Jacobi (default)\n\t1: Gauss-Seidel"); puts("Please enter the algorithm to use:\n\t0: Jacobi (default)\n\t1: Gauss-Seidel");
int algorithm; int algorithm; // int-Variable um Eingabewerte zwischenzuspeichern
while(true) { while(true) { // Endlosschleife, die durch erfolgreiche Eingabe oder Programmfehler beendet wird
algorithm = getchar(); algorithm = getchar(); // Nutzereingabe
if(algorithm == EOF) { if(algorithm == EOF) { // Bei der Eingabe ist ein Fehler aufgetreten
returnCode = 20;
goto end; goto end;
} }
if(algorithm == '\n' || algorithm == 0) { if(algorithm == '\n' || algorithm == 0) { // Wenn der Nutzer nichts eingegeben hat
puts("Defaulting to Jacobi"); puts("Defaulting to Jacobi");
algorithm = 0; algorithm = JACOBI; // Standardalgoritmus: JACOBI
break; break; // Verlassen der Schleife
} }
flushStdin(); flushStdin(); // Konsoleneingabe bereinigen
if(algorithm == '0' || algorithm == '1') { if(algorithm == '0' || algorithm == '1') { // Wenn die Eingabe gültig ist
algorithm -= '0'; algorithm -= '0'; // Algorithmusnummer wird bestimmt
break; break; // Verlassen der Schleife
} }
fputs("Please enter 0, 1 or leave empty to exit!\n", stderr); fputs("Please enter 0, 1 or leave empty to exit!\n", stderr); // Fehlermeldung
} }
puts("Please enter the precision to use:"); puts("Please enter the precision to use:");
double e; double e; // Variable für die Algorithmusgenauigkeit
int scan; int scan; // Variable zum Speichern des scanf Rückgabewerts
while(true) { while(true) {
scan = scanf("%lf", &e); scan = scanf("%lf", &e); // Eingabe eines doubles
if(scan == EOF) { if(scan == EOF) { // Fehler bei der Eingabe
returnCode = 20;
goto end; goto end;
} }
flushStdin(); flushStdin(); // Konsoleneingabe bereinigen
if(scan == 1) { if(scan == 1) { // Bei erfolgreicher Eingabe die Schleife verlassen
break; break;
} }
fputs("Invalid input - please enter a valid floating point number!\n", stderr); fputs("Invalid input - please enter a valid floating point number!\n", stderr); // Fehlermeldung
} }
Vector* result = solve(algorithm, matrix, b, x, e); Vector* result = solve(algorithm, matrix, b, x, e); // Ausführung des Algorithmus
if(result == NULL) {
fputs("Failed to run the algorithm!\n", stderr); if(result == NULL) { // Beim Auftritt eines Fehlers
returnCode = 100; puts("Given equation system doesn't converge!\nEnter 0 to repeat the program (default) or 1 to exit"); // Fehlermeldung und Auswahlmöglichkeiten
algorithm = getchar(); // Benutzereingabe
if(algorithm != '\n' && algorithm != 0) { // Wenn Eingabe nicht leer war
flushStdin(); // Konsoleneingabe bereinigen
if(algorithm == '1') { // Bei Auswahl der Beendigung Programm erfolgreich beenden
goto end;
}
}
} else { } else {
int input; puts("Solution found!\nEnter 0 to just print the solution (default) or 1 to print the whole sequence of iteration steps!"); // Auswahlmöglichkeiten
while(true) { algorithm = getchar(); // Benutzereingabe
puts("Choose what to output:\n\t0: Only the final result (default)\n\t1: All the iteration steps"); if(algorithm != '\n' && algorithm != 0) // Wenn Eingabe nicht leer
input = getchar(); flushStdin(); // Konsoleneingabe bereinigen
if(input == '\n') { if(algorithm == '1') { // Alle Schritte ausgeben
puts("Defaulting to final result"); int i = 0; // Zählervariable
input = 0; do { // Solange wie der aktuelle Vektor nicht leer ist und das Array nicht zu Ende ist
} else { printVector(&result[i]); // Vektor ausgeben
flushStdin(); free(result[i].data); // Speicher freigeben
} while(result[++i].n != 0 && i <= MAX_ITERATION_STEPS);
free(result); // Schließlich den Speicher des Arrays freigeben
} else {
int i = 0; // Zählervariable (erstes Element wird durch kopfgesteurte Schleife nicht überprüft)
while(result[++i].n != 0 && i < MAX_ITERATION_STEPS) { // Solange wie der aktuelle Vektor nicht leer ist und das Array nicht zu Ende ist
free(result[i - 1].data); // Speicher des vorherigen Vektors
} }
if(input == 0 || input == '\n' || input == '0') { printVector(&result[i-1]); // Ausgabe des letzten existierenden Vektors
puts("Showing final result:"); free(result[i-1].data); // Speicher der letzten existierenden Vektordaten wird freigegeben
int i = 0; free(result); // Vektoren werden freigegeben
while(result[++i].n != 0 && i < MAX_ITERATION_STEPS) }
free(result[i-1].data); break; // Hauptschleife verlassen
printVector(&result[i-1]);
free(result[i-1].data);
break;
}
if(input == '1') {
puts("Showing all iterations:");
for(int i = 0; i < MAX_ITERATION_STEPS; i++) {
printVector(&result[i]);
if(result[i].n == 0) {
break;
}
free(result[i].data);
}
break;
}
fputs("Please enter 0, 1 or leave empty!", stderr);
};
free(result);
} }
break; } else { // Datei konnte nicht geladen werden
} else { fputs("Failed to load data from file.\n", stderr);
fputs("Failed to load data from file.\nEnter new file path or leave empty to exit.\n", stderr);
int result = scanf("%" STR(MAX_FILE_PATH_LENGTH) "[^\n]", filePath);
if(result == EOF || result == 0 || filePath[0] == 0) {
goto end;
}
if(result != 1) {
fputs("Couldn't read file path - stopping\n", stderr);
returnCode = 1;
goto end;
}
flushStdin();
} }
puts("Enter file path or leave empty to exit");
int result = scanf(FILE_PATH_PATTERN, filePath); // Erneute Abfrage des Dateipfads
if(result == EOF || result == 0 || filePath[0] == 0) { // Wenn Eingabe leer ist
goto end;
}
if(result != 1) { // Wenn Fehler bei der Eingabe aufgetreten ist
fputs("Couldn't read file path - stopping\n", stderr);
returnCode = 1;
goto end;
}
flushStdin(); // Konsoleneingabe bereinigen
} }
end: end:
// Matrix- und Vektorspeicher freigeben
freeMatrix(matrix); freeMatrix(matrix);
freeVector(b); freeVector(b);
freeVector(x); freeVector(x);
printf("\nReturning with code %i\n", returnCode); printf("\nReturning with code %i\n", returnCode); // Den Rückgabewert anzeigen
return returnCode; return returnCode;
} }
bool load(const char* filename, Matrix* matrix, Vector* b, Vector* x) { bool load(const char* filename, Matrix* matrix, Vector* b, Vector* x) {
FILE* file = fopen(filename, "r"); FILE* file = fopen(filename, "r"); // Die gegebene Datei zum Lesen öffnen
if(file == NULL) { if(file == NULL) { // Beim Auftritt eines Fehlers -> Laden ist fehlgeschlagen
fprintf(stderr, "Failed to open file \"%s\"\n", filename); fprintf(stderr, "Failed to open file \"%s\"\n", filename);
return false; return false;
} else { } else {
// Erste Zeile der Datei wird mit Maximalgröße gelesen
double* firstLineBuffer = malloc(sizeof(double) * (MAX_MATRIX_IN_FILE_SIZE)); double* firstLineBuffer = malloc(sizeof(double) * (MAX_MATRIX_IN_FILE_SIZE));
int colsInFile = readMatrixLine(file, firstLineBuffer, MAX_MATRIX_IN_FILE_SIZE); // Zeile lesen und Anzahl der gelesenen Werte speichern
int colsInFile = readMatrixLine(file, firstLineBuffer, MAX_MATRIX_IN_FILE_SIZE); if(colsInFile == -1) { // Es konnte kein double gelesen werden
if(colsInFile == -1) {
fputs("Unexpected input on line 0", stderr); fputs("Unexpected input on line 0", stderr);
free(firstLineBuffer); // Speicher freigeben
free(firstLineBuffer); goto failure; // Zum Fehlerlabel springen
goto failure; } else if(colsInFile == -2) { // Die Zeile war länger als die Maximalgröße erlaubt
} else if(colsInFile == -2) {
fprintf(stderr, "Exceeded maximum matrix size of %i\n", MAX_MATRIX_SIZE); fprintf(stderr, "Exceeded maximum matrix size of %i\n", MAX_MATRIX_SIZE);
free(firstLineBuffer); free(firstLineBuffer);
goto failure; goto failure; // Zum Fehlerlabel springen
} else { } else { // Erfolgreich gelesen
// success int cols = colsInFile - 1; // Tatsächliche Größe der Matrix/Vektoren ist um eins kleiner, da zumindest b mit eingelesen wurde
int cols = colsInFile - 1; initVector(b, cols); // Vektoren werden initialisiert
initVector(b, cols);
initVector(x, cols); initVector(x, cols);
b->data[0] = firstLineBuffer[cols]; b->data[0] = firstLineBuffer[cols]; // b0 enthält den letzten Eintrag der ersten Zeile
createMatrixRows(matrix, cols); createMatrixRows(matrix, cols); // Matrix wird mit cols Zeilen angelegt (nur das Haupt-Array - die Einträge sind nicht initialisiert)
matrix->data[0] = firstLineBuffer; matrix->data[0] = firstLineBuffer; // Erste Matrix-Zeile entspricht erster eingelesener Zeile. b-Wert ist irrelevant da durch Matrix-Größe die erste Zeile vorher endet
int colsInLine; int colsInLine; // Variable zum Speichern der pro Zeile eingelesenen Einträge
for(int i = 1; i < cols; i++) { for(int i = 1; i < cols; i++) { // Einlesen von cols Zeilen
matrix->data[i] = malloc(sizeof(double) * (colsInFile)); matrix->data[i] = malloc(sizeof(double) * (colsInFile)); // Matrix Zeile wird initialisiert
colsInLine = readMatrixLine(file, matrix->data[i], colsInFile); colsInLine = readMatrixLine(file, matrix->data[i], colsInFile); // Nächste Zeile in Matrix einlesen
if(colsInLine < 0) { if(colsInLine < 0) { // Wenn ein Fehler beim Einlesen aufetreten ist
if(i == cols - 1) { if(i == cols - 1) { // Wenn die vermeintlich letzte Zeile erreicht ist und ein Fehler auftritt, dann wird davon ausgegangen, dass x-Werte übergeben wurden
puts("Optional parameters are being used"); puts("Optional parameters are being used");
// Matrix is one smaller than assumed cols--; // Die tatsächliche Matrixgröße ist also eins geringer
cols--; b->n--; // Ebenso für die Vektoren
b->n--;
x->n--; x->n--;
matrix->n--; matrix->n--;
free(matrix->data[i]); free(matrix->data[i]); // der bereits allokierte Speicher kann wieder freigegeben werden
x->data[0] = 0.4; // Die letzte Spalte (derzeit b) ist eigentlich x, die Zeiger auf die Daten können also getauscht werden
{
double* temp = x->data;
x->data = b->data;
b->data = temp;
}
// Copy b to x // b wird nun aus der zugehörigen Spalte in der Matrix ausgelesen
memcpy(x->data, b->data, b->n * sizeof(double));
// extract b
for(int j = 0; j < cols; j++) { for(int j = 0; j < cols; j++) {
b->data[j] = matrix->data[j][cols]; b->data[j] = matrix->data[j][cols];
} }
goto success; goto success; // Ausführung erfolgreich beendet
} else { } else { // Unerwarteter Fehler ist aufgetreten
fprintf(stderr, "Line %i contains illegal formatting - please fix!\n", i + 1); fprintf(stderr, "Line %i contains illegal formatting - please fix!\n", i + 1); // Fehlermeldung
goto failure; goto failure; // Abbruch
} }
} else if(colsInLine != colsInFile) { } else if(colsInLine != colsInFile) { // Die Anzahl der gelesenen Spalten stimmt nicht mit der Erwartung überein
fprintf(stderr, "Illegal line length found in line %i\n", i + 1); fprintf(stderr, "Illegal line length found in line %i\n", i + 1); // Fehlermeldung
goto failure; goto failure; // Abbruch
} else { } else { // Erfolgreiches Einlesen
b->data[i] = matrix->data[i][cols]; b->data[i] = matrix->data[i][cols]; // b-Wert auslesen
} }
} } // Ende Schleife
// successful but with no optional parameter
// initialize vector x with zeros // Da an dieser Stelle keine x-Werte gelesen wurden, wird x mit Nullen initialisiert
memset(x->data, 0, cols * sizeof(double)); memset(x->data, 0, cols * sizeof(double));
} }
} }
success: success: // Erfolgslabel
fclose(file); fclose(file); // Die Datei wird geschlossen
return true; return true;
failure: failure: // Fehlerlabel
fclose(file); fclose(file); // Die Datei wird geschlossen
return false; return false;
} }
int readMatrixLine(FILE* file, double* matrixLine, int maxCols) { int readMatrixLine(FILE* file, double* matrixLine, int maxCols) {
char nextChar = 0; char nextChar = 0; // Variable für den nächsten zu verarbeitenden char
int col = 0; int col = 0; // Die Anzahl gelesener Werte
double buffer;
while(true) { do { // Solange wie Kommas als Trennzeichen gelesen werden
if(fscanf(file, "%lf", &buffer) != 1) { if(fscanf(file, "%lf", &matrixLine[col]) != 1) { // In das Array wird ein double-Wert eingelesen
return -1; return -1; // Es konnte kein double gelesen werden
} }
matrixLine[col] = buffer;
col++; col++; // Gelesene Werte erhöhen
if(col > maxCols) { if(col > maxCols) { // Wenn zu viele Werte gelesen wurden
return -2; return -2; // Fehlerrückgabe
} }
nextChar = fgetc(file); nextChar = fgetc(file); // nächstes Trennzeichen einlesen
if(nextChar == EOF || nextChar == '\n') break; } while (nextChar == ',');
} return col; // Anzahl gelesener Werte zurückgeben
return col;
} }
void flushStdin(void) { void flushStdin(void) {
int c; int c; // Buffer-Variable
while((c = getchar()) != '\n' && c != EOF && c != 0); while((c = getchar()) != '\n' && c != EOF && c != 0); // Solange das Konsoleneingabe-Ende noch nicht erreicht ist werden einzelne chars eingelesen
} }
Vector* solve(Method method, Matrix* A, Vector* b, Vector* x, double e) { Vector* solve(Method method, Matrix* A, Vector* b, Vector* x, double e) {
if(method == JACOBI) { Vector* vectors = malloc(sizeof(Vector) * (MAX_ITERATION_STEPS + 1)); // Historie der Iterationsschritte/Rückgabe-Array
return solveJacobi(A, b, x, e);
} else {
return solveGaussSeidel(A, b, x, e);
}
}
Vector* solveJacobi(Matrix* A, Vector* b, Vector* x, double e) { initVector(&vectors[0], b->n); // Erster Vektor wird initialisiert...
Vector* history = malloc(sizeof(Vector) * (MAX_ITERATION_STEPS + 1)); memcpy(vectors[0].data, x->data, b->n * sizeof(double)); // ...und mit den Werten aus x gefüllt
initVector(history, x->n); int vectorCount = 1; // Länge existierender Vektoren in vectors
memcpy(history[0].data, b->data, b->n * sizeof(double)); double temp; // Temporäre Variable zur Berechnung
double delta; double delta; // Abweichung der Iterationsschritte - zur Genauigkeitsberechnung
int i, j, steps = 1;
double value;
double* data;
do { if (method == JACOBI){
delta = 0.; do { // Solange wie die Abweichung größer als die Genauigkeit ist
delta = 0.0;
initVector(&vectors[vectorCount], b->n); // Vektor an aktueller Position initialisieren
initVector(&history[steps], x->n); for (int i = 0; i < b->n; i++) { // Iteration über alle Zeilen
data = history[steps].data; temp = 0.0; // temp wird zur Summenbildung verwendet
for (int j = 0; j < b->n; j++) { // für alle Spalten, die nicht auf der Diagonale liegen
for(i = 0; i < x->n; i++) { if (j != i){
value = b->data[i]; temp = temp + A->data[i][j] * vectors[vectorCount - 1].data[j];
for(j = 0; j < x->n; j++) { }
if(i != j) }
value -= history[steps-1].data[i] * A->data[i][j]; vectors[vectorCount].data[i] = (b->data[i] - temp) / A->data[i][i]; // Berechneten Wert in Historie aufnehmen
delta = fmax(fabs(vectors[vectorCount].data[i] - vectors[vectorCount - 1].data[i]), delta); // Berechnung der maximalen Abweichung durchführen
} }
data[i] = value / A->data[i][i]; vectorCount++; // Größe der Historie erhöhen
if (vectorCount >= MAX_ITERATION_STEPS) // Wenn zu viele Iterationsschritte durchgeführt wurden
goto fail; // Fehlerbehandlung
} while (delta > e);
} else { // GAUSS-SEIDEL
do { // Solange wie die Abweichung größer als die Genauigkeit ist
delta = 0.0;
initVector(&vectors[vectorCount], b->n); // Vektor an aktueller Position initialisieren
memcpy(vectors[vectorCount].data, vectors[vectorCount - 1].data, b->n * sizeof(double)); // Werte des vorherigen Schrittes in den neuen Schritt kopieren
delta = fmax(delta, fabs(data[i] - history[steps - 1].data[i])); for (int i = 0; i < b->n; i++) { // Iteration über alle Zeilen
} temp = 0.0; // temp wird zur Summenbildung verwendet
for (int j = 0; j < b->n; j++) { // für alle Spalten, die nicht auf der Diagonale liegen
steps++; if (j != i){
} while(delta > e && steps < MAX_ITERATION_STEPS); temp = temp + A->data[i][j] * vectors[vectorCount].data[j];
}
if(steps < MAX_ITERATION_STEPS) { }
history[steps].n = 0; vectors[vectorCount].data[i] = (b->data[i] - temp) / A->data[i][i]; // Berechneten Wert in Historie aufnehmen
delta = fmax(fabs(vectors[vectorCount].data[i] - vectors[vectorCount - 1].data[i]), delta); // Berechnung der maximalen Abweichung durchführen
}
vectorCount++; // Größe der Historie erhöhen
if (vectorCount >= MAX_ITERATION_STEPS) // Wenn zu viele Iterationsschritte durchgeführt wurden
goto fail; // Fehlerbehandlung
} while(delta > e);
} }
return history; vectors[vectorCount].n = 0; // Abschließenden Vektor auf Größe 0 setzen
} return vectors;
Vector* solveGaussSeidel(Matrix* A, Vector* b, Vector* x, double e) { fail: // Fehlerlabel
Vector* history = malloc(sizeof(Vector) * (MAX_ITERATION_STEPS + 1)); for (int i = 0; i < vectorCount; i++) { // Allokierten Daten-Speicher freigeben
free(vectors[i].data);
initVector(history, x->n);
memcpy(history[0].data, b->data, x->n * sizeof(double));
double delta;
int i, k, steps = 1;
double* data;
double value;
do {
delta = 0.;
initVector(&history[steps], x->n);
data = history[steps].data;
for(k = 0; k < x->n; k++) {
value = b->data[k];
for(i = 0; i < k; i++) {
value -= A->data[k][i] * data[i];
}
for(i = k + 1; i < x->n; i++) {
value -= A->data[k][i] * history[steps - 1].data[i];
}
data[k] = value / A->data[k][k];
delta = fmax(delta, fabs(data[k] - history[steps - 1].data[k]));
}
steps++;
} while(delta > e && steps < MAX_ITERATION_STEPS);
if(steps < MAX_ITERATION_STEPS) {
history[steps].n = 0;
} }
return history; free(vectors); // Vektoren-Array freigeben
return NULL;
} }
inline Matrix* createMatrix(void) { inline Matrix* createMatrix(void) {
@@ -389,17 +446,17 @@ inline void createMatrixRows(Matrix* matrix, int rows) {
} }
inline void freeMatrix(Matrix* matrix) { inline void freeMatrix(Matrix* matrix) {
for(int i = 0; i < matrix->n; i++) { for(int i = 0; i < matrix->n; i++) { // Gibt die Zeilen frei
free(matrix->data[i]); free(matrix->data[i]);
} }
free(matrix->data); free(matrix->data); // Gibt das Zeilen-Array frei
free(matrix); free(matrix); // Gibt das Matrix-Object frei
} }
void printMatrix(Matrix* matrix) { void printMatrix(Matrix* matrix) {
for(int i = 0; i < matrix->n; i++) { for(int i = 0; i < matrix->n; i++) {
for(int j = 0; j < matrix->n; j++) { for(int j = 0; j < matrix->n; j++) {
printf("%le, ", matrix->data[i][j]); printf("%lf, ", matrix->data[i][j]);
} }
puts(""); puts("");
} }
@@ -423,7 +480,7 @@ inline void freeVector(Vector* vector) {
void printVector(Vector* vector) { void printVector(Vector* vector) {
for(int i = 0; i < vector->n; i++) { for(int i = 0; i < vector->n; i++) {
printf("%le, ", vector->data[i]); printf("%lf ", vector->data[i]);
} }
puts(""); puts("");
} }

3
test-data/3.csv Normal file
View File

@@ -0,0 +1,3 @@
4,2,1,7,100
2,4,1,7,200
1,1,3,5,300
1 4 2 1 7 100
2 2 4 1 7 200
3 1 1 3 5 300