std.numeric — numerisches Grundwerkzeug
Nullstellen, Integration, Interpolation und Splines, gewöhnliche Differentialgleichungen samt steifer Löser und Randwertprobleme.
→ Mathematik-Units · std.sum · std.autodiff · Funktionen
import std.numeric;
Schicht 1, hängt an std.sum, std.math und std.alloc. 34 Funktionen. Alle Beispiele mit lyxc 1.0.21A übersetzt und ausgeführt.
Die Funktion wird übergeben
std.numeric arbeitet mit Funktionszeigern. Eine zu untersuchende Funktion wird als gewöhnliche fn geschrieben und beim Aufruf über ihren Namen weitergereicht:
fn f(x: f64): f64 { return x * x - 2.0; }
var wurzel: f64 := NumBrent(f, 1.0, 2.0, 0.000000001, 200);
| Signatur | Wofür |
|---|---|
fn(f64): f64 | Nullstellen, Integration, Ableitung |
fn(f64, f64): f64 | ODE — f(t, y) |
fn(f64, f64, f64): f64 | Randwertproblem — f(t, y, y') |
fn(f64, int64, int64): void | ODE-System, Zustand über Adressen |
Nullstellen
unit main;
import std.io;
import std.string;
import std.alloc;
import std.math;
import std.numeric;
fn ZF(t: pchar, v: f64): void { Print(t); PrintF64(v); }
fn f(x: f64): f64 { return x * x - 2.0; }
fn df(x: f64): f64 { return 2.0 * x; }
fn main(): int64 {
ZF("Bisect : ", NumBisect(f, 1.0, 2.0, 0.000000001, 200));
ZF("Brent : ", NumBrent(f, 1.0, 2.0, 0.000000001, 200));
ZF("Newton : ", NumNewton(f, df, 1.0, 0.000000001, 100));
ZF("NewtonNum : ", NumNewtonNum(f, 1.0, 0.000000001, 100));
ZF("Secant : ", NumSecant(f, 1.0, 2.0, 0.000000001, 100));
ZF("sqrt(2) : ", SqrtF64(2.0));
return 0;
}
Bisect : 1.414213
Brent : 1.414213
Newton : 1.414213
NewtonNum : 1.414213
Secant : 1.414213
sqrt(2) : 1.414213
Alle fünf finden dieselbe Nullstelle — sie unterscheiden sich in Voraussetzungen und Geschwindigkeit:
| Verfahren | Braucht | Verhalten |
|---|---|---|
NumBisect | Intervall mit Vorzeichenwechsel | findet immer, aber langsam |
NumBrent | dasselbe | schnell und garantiert — die Vorgabe |
NumNewton | Startwert und Ableitung | am schnellsten, kann davonlaufen |
NumNewtonNum | nur Startwert | Ableitung numerisch, entsprechend ungenauer |
NumSecant | zwei Startwerte | ohne Ableitung, meist schneller als Bisektion |
NumBrentist fast immer die richtige Wahl. Es verbindet die Sicherheit der Bisektion mit der Geschwindigkeit der inversen quadratischen Interpolation: es kann nicht aus dem Intervall laufen, braucht aber typisch ein Zehntel der Schritte. Newton ist nur dann besser, wenn die Ableitung exakt vorliegt — und dann führt der Weg über std.autodiff, das sie ohne Handrechnung liefert.
Newton ohne Vorzeichenwechsel-Intervall kann bei einem schlechten Startwert beliebig weit weglaufen oder zwischen zwei Punkten pendeln. DiemaxIter-Grenze ist deshalb kein Formalismus.
NumDeriv(f, x) und NumDeriv2(f, x) liefern erste und zweite Ableitung numerisch; NumDerivStep(x) gibt die dazu passende Schrittweite.
Integration
fn g(x: f64): f64 { return x * x; } // Integral 0..1 = 1/3
Trapez x^2 0..1 : 0.333333
Simpson x^2 0..1 : 0.333333
Romberg x^2 0..1 : 0.333333
Gauss5 x^2 0..1 : 0.333333
| Verfahren | Eigenschaft |
|---|---|
NumTrapezoid(f, a, b, n) | einfachste Form, fester Raster |
NumSimpson(f, a, b, n) | deutlich genauer bei gleichem Aufwand |
NumAdaptiveSimpson(f, a, b, tol, …) | verfeinert nur dort, wo es nötig ist |
NumRomberg(f, a, b, maxLevel, tol) | Extrapolation, sehr genau bei glatten Funktionen |
NumGauss5(f, a, b) | fünf Stützstellen, exakt bis Grad 9 |
NumGaussComposite(f, a, b, n) | dasselbe stückweise |
NumGauss5 rechnet x² mit fünf Auswertungen exakt, während Trapez dafür tausend braucht. Der Preis: Gauß setzt eine glatte Funktion voraus. Bei einem Knick oder einer Polstelle ist NumAdaptiveSimpson die verlässlichere Wahl, weil es die Verfeinerung dorthin lenkt, wo sich die Funktion tatsächlich ändert.
Interpolation
| Funktion | Zweck |
|---|---|
NumLerp(x0, y0, x1, y1, x) | zwischen zwei Punkten |
NumInterpLinear(xs, ys, n, x) | Streckenzug durch n Punkte |
NumLagrange(xs, ys, n, x) | Polynom durch alle Punkte |
NumSplineBuild + NumSplineEval | kubischer Spline |
Lagrange ist bei vielen Punkten die falsche Wahl. Ein Polynom durch 20 Stützstellen schwingt zwischen ihnen stark aus — das Runge-Phänomen. Für glatte Kurven durch viele Punkte ist der Spline richtig:NumSplineBuildrechnet einmal die zweiten Ableitungen aus (Feldy2), danach ist jedesNumSplineEvalbillig.
Differentialgleichungen
fn ode(t: f64, y: f64): f64 { return y; } // y' = y, y(0)=1 -> y(1) = e
Rk4 y'=y, y(1) : 2.718281
Euler y'=y, y(1) : 2.704813
e zum Vergleich : 2.718281
Bei gleicher Schrittzahl (100) trifft Runge-Kutta alle gezeigten Stellen, Euler weicht schon in der dritten ab. Das ist der Unterschied zwischen einem Verfahren erster und vierter Ordnung: halbiert man die Schrittweite, wird der Fehler bei Euler halbiert, bei RK4 auf ein Sechzehntel gedrückt.
| Gruppe | Funktionen |
|---|---|
| Einzelschritt | NumEulerStep · NumMidpointStep · NumRk4Step |
| Über ein Intervall | NumEulerSolve · NumRk4Solve · NumRk4Adaptive |
| Systeme | NumRk4SolveSys |
| Mehrschritt | NumAdamsBashforth4 · NumAdamsMoulton4 |
| Steif | NumBdf1 · NumBdf2 · NumTrapezoidal |
| Randwertprobleme | NumShoot · NumShootTrace · NumBvpLinear |
Steife Gleichungen erkennt man daran, dass RK4 winzige Schritte braucht. Wenn eine Lösung schnell abklingende und langsam veränderliche Anteile mischt, erzwingt der schnelle Anteil die Schrittweite — auch lange nachdem er praktisch verschwunden ist. Explizite Verfahren werden dann unbrauchbar langsam oder instabil.
NumBdf1,NumBdf2undNumTrapezoidalsind implizit und haben das Problem nicht. Sie kosten je Schritt mehr, brauchen aber Größenordnungen weniger Schritte. Typische Fälle: chemische Reaktionskinetik, elektrische Netzwerke mit sehr verschiedenen Zeitkonstanten, Regelkreise.
NumShoot löst ein Randwertproblem, indem es die Anfangssteigung so lange anpasst, bis der zweite Rand getroffen wird; NumBvpLinear geht bei linearen Problemen direkt über ein Gleichungssystem.
Zusammenspiel
- Für exakte Ableitungen statt numerischer: std.autodiff liefert sie über Dualzahlen —
NumNewtonwird damit sowohl schnell als auch genau. - Die Summationen laufen über std.sum, sind also gegen Auslöschung abgesichert.
Letzte Aktualisierung: 2026-08-16 · alle Beispiele mit lyxc 1.0.21A übersetzt und ausgeführt; Nullstellen, Integrale, Ableitungen und ODE-Lösungen gegen geschlossene Ausdrücke geprüft.
