Go gehört zu den wenigen Mainstream-Sprachen, die komplexe Zahlen direkt in die Sprache eingebaut haben — als eigene Typen complex64 und complex128, mit imaginärem Literal-Suffix i und drei Built-in-Funktionen für Konstruktion und Zerlegung. Im Backend- und Web-Alltag braucht man das fast nie. Wer aber Signal-Processing, FFT, Physik-Simulationen oder geometrische Transformationen schreibt, bekommt die übliche (re, im)-Mathematik ohne Library geliefert. Dieser Artikel zeigt die beiden Typen, die Literal-Syntax, das math/cmplx-Paket und wo die typischen Stolperfallen liegen.

Was Complex in Go bietet

Go kennt genau zwei eingebaute Complex-Typen:

TypReal-AnteilImaginär-AnteilGesamtgröße
complex64float32float3264 Bit
complex128float64float64128 Bit

Beide Typen sind predeclared — du brauchst keinen Import, um sie zu nutzen. Die Komponenten sind ganz normale IEEE-754-Floats, mit allen üblichen Eigenheiten (siehe Float-Artikel). complex128 ist die idiomatische Default-Wahl; complex64 nimmt man nur, wenn Speicher knapp ist (große Arrays, GPU-nahe Daten).

Imaginäres Literal mit i-Suffix

Eine imaginäre Konstante ist eine Integer- oder Float-Zahl gefolgt vom kleingeschriebenen Buchstaben i:

Go literals.go
package main

import "fmt"

func main() {
    a := 1 + 2i           // complex128: real=1, imag=2
    b := 3.14i            // complex128: real=0, imag=3.14
    c := 0i               // complex128: 0+0i
    d := 6.67428e-11i     // wissenschaftliche Notation erlaubt

    fmt.Printf("%v %v %v %v\n", a, b, c, d)
}

Der Compiler erkennt aus 1 + 2i automatisch den Complex-Typ. Imaginäre Literale folgen denselben Regeln wie Float-Literale — Hex (0x1p-2i), wissenschaftliche Notation (1E6i) und Underscore-Trennzeichen sind alle erlaubt. Eine Eigenheit zur Rückwärtskompatibilität: 0123i wird als dezimales 123i gelesen, nicht als Oktal. Wer Oktal will, muss explizit 0o123i schreiben.

Built-ins: complex, real, imag

Drei Built-in-Funktionen reichen für Konstruktion und Zerlegung — kein Import nötig:

Go builtins.go
package main

import "fmt"

func main() {
    c := complex(3, 4)    // 3+4i als complex128
    r := real(c)          // 3 (float64)
    i := imag(c)          // 4 (float64)

    fmt.Printf("c=%v real=%v imag=%v\n", c, r, i)

    // complex64 mit float32-Argumenten:
    var f32a, f32b float32 = 1.5, 2.5
    small := complex(f32a, f32b) // ergibt complex64
    fmt.Printf("%T\n", small)
}
Output
c=(3+4i) real=3 imag=4
complex64

complex(re, im) wählt den Ergebnistyp anhand der Argument-Typen: float32complex64, float64complex128. real() und imag() geben den passenden Float-Typ zurück.

Arithmetik mit Complex

Die vier Grundrechenarten +, -, *, / funktionieren direkt am Complex-Typ — implementiert nach den üblichen Regeln der komplexen Arithmetik:

Go arithmetic.go
package main

import "fmt"

func main() {
    a := 2 + 3i
    b := 1 - 1i

    fmt.Println(a + b) // (3+2i)
    fmt.Println(a - b) // (1+4i)
    fmt.Println(a * b) // (5+1i)  — (2+3i)(1-1i) = 2-2i+3i-3i² = 5+i
    fmt.Println(a / b) // (-0.5+2.5i)
}
Output
(3+2i)
(1+4i)
(5+1i)
(-0.5+2.5i)

Modulo (%) gibt es nicht — definiert ist es für komplexe Zahlen ohnehin nicht. Vergleich mit < oder > ebenfalls nicht (komplexe Zahlen sind nicht total geordnet); nur == und != sind erlaubt.

Das math/cmplx-Paket

Was über die vier Grundrechenarten hinausgeht, lebt im Standard-Paket math/cmplx. Alle Funktionen arbeiten ausschließlich mit complex128:

Go cmplx.go
package main

import (
    "fmt"
    "math/cmplx"
)

func main() {
    c := 3 + 4i

    fmt.Println(cmplx.Abs(c))          // 5 (Betrag/Modul)
    fmt.Println(cmplx.Phase(c))        // 0.927… (Argument in Radiant)
    r, θ := cmplx.Polar(c)             // Polarkoordinaten
    fmt.Printf("r=%v θ=%v\n", r, θ)

    fmt.Println(cmplx.Sqrt(-1))        // (0+1i)
    fmt.Println(cmplx.Exp(1i * 3.14159265))  // ≈ -1+0i (Eulers Identität)
    fmt.Println(cmplx.Conj(c))         // 3-4i
}
Output
5
0.9272952180016122
r=5 θ=0.9272952180016122
(0+1i)
(-1+1.2246467991473515e-16i)
(3-4i)

Weiterhin verfügbar: Log, Log10, Pow, Rect (von Polar zurück), trigonometrische Funktionen Sin/Cos/Tan samt Inversen, hyperbolische Varianten sowie Inf, NaN, IsInf, IsNaN für Spezialwerte. Das Paket folgt C99 Annex G, der Norm-Vorgabe für komplexe Arithmetik.

Wann braucht man Complex überhaupt?

Ehrlich gesagt: in typischen Web- und Backend-Workloads praktisch nie. Die natürlichen Anwendungsfelder liegen anderswo:

  • Signalverarbeitung — DFT/FFT, Filter-Design, Audio- und Bildverarbeitung. Frequenzbereich ist immer komplex.
  • Physik-Simulation — Quantenmechanik (Wellenfunktionen sind komplexwertig), AC-Stromkreise (Impedanz), Wellengleichungen.
  • Geometrische Transformationen — Rotation in der Ebene als Multiplikation mit e^(iθ) ist eleganter als 2x2-Matrizen.
  • Kontrolltechnik — Pol-Nullstellen-Analyse, Bode-Plots, Stabilitätsanalyse.
  • Numerische Mathematik — Wurzeln von Polynomen höheren Grades sind oft komplex, auch wenn die Koeffizienten reell sind.

Für eine REST-API, einen Scheduler oder ein CLI-Tool wirst du complex128 nie sehen. Das Sprachfeature ist trotzdem da — eine bewusste Entscheidung der Go-Designer, die Numerik-Modell aus C übernommen haben.

FAQ

Wieso hat Go eingebauten Complex-Support, aber kein Decimal?

Go orientiert sich am C-/IEEE-754-Numerik-Modell. Komplexe Zahlen sind dort als _Complex seit C99 Sprach-Feature, also hat Go sie übernommen. Decimal-Arithmetik (wie Pythons decimal oder Javas BigDecimal) gehört nicht zur IEEE-Hardware-Welt und lebt in Go ausschließlich in Drittpaketen — etwa shopspring/decimal. Eine Konsistenz-Entscheidung, keine grundsätzliche Bevorzugung.

Welcher Complex-Typ ist Default?

Bei untypisierten Literalen wie `1 + 2i` wählt Go `complex128`. Das spiegelt die Default-Wahl bei Floats wider (`float64` ist Standard). `complex64` entsteht nur, wenn du explizit mit `float32`-Argumenten konstruiert oder den Typ explizit angibst.

Kann man Complex mit anderen Numerischen mischen?

Nein. Wie überall in Go braucht es explizite Konvertierung. `var x float64 = 3.0; c := complex(x, 0)` ist der saubere Weg, ein Float in einen Complex zu heben. Ein direktes `x + 1i` mit typisiertem x schlägt fehl, weil Typen nicht gemischt werden.

Vergleich mit "==" möglich?

Ja — `==` und `!=` sind definiert und vergleichen Real- und Imaginärteil paarweise. Die üblichen Floating-Point-Caveats gelten unverändert: rechnest du Werte ineinander um, sind exakte Gleichheits-Checks selten verlässlich. Besser über `cmplx.Abs(a - b) < epsilon` arbeiten. Ordnungsvergleiche (`<`, `>`) gibt es nicht, da komplexe Zahlen keine totale Ordnung haben.

Format-Verb in fmt.Printf?

Es gibt kein eigenes Verb wie `%c`. Stattdessen funktioniert `%v` universell und liefert die Form `(re+imi)`. Auch `%g` und `%f` sind anwendbar und formatieren beide Komponenten konsistent. (`%c` ist in Go für Unicode-Zeichen reserviert — siehe Rune.)

Wie konvertiere ich complex64 nach complex128?

Wie jede Type Conversion in Go: `big := complex128(c)`. Das hebt Real- und Imaginärteil von `float32` auf `float64` hoch — verlustfrei. Andersherum (`complex64(big)`) ist es eine Verkürzung mit potenziellem Genauigkeitsverlust, genau wie bei den Floats darunter.

Weiterführende Ressourcen

Externe Quellen

/ Weiter

Zurück zu Datentypen

Zur Übersicht