std.complex — komplexe Zahlen

Die komplexe Zahl als Wert: Division nach Smith, Betrag über hypot (überlaufsicher bis 1e200), Verzweigungsschnitte nach C99 Annex G.

Mathematik-Units · std.fft · std.tensor · std.mathx

import std.complex;

Schicht 2, hängt an std.dist, std.feq und std.mathx. 56 Funktionen. Alle Beispiele mit lyxc 1.0.21A übersetzt und ausgeführt.


 
Die Struct-Rückgabe legt keinen Speicher mehr an (#1580 behoben). Vorher kostete jeder Aufruf zwei mmap ohne munmap — die Kopie bei der Rückgabe und, größer noch, die Deklaration var p: Pair; mit 4096 Byte. Nachgemessen mit 1.1.2E über 200 000 Rückgaben:

Laufzeit 0,05 s, Spitzenspeicher 6272 kB
mmap-Aufrufe insgesamt: 9   (Programmstart, nicht die Schleife)


Der frühere Rat, in Schleifen adressbasiert zu arbeiten, ist damit hinfällig. Für Signalverarbeitung über viele Werte bleibt std.fft mit getrennten Re/Im-Feldern trotzdem der direktere Weg; CxLoad/CxStore schlagen die Brücke.

Zwei Darstellungen, eine Brücke

std.fft und std.tensor halten Real- und Imaginärteil in getrennten Feldern — gut für lange Reihen, umständlich für eine einzelne Zahl. std.complex ergänzt die einzelne Zahl als Wert:

var z: Cx := CxLoad(reArr, imArr, i);      // aus getrennten Feldern
CxStore(z, reArr, imArr, i);               // und zurück

Damit lässt sich eine einzelne Stelle bequem rechnen, ohne die Feldstruktur aufzugeben.


Rechnen

unit main;
import std.io;
import std.string;
import std.complex;

fn ZC(t: pchar, z: Cx): void {
    Print(t); PrintF64(CxRe(z)); Print("   im="); PrintF64(CxIm(z));
}
fn ZF(t: pchar, v: f64): void { Print(t); PrintF64(v); }

fn main(): int64 {
    var a: Cx := CxNew(3.0, 4.0);
    var b: Cx := CxNew(1.0, 2.0);

    ZF("Abs(3+4i)          re=", CxAbs(a));
    ZC("Mul(3+4i, 1+2i)    re=", CxMul(a, b));
    ZC("Div(3+4i, 1+2i)    re=", CxDiv(a, b));
    ZF("Arg(i)             re=", CxArg(CxI()));

    var big: Cx := CxNew(1.0e200, 1.0e200);
    ZF("Abs(1e200+1e200i)/1e200 = ", CxAbs(big) / 1.0e200);
    return 0;
}

Abs(3+4i)          re=5.000000
Mul(3+4i, 1+2i)    re=-5.000000
   im=10.000000
Div(3+4i, 1+2i)    re=2.200000
   im=-0.400000
Arg(i)             re=1.570796
Abs(1e200+1e200i)/1e200 = 1.414213

Sämtliche Werte stimmen mit der Referenzrechnung überein.


Zwei Entwurfsentscheidungen, die zählen

 
Der Betrag läuft über hypot, nicht über √(re² + im²). Bei 1e200 + 1e200i überläuft schon das Quadrat — die naive Formel liefert inf, obwohl das Ergebnis 1,41e200 problemlos darstellbar ist. Oben ist es nachgemessen: geteilt durch 1e200 kommt 1,414213 heraus, also ein endlicher Wert.

Die Division rechnet nach Smith, nicht nach der Lehrbuchformel. (ac+bd)/(c²+d²) überläuft aus demselben Grund. Smith klammert vorher den betragsgrößeren Nenneranteil aus und bleibt damit im darstellbaren Bereich.

Verzweigungsschnitte

Bei sqrt, log, asin, acos, atanh und Verwandten ist die komplexe Funktion mehrdeutig; welcher Zweig gilt, legt eine Konvention fest. std.complex folgt C99 Annex G — derselben Festlegung wie die C-Standardbibliothek und Pythons cmath.

 
Das Vorzeichen der Null entscheidet mit. Auf dem Schnitt selbst — etwa bei log entlang der negativen reellen Achse — hängt es von −0,0 gegen +0,0 ab, ob das Ergebnis +πi oder −πi lautet. Genau hier ist Atan2F64 aus std.math fehlerhaft (#1577): es verwirft das Vorzeichen der Null und landet in der falschen Halbebene. std.complex rechnet deshalb über MxAtan2 aus std.mathx.

Funktionsübersicht

Gruppe Funktionen
Erzeugen CxNew · CxFromReal · CxFromImag · CxFromPolar · CxZero · CxOne · CxI · CxCopy
Zerlegen CxRe · CxIm · CxAbs · CxAbs2 · CxArg
Prüfen CxIsZero · CxIsReal · CxIsNaN · CxIsInf · CxIsFinite
Grundrechenarten CxAdd · CxSub · CxMul · CxDiv · CxNeg · CxConj · CxInv
Mit einer reellen Zahl CxAddReal · CxSubReal · CxMulReal · CxDivReal
Brücke zu Feldern CxLoad · CxStore

Dazu die analytischen Funktionen — Wurzel, Exponential, Logarithmus, Potenz, Winkel- und Hyperbelfunktionen samt Umkehrungen — durchgehend mit den Schnitten nach C99.

CxAbs2 spart die Wurzel: für Vergleiche genügt das Betragsquadrat, und es ist zugleich der Ausdruck, der in Energie- und Leistungsrechnungen ohnehin gebraucht wird.

 
Bei einer Abweichung zuerst die Referenz prüfen. Beim komplexen pow wich das Ergebnis um 8e−6 von Pythons ab ab. Mit einer Rechnung auf 60 Stellen nachgeprüft lag diese Unit bei 1,1e−13 und Python bei 8,3e−6. Ist eine Abweichung zu groß für IEEE-Rundung, muss nicht der eigene Code falsch sein. </box> —- Letzte Aktualisierung: 2026-08-16 · alle Beispiele mit lyxc 1.0.21A'' übersetzt und ausgeführt; Betrag, Produkt, Quotient und die Überlaufsicherheit gegen eine unabhängige Referenzrechnung geprüft, #1580 selbst nachgemessen.