double integrate(function f, double a, double b, double epsilon, int rdepth) { /* Berechnet die erste Naeherung nach Simpson fuer das Intervall [a,b] */ double h = b - a; double mid = 0.5 * (a + b); double fa = f.func(a, f.args); double fmid = f.func(mid, f.args); double fb = f.func(b, f.args); double simp = (fa + 4*fmid + fb) * h / 6; /* Leitet die Rekursion ein. Dabei werden alle schon berechneten Funktions- * werte weitergegeben, damit die Anzahl der Funktionsaufrufe minimiert wird. * Es wird auch der aktuelle Wert des Integrals ueberreicht, damit verglichen * werden kann, welchen Einfluss die Verfeinerung auf das Ergebnis hat */ return recursive_simpson(f, simp, a, mid, b, fa, fmid, fb, epsilon, rdepth); }
int find_root(function f, double x1, double x2, double epsilon, double *root) { /* Es wird davon ausgegangen, dass eine Nullstelle mit Vorzeichenwechsel * im Intervall [x1,x2] vorliegt und die Funktion stetig ist. Es werden die * Funktionswerte am Rand und in der Mitte des Intervalls berechnet */ double f1, f2; double mid, fmid; f1 = f.func(x1, f.args); f2 = f.func(x2, f.args); /* Ueberpruefung ob das Intervall sinnvoll gewaehlt wurde */ if (f1 * f2 > 0) { return 1; } /* Bisektion solange bis die Nullstelle mit einem absoluten Fehler <= epsilon * bestimmt wurde. */ while (fabs(f1 - f2) > epsilon) { mid = 0.5 * (x1 + x2); fmid = f.func(mid, f.args); /* Bisektion: das Intervall wurde halbiert und der Funktionswert der Mitte * berechnet. Einige Faelle (Rest analog): * Fall (+,+,-): Die Nullstelle liegt im rechten Teilintervall * Fall (+,-,-): Die Nullstelle liegt im linken Teilintervall */ if (f1 * fmid > 0) { x1 = mid; f1 = fmid; } else { x2 = mid; f2 = fmid; } } *root = 0.5 * (x1 + x2); return 0; }
double recursive_simpson(function f, double prev_simp, double x0, double x1, double x2, double f0, double f1, double f2, double epsilon, int rdepth) { /* Wir haben zwei Intervalle [x0,x1] und [x1,x2] mit den Funktionswerten f0, * f1 und f2. Es wird die naechste Verfeinerung nach Simpson berechnet. */ double h = x1 - x0; /* Berechne den Beitrag des Intervalls [x0,x1] zum Integral, dazu muss die * Stuetzstelle in der Haelfte des Intervalls berechnet werden: */ double x01 = 0.5 * (x0 + x1); double f01 = f.func(x01, f.args); double simp01 = (f0 + 4*f01 + f1) * h / 6; /* Berechne den Beitrag des Intervalls [x1,x2] zum Integral: */ double x12 = x01 + h; double f12 = f.func(x12, f.args); double simp12 = (f1 + 4*f12 + f2) * h / 6; /* Neue Abschaetzung des Integrals: */ double simp = simp01 + simp12; /* Rekursionszaehler */ rdepth--; /* Vergleich des neuen Schaetzwertes mit dem Alten. Sollte die Differenz * groesser als epsilon sein, werden die Intervalle halbiert und der Prozess * erneut auf die halbierten Intervalle durchgefuehrt. */ if (rdepth > 0 && fabs(prev_simp - simp) > epsilon) { return recursive_simpson(f, simp01, x0, x01, x1, f0, f01, f1, 0.5*epsilon, rdepth) + recursive_simpson(f, simp12, x1, x12, x2, f1, f12, f2, 0.5*epsilon, rdepth); } else { return simp; } }