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
 
NumBrent ist 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. Die maxIter-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 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: NumSplineBuild rechnet einmal die zweiten Ableitungen aus (Feld y2), danach ist jedes NumSplineEval billig.

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, NumBdf2 und NumTrapezoidal sind 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 — NumNewton wird 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.