Ihr Array belegt etwa 8 GB Speicher (1.000 x 1.000.000 x Größe von (doppelten) Bytes). Das könnte ein Faktor für Ihr Problem sein. Es ist eine globale Variable und keine Stapelvariable. Sie können also in Ordnung sein, aber Sie stoßen hier an Grenzen.
Das Schreiben von so vielen Daten in eine Datei wird eine Weile dauern.
Sie überprüfen nicht, ob die Datei erfolgreich geöffnet wurde, was ebenfalls eine Fehlerquelle sein könnte (wenn sie fehlgeschlagen ist, ist ein Segmentierungsfehler sehr wahrscheinlich).
Sie sollten wirklich einige benannte Konstanten für 1.000 und 1.000.000 einführen; was repräsentieren sie?
Sie sollten auch eine Funktion schreiben, um die Berechnung durchzuführen; Sie könnten eine inline
-Funktion in C99 oder höher (oder C++) verwenden. Die Wiederholung im Code ist unerträglich anzusehen.
Sie sollten auch C99-Notation für main()
verwenden, mit dem expliziten Rückgabetyp (und vorzugsweise void
für die Argumentliste, wenn Sie nicht argc
oder argv
verwenden):
int main(void)
Aus reiner Neugier Ich habe eine Kopie Ihres Codes erstellt, alle Vorkommen von 1000 in ROWS geändert, alle Vorkommen von 1000000 in COLS und dann enum { ROWS = 1000, COLS = 10000 };
erstellt (wodurch die Größe des Problems um den Faktor 100 reduziert wurde).Ich habe ein paar kleinere Änderungen vorgenommen, so dass es unter meinen bevorzugten Kompilierungsoptionen sauber kompiliert werden würde (nichts Ernstes: static
vor den Funktionen und das Haupt-Array; file
wird zu einem lokalen main
; Fehler überprüfen Sie die fopen()
, etc.).
Ich erstellte dann eine zweite Kopie und erstellte eine Inline-Funktion, um die wiederholte Berechnung zu tun (und eine zweite, um tiefgestellte Berechnungen zu tun). Dies bedeutet, dass der monströse Ausdruck nur einmal ausgeschrieben wird - was sehr wünschenswert ist, um Konsistenz zu gewährleisten.
#include <stdio.h>
#define lambda 2.0
#define g 1.0
#define F0 1.0
#define h 0.1
#define e 0.00001
enum { ROWS = 1000, COLS = 10000 };
static double F[ROWS][COLS];
static void Inicio(double D[ROWS][COLS])
{
for (int i = 399; i < 600; i++) // Magic numbers!!
D[i][0] = F0;
}
enum { R = ROWS - 1 };
static inline int ko(int k, int n)
{
int rv = k + n;
if (rv >= R)
rv -= R;
else if (rv < 0)
rv += R;
return(rv);
}
static inline void calculate_value(int i, int k, double A[ROWS][COLS])
{
int ks2 = ko(k, -2);
int ks1 = ko(k, -1);
int kp1 = ko(k, +1);
int kp2 = ko(k, +2);
A[k][i] = A[k][i-1]
+ e/(h*h*h*h) * g*g * (A[kp2][i-1] - 4.0*A[kp1][i-1] + 6.0*A[k][i-1] - 4.0*A[ks1][i-1] + A[ks2][i-1])
+ 2.0*g*e/(h*h) * (A[kp1][i-1] - 2*A[k][i-1] + A[ks1][i-1])
+ e * A[k][i-1] * (lambda - A[k][i-1] * A[k][i-1]);
}
static void Iteration(double A[ROWS][COLS])
{
for (int i = 1; i < COLS; i++)
{
for (int k = 0; k < R; k++)
calculate_value(i, k, A);
A[999][i] = A[0][i];
}
}
int main(void)
{
FILE *file = fopen("P2.txt","wt");
if (file == 0)
return(1);
Inicio(F);
Iteration(F);
for (int i = 0; i < COLS; i++)
{
for (int j = 0; j < ROWS; j++)
{
fprintf(file,"%lf \t %.4f \t %lf\n", 1.0*j/10.0, 1.0*i, F[j][i]);
}
}
fclose(file);
return(0);
}
Dieses Programm schreibt P2.txt
statt P1.txt
. Ich habe beide Programme ausgeführt und die Ausgabedateien verglichen. die Ausgabe war identisch. Wenn ich die Programme auf einem meist ungenutzten Rechner (MacBook Pro, 2,3 GHz Intel Core i7, 16 GiB 1333 MHz RAM, Mac OS X 10.7.5, GCC 4.7.1) laufen ließ, bekam ich ein vernünftiges, aber nicht ganz konsistentes Timing:
Original Modified
6.334s 6.367s
6.241s 6.231s
6.315s 10.778s
6.378s 6.320s
6.388s 6.293s
6.285s 6.268s
6.387s 10.954s
6.377s 6.227s
8.888s 6.347s
6.304s 6.286s
6.258s 10.302s
6.975s 6.260s
6.663s 6.847s
6.359s 6.313s
6.344s 6.335s
7.762s 6.533s
6.310s 9.418s
8.972s 6.370s
6.383s 6.357s
Die meiste Zeit wird jedoch für die Datenträger-E/A ausgegeben. Ich reduzierte die Disk-I/O nur die letzte Zeile von Daten, so dass die äußere I/O for
Schleife wurde:
for (int i = COLS - 1; i < COLS; i++)
die Zeiten wurden erheblich reduziert und sehr viel konsequenter:
Original Modified
0.168s 0.165s
0.145s 0.165s
0.165s 0.166s
0.164s 0.163s
0.151s 0.151s
0.148s 0.153s
0.152s 0.171s
0.165s 0.165s
0.173s 0.176s
0.171s 0.165s
0.151s 0.169s
Die Vereinfachung im Code von dem schrecklichen Ausdruck, der nur einmal ausgeschrieben wurde, ist sehr nützlich, scheint mir. Ich hätte dieses Programm sicherlich viel lieber beibehalten müssen als das Original.
An welchem Punkt tritt der Segfault auf? –
^Verwenden Sie Valgrind, um die Zeilennummer zu erhalten, an der der Segfault auftritt. Es ist in der Regel ziemlich offensichtlich, wenn Sie es auf eine Zeile eingegrenzt haben - wenn nicht, geben Sie an, welche Zeile es ist und wir können Ihnen helfen. –
Ihren Code zu sehen, zuerst Ihr Compiler muss Segmentierung Fehler gegangen sein ... – perilbrain