swift-complex
August 12, 2026 · View on GitHub
swift-complex
Complex numbers in Swift and Swift Package Manager.
Synopsis
import Complex
let z0 = 1.0 + 1.0.i // (1.0+1.0.i)
let z1 = 1.0 - 1.0.i // (1.0-1.0.i)
z0.conj // (1.0-1.0.i)
z0.i // (-1.0+1.0.i)
z0.norm // 2
z0 + z1 // (2.0+0.0.i)
z0 - z1 // (0.0+2.0.i)
z0 * z1 // (2.0+0.0.i)
z0 / z1 // (0.0+1.0.i)
Description
complex.swift implements all the functionality of std::complex in c++11, arguably more intuitively.
like C++11
- Protocol-Oriented
- Complex numbers are
Complex<R>whereRis the type of.realand.imagthat conforms toFloatingPoint. Math functions become available whenRalso conforms toRMath, akaRealElementaryFunctions. - Gaussian integers are
GaussianInt<I>whereIconforms to theGaussianIntElementprotocol, that is,SignedInteger. - In addition to basic arithmetic operations like
+,-,*,/andabs(),Complex<R>getslibmfunctions likeexp(),log(),sin(),cos().
- Complex numbers are
unlike C++11
- Instead of defining the constant
i,DoubleandComplexhave a property.iwhich returnsself * Complex(0,1)so it does not pollute the identifieri, too popularly used for iteration to make it a constant. - Following functions are provided as computed properties:
z.absforabs(z)z.argforarg(z)z.normfornorm(z)z.conjforconj(z)z.projforproj(z)
- Construct a complex number via polar notation as:
Complex(abs:magnitude, arg:argument)
RMath and CMath
What you get out of Complex<R> depends on what R can do.
R: FloatingPointis all the struct itself asks. Construction,+-*/,conj,norm,.i,description, andCodable(whenRis) — everything that is plain arithmetic works for any element.R: RMathis where the math comes from. WhenRconforms,Complex<R>conforms toCMath(typealiasComplexElementaryFunctions) and gainsexp,log,sqrtand friends,abs/argand polar construction, andtoString(_:radix:).
RMath (typealias RealElementaryFunctions; deliberately not named ElementaryFunctions, which would collide with apple/swift-numerics and friends) asks of the element:
init(_:Double)andtoDouble()— the two conversions no protocol can guess;static var precision:Int— the bit width results are computed to;- the math functions,
exp(_:)throughatan2(y:x:), in plain form and withprecision:debug:flags. The full forms are requirements, not conveniences, so that aprecision:you pass dispatches to the element instead of being silently dropped; fixed-precision elements accept and ignore the flags. (cbrt,expm1, andlog1pcome with defaults built from the other requirements.)
Out of the box only Double is predefined, by way of RMathViaDouble — a sub-protocol that implements every math requirement by round-tripping through Double; adopt it and toDouble() is all your type owes. Every other element is a conformance you, or a sibling package, declare:
- SwiftNumericsExample fills
Float's deliberately vacant slot with apple/swift-numerics'RealModule. - SwiftBigNumExample adopts
BigRatandBigFloatof dankogai/swift-bignum with an empty extension each, for arbitrary precision —Complex<BigFloat>.sqrt(z, precision:256)really is 256 bits, andComplex<BigRat>arithmetic is exact.
CMath also has a settable precision, defaulting to 128: the default precision: handed down to the element, likewise ignored by elements whose precision is fixed.
ComplexOperators
** — pow(base, exponent) as an operator — lives in a separate module so that plain import Complex does not add operators to your namespace:
import ComplexOperators // @_exported imports Complex, too
2.0 ** 3.0 // 8.0
(1.0+1.0.i) ** 2.0 // (0.0+2.0.i)
2.0 ** 3.0 ** 2.0 // 512.0 -- binds tighter than *, associates right
Usage
build
$ git clone https://github.com/dankogai/swift-complex.git
$ cd swift-complex # the following assumes your $PWD is here
$ swift build
test
The suites are written in Swift Testing, the modern successor of XCTest. The root package tests everything that needs no dependency — still fetching nothing:
$ swift test
The element conformances have suites of their own, in the sibling example packages:
$ (cd SwiftNumericsExample && swift test)
$ (cd SwiftBigNumExample && swift test)
REPL
Simply
$ swift run --repl
and in your repl,
Welcome to Swift! Type :help for assistance.
1> import Complex
2> Complex.sqrt(1.i)
$R0: Complex.Complex<Double> = {
real = 0.70710678118654757
imag = 0.70710678118654757
}
Xcode
Just open the package directory — Xcode natively supports Swift Package Manager:
$ open ./Package.swift
From Your SwiftPM-Managed Projects
Add the following to the dependencies section:
.package(
url: "https://github.com/dankogai/swift-complex.git", from: "6.3.0"
)
and the following to the .target argument:
.target(
name: "YourSwiftyPackage",
dependencies: ["Complex"])
Now all you have to do is:
import Complex
in your code. Enjoy!
Prerequisite
Swift 6 or better, macOS or Linux to build.
Swift Numerics vs. this module
This section used to be a CAVEAT that began "You should consider using ComplexModule of Numerics instead of this." No longer. With apple/swift-numerics complex number support on Swift is official at last — and as of 6.3 this module is fully resurrected, for the parts officialdom does not cover.
- The element is open.
Complex<R>asks onlyFloatingPointofR; the math functions arrive whenRconforms toRMath, whose slot is deliberately left for you to fill.ComplexModulerequiresRealType: Real, its own hierarchy. Here the element's math is whatever you choose — SwiftNumericsExample fills the slot with swift-numerics' ownRealModule, SwiftBigNumExample with dankogai/swift-bignum, an emptyextensioneach. This module does not compete with swift-numerics; it runs happily on top of it. - Arbitrary precision, all the way down. Every math function comes in a
precision:debug:form, as in swift-bignum, andComplexhands the flag to every element call underneath —Complex<BigFloat>.sqrt(z, precision:256)really is 256 bits. Exact types stay exact:(1+2i)/(3+4i)overComplex<BigRat>is(11+2i)/25, not a rounding of it.ComplexModulehas no such channel. - No point at infinity.
ComplexModuleadopts it; while mathematically more correct, it may technically cause unexpected results because real operations on complex numbers are no longer isomorphic to real operations on real numbers:Complex(-1.0, 0.0) / Complex(0.0, 0.0)isComplex(+infinity, 0.0)there, notComplex(-infinity, nan)like many other platforms. This module keeps the componentwise semantics of C++'sstd::complexand friends. - Gaussian integers.
GaussianInt<I>for anySignedInteger,BigIntincluded. swift-numerics has no counterpart. - Ergonomics.
1.0 + 2.0.iliterals;abs,arg,magnitudeandargumentthat are settable, not just readable; polar construction;toString(_:radix:)down to hexfloat;**viaimport ComplexOperators, opt-in so it never sneaks into your namespace. - Nothing to fetch. The library depends on nothing but the standard library. The examples that do depend on things are packages of their own, so
swift buildhere fetches exactly nothing.