====== std.complex — komplexe Zahlen ======
Die komplexe Zahl als **Wert**: Division nach Smith, Betrag über ''hypot'' (überlaufsicher bis 1e200), Verzweigungsschnitte nach C99 Annex G.
→ [[lyx_-_programmiersprache:units:mathematik|Mathematik-Units]] · [[lyx_-_programmiersprache:units:fft|std.fft]] · [[lyx_-_programmiersprache:units:tensor|std.tensor]] · [[lyx_-_programmiersprache:units:mathx|std.mathx]]
import std.complex;
Schicht 2, hängt an [[lyx_-_programmiersprache:units:dist|std.dist]], [[lyx_-_programmiersprache:units:feq|std.feq]] und [[lyx_-_programmiersprache:units:mathx|std.mathx]]. 56 Funktionen. Alle Beispiele mit ''lyxc 1.0.21A'' übersetzt und ausgeführt.
----
> **Die Struct-Rückgabe legt keinen Speicher mehr an** ([[https://github.com/SEOLizer/LyX-Compiler/issues/1580|#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 [[lyx_-_programmiersprache:units:fft|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 ([[https://github.com/SEOLizer/LyX-Compiler/issues/1577|#1577]]): es verwirft das Vorzeichen der Null und landet in der falschen Halbebene. ''std.complex'' rechnet deshalb über ''MxAtan2'' aus [[lyx_-_programmiersprache:units:mathx|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 ''a**b'' 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.
----
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.