Compare commits
7 Commits
backup-fin
...
final
| Author | SHA1 | Date | |
|---|---|---|---|
| 2c7511da52 | |||
| 50081506f3 | |||
| ebaf6a77f2 | |||
| bfa5fb3ce8 | |||
| 20e98a1105 | |||
| 8bd26b9a9c | |||
| 077a54af18 |
BIN
Simon Bestler und Johannes Freitag.zip
Normal file
BIN
Simon Bestler und Johannes Freitag.zip
Normal file
Binary file not shown.
428
main.c
428
main.c
@@ -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,268 +11,426 @@
|
|||||||
#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);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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(argc >= 2) { // Wenn Argumente übergeben wurden
|
||||||
strncpy(filePath, argv[1], MAX_FILE_PATH_LENGTH);
|
strncpy(filePath, argv[1], MAX_FILE_PATH_LENGTH); // Das erste Argument wird (auf MAX_FILE_PATH_LENGTH gekürzt) in filePath kopiert
|
||||||
} else {
|
} 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(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 == '0' || algorithm == '1') {
|
if(algorithm == '\n' || algorithm == 0) { // Wenn der Nutzer nichts eingegeben hat
|
||||||
algorithm -= '0';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if(algorithm == '\n' || algorithm == 0) {
|
|
||||||
puts("Defaulting to Jacobi");
|
puts("Defaulting to Jacobi");
|
||||||
algorithm = 0;
|
algorithm = JACOBI; // Standardalgoritmus: JACOBI
|
||||||
break;
|
break; // Verlassen der Schleife
|
||||||
}
|
}
|
||||||
fputs("Please enter 0, 1 or leave empty to exit!\n", stderr);
|
flushStdin(); // Konsoleneingabe bereinigen
|
||||||
|
if(algorithm == '0' || algorithm == '1') { // Wenn die Eingabe gültig ist
|
||||||
|
algorithm -= '0'; // Algorithmusnummer wird bestimmt
|
||||||
|
break; // Verlassen der Schleife
|
||||||
|
}
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
if(scan == 1) {
|
flushStdin(); // Konsoleneingabe bereinigen
|
||||||
|
if(scan == 1) { // Bei erfolgreicher Eingabe die Schleife verlassen
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
flushStdin();
|
fputs("Invalid input - please enter a valid floating point number!\n", stderr); // Fehlermeldung
|
||||||
fputs("Invalid input - please enter a valid floating point number!\n", stderr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector* result = solve(algorithm, matrix, b, x, e);
|
Vector* result = solve(algorithm, matrix, b, x, e); // Ausführung des Algorithmus
|
||||||
free(result);
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
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 == NULL) { // Beim Auftritt eines Fehlers
|
||||||
if(result == EOF || result == 0 || filePath[0] == 0) {
|
puts("Given equation system doesn't converge!\nEnter 0 to repeat the program (default) or 1 to exit"); // Fehlermeldung und Auswahlmöglichkeiten
|
||||||
goto end;
|
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 {
|
||||||
|
puts("Solution found!\nEnter 0 to just print the solution (default) or 1 to print the whole sequence of iteration steps!"); // Auswahlmöglichkeiten
|
||||||
|
algorithm = getchar(); // Benutzereingabe
|
||||||
|
if(algorithm != '\n' && algorithm != 0) // Wenn Eingabe nicht leer
|
||||||
|
flushStdin(); // Konsoleneingabe bereinigen
|
||||||
|
if(algorithm == '1') { // Alle Schritte ausgeben
|
||||||
|
int i = 0; // Zählervariable
|
||||||
|
do { // Solange wie der aktuelle Vektor nicht leer ist und das Array nicht zu Ende ist
|
||||||
|
printVector(&result[i]); // Vektor ausgeben
|
||||||
|
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
|
||||||
|
}
|
||||||
|
printVector(&result[i-1]); // Ausgabe des letzten existierenden Vektors
|
||||||
|
free(result[i-1].data); // Speicher der letzten existierenden Vektordaten wird freigegeben
|
||||||
|
free(result); // Vektoren werden freigegeben
|
||||||
|
}
|
||||||
|
break; // Hauptschleife verlassen
|
||||||
}
|
}
|
||||||
if(result != 1) {
|
} else { // Datei konnte nicht geladen werden
|
||||||
fputs("Couldn't read file path - stopping\n", stderr);
|
fputs("Failed to load data from file.\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) {
|
||||||
Vector* vectors = malloc(sizeof(Vector) * (MAX_ITERATION_STEPS + 1));
|
Vector* vectors = malloc(sizeof(Vector) * (MAX_ITERATION_STEPS + 1)); // Historie der Iterationsschritte/Rückgabe-Array
|
||||||
|
|
||||||
// MAX_ITERATION_STEPS enthält die maximal zulässige Anzahl an Iterationsschritten (100)
|
initVector(&vectors[0], b->n); // Erster Vektor wird initialisiert...
|
||||||
// Die einzelnen Vektoren müssen noch mit initVector initialisiert werden
|
memcpy(vectors[0].data, x->data, b->n * sizeof(double)); // ...und mit den Werten aus x gefüllt
|
||||||
|
|
||||||
|
int vectorCount = 1; // Länge existierender Vektoren in vectors
|
||||||
|
double temp; // Temporäre Variable zur Berechnung
|
||||||
|
double delta; // Abweichung der Iterationsschritte - zur Genauigkeitsberechnung
|
||||||
|
|
||||||
// HIER kommt der Code hin ;)
|
if (method == JACOBI){
|
||||||
|
do { // Solange wie die Abweichung größer als die Genauigkeit ist
|
||||||
|
delta = 0.0;
|
||||||
|
initVector(&vectors[vectorCount], b->n); // Vektor an aktueller Position initialisieren
|
||||||
|
|
||||||
// on success
|
for (int i = 0; i < b->n; i++) { // Iteration über alle Zeilen
|
||||||
// Sei x die Anzahl der durchgeführten Iterationschritte. Dann setzt vectors[x+1].n = 0. Damit weiß das folgende Programm wie viele Schritte getätigt wurden.
|
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
|
||||||
|
if (j != i){
|
||||||
|
temp = temp + A->data[i][j] * vectors[vectorCount - 1].data[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
|
||||||
|
}
|
||||||
|
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
|
||||||
|
|
||||||
|
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
|
||||||
|
if (j != i){
|
||||||
|
temp = temp + A->data[i][j] * vectors[vectorCount].data[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
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
vectors[vectorCount].n = 0; // Abschließenden Vektor auf Größe 0 setzen
|
||||||
return vectors;
|
return vectors;
|
||||||
|
|
||||||
// on failure
|
fail: // Fehlerlabel
|
||||||
free(vectors);
|
for (int i = 0; i < vectorCount; i++) { // Allokierten Daten-Speicher freigeben
|
||||||
|
free(vectors[i].data);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(vectors); // Vektoren-Array freigeben
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -282,11 +446,11 @@ 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) {
|
||||||
@@ -316,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("%lf, ", vector->data[i]);
|
printf("%lf ", vector->data[i]);
|
||||||
}
|
}
|
||||||
puts("");
|
puts("");
|
||||||
}
|
}
|
||||||
|
|||||||
3
test-data/3.csv
Normal file
3
test-data/3.csv
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
4,2,1,7,100
|
||||||
|
2,4,1,7,200
|
||||||
|
1,1,3,5,300
|
||||||
|
Reference in New Issue
Block a user