Integral mit Trapezregel berechnen in C

Gerowia

Grünschnabel
Hallo :)
Ich schreibe für die Uni ein C-Programm, welches ein bestimmtes Integral mit der Trapezformel ( I ≈ In = h /2 (f(x0) +2 f(x1) +···+2 f(xn−1) + f(xn)) mit h = (b−a)/n berechnen soll. Die Integrationsgrenzen a und b werden vom Benutzer eingegeben, n ist festgelegt als 5 und wird solange um 5 erhöht, bis I I(n−5) −In| / | In | < 10e−6 gilt oder n = 100 ist.

Ich habe bisher folgendes:
C:
#include<stdio.h>
#include<math.h>



double f(double x){
    double y;
    if(x>0){
        y=log(x)/x;
    }
    return y;
}

double trapez(double a,double b, int n){
    double I,h, rechnung;
    int i=1;
    double z[5000];
  
    h= (b-a)/n;
    rechnung=0;
  
  
        for(i=1;i=n-1;i++){
      
            rechnung=rechnung+2*(f(a+i*h));
        }
  
    I= (h/2)*(f(a)+rechnung+f(b));
    z[n]=I;

  
    return z[n];
}


int main(void){
    double a,b,e,z[5000];
    int n=5;
    printf("Bitte geben Sie a und b ein: ");
    scanf("%lf %lf", &a,&b);
  
    do{
    e=trapez(a,b,n);
    printf("Index n= %d", n);
    printf("Naeherung I_n= %lf ",e);
    n=n+5;
    }while(n<=100||(fabs(z[n-5]-z[n])/fabs(z[n]))<10e-6);
  
    return 0;
  
}

Das Programm kompiliert (Ich benutze DevC++) , dann sollen a und b eingegeben werden und nach der Eingabe stürzt es einfach ab...

Sieht jemand meinen Fehler? Ich komme nicht darauf. :unsure:
 
Zuletzt bearbeitet:

ComFreek

Mod | @comfreek
Moderator
Du könntest einen Debugger einsetzen. DevC++ besitzt sogar gdb als integrierten Debugger, aber du solltest wirklich deine Entwicklungsumgebung ändern, denn DevC++ wurde das letzte Mal 2012 aktualisiert.
 

cwriter

Erfahrenes Mitglied
Comfreek's Antwort ist natürlich bei diesen Dingen immer die Beste.

Ich sehe im Code aber auch ohne Debugger ein paar Probleme:
Du liest uninitialisierte Werte in der main-Funktion, nämlich z[n] und z[n-5]. Diese werden nämlich nie gesetzt. Das sorgt dafür, dass der Code nicht funktional ist, aber der Grund des Absturzes liegt nicht dort.
Dann schauen wir uns mal trapez() an.

Hier haben wir diesen loop:
C:
for(i = 1; i = n-1; ++i)
{
  rechnung=rechnung+2*(f(a+i*h));
}
Siehst du das Problem?
Dieser Loop wird ewig laufen. Der Loop-Body verändert keine der Iterationsvariablen {i, n}, daher können wir uns den wegdenken.
Wir haben also:
i = 1;
condcheck:
cond = (i = n -1); // cond == n-1
if(!cond) goto end;

i = i + 1;
goto condcheck;
end:

Wie du siehst, wird der Loop mit n != 1 ewig laufen, daher das, was dir wie ein Absturz vorkommt.
Daher ist es auch immer sehr wichtig, dass du klar definierst, was ein Absturz ist. Wenn das Programm einfach nicht mehr reagiert (Windows: "Programm reagiert nicht mehr"), dann ist es oft einfach eine Endlosschleife, besonders, wenn es ein paar Sekunden geht, bis das Fenster erscheint. Unter Linux ist es noch einfacher: Abstürze geben immer eine Fehlermeldung aus (z.B. SIGSEGV), Endlosloops laufen einfach.
Korrigiere die Loop-Condition und der "Absturz" sollte weg sein. Allerdings bleibt das Problem, dass das Programm nicht funktioniert, da du double z in der main-Funktion nie setzt.

Gruss
cwriter
 
Zuletzt bearbeitet:

Gerowia

Grünschnabel
Danke für die Antwort schon mal :) Ja mit Absturz meinte ich, dass das Programm nicht mehr reagiert.

Ich habe die Grenze der for-Schleife überarbeitet:
C:
    for(i=0;i<=n;i++){
        
            rechnung=rechnung+2*(f(a+i*h));
        }
das müsste doch klappen, oder?

Allerdings dachte ich, dass z[n] dadurch in der main gesetzt wird, dass es der Rückgabewert der Funktion trapez ist und in der do-while-Schleife der main Funktion ja aufgerufen wird.
 
Zuletzt bearbeitet:

cwriter

Erfahrenes Mitglied
Aber als Abbruchbedingung gilt ja, dass i=n-1 sein soll und da i bei jedem Durchlauf um 1 erhöht wird, müsste es das doch auch werden oder?
Oh, das ist ein Klassiker:

= und == sind nicht dasselbe.
(a = b) evaluiert zu typeof(a), (a == b) evaluiert zu bool.
Verwirrenderweise ist = in C das ':=' in der Mathematik (definiere als), während == aus C das eigentliche '=' der Mathematik ist.


Du scheinst einen Verständnisfehler bei for zu haben: Die for-Bedingung ist nicht die Abbruchbedingung, sondern die Loopbedingung. Wenn du bei
Code:
i == n - 1
abbrechen willst, müsstest du also
Code:
 i != n-1;
schreiben. Oder, falls es so intuitiver vorstellbar ist:
C:
for(init;cond;each) body

//ist dasselbe* wie
init;
while(cond)
{
    body;
    each;
}
//*: Ausnahmen gibt es beim Keyword "continue", wo immer "each" noch ausgeführt wird.


Allerdings dachte ich, dass z[n] dadurch in der main gesetzt wird, dass es der Rückgabewert der Funktion trapez ist und in der do-while-Schleife der main Funktion ja aufgerufen wird.
Das lässt sich mit "Programming by Types" recht schnell feststellen:
trapez() hat Rückgabewert double. Woher soll der Compiler aus diesem Typ wissen, dass der Wert in deinen Array kommt? Du speicherst den Wert ja selbst in e und nicht im Array.
Der Array scheint mir übrigens nicht nötig. Falls du ihn als Stütze dennoch so haben willst, musst du Du musst ein z[n] = e; einfügen. Allerdings müsstest du dann noch einen Initialen Wert in z[0] schreiben... Ich denke wirklich, dass der Array es eher schwieriger macht...

EDIT: Formel nachgeschlagen und ja, du solltest die Werte in einem Array speichern, sorry. Der Rest sollte aber noch stimmen ;)


Gruss
cwriter
 
Zuletzt bearbeitet:

Gerowia

Grünschnabel
Ja gut, das mit der for-Schleife habe ich zwischenzeitlich(hoffentlich) verstanden und abgeändert in :
C:
    for(i=0;i<=n;i++){
        
            rechnung=rechnung+2*(f(a+i*h));
        }
(hatte es oben editiert, aber das hatte sich scheinbar mit deiner Antwort überschnitten.)

Zu dem Array: also ich habe deshalb das Array gewählt, weil das Ergebnis I abhängig von n ist, n soll solange um 5 erhöht werden , bis n entweder 100 ist oder der Wert von I wenn n=n-5 ist - I bei n / I bei n <10^-6 ist. Hierbei soll für jedes n I berechnet werden und jeweils n und I ausgegeben werden.

Also dachte ich,dass durch das Array z[n]=I der Wert I halt in Abhängigkeit zu n gespeichert wird und dann auch so an die main übergeben wird. Mir fiel keine andere Möglichkeit ein, das hinzubekommen.
Diese Grenze zu setzen war auch bisher mein Hauptproblem bei diesem Programm.
 

cwriter

Erfahrenes Mitglied
Also dachte ich,dass durch das Array z[n]=I der Wert I halt in Abhängigkeit zu n gespeichert wird und dann auch so an die main übergeben wird. Mir fiel keine andere Möglichkeit ein, das hinzubekommen.
Diese Grenze zu setzen war auch bisher mein Hauptproblem bei diesem Programm.
Ok, nach genauerer Analyse: Dein do-while hat einen Bug. Die Condition ist true, n <= 100 ist oder die Differenz zu gross; also muss beides nicht erfüllt sein, um abzubrechen (|| -> &&). Oh, das '<' sollte da doch ein '>' sein, oder?
Falls du z teilen willst, muss du es einmal global definieren (vor trapez()) und die anderen Definitionen löschen. Dann kannst du aus beiden Funktionen darauf zugreifen. Oder aber, du übergibst einen Pointer darauf an trapez(), aber das ist ein bisschen komplizierter für Anfänger.

Zum anderen: Siehe edit ;)