Skip to content

Add Complex<T> generic struct mirroring Complex API surface#127333

Merged
tannergooding merged 8 commits into
copilot/add-generic-complex-supportfrom
copilot/sub-pr-127331
May 14, 2026
Merged

Add Complex<T> generic struct mirroring Complex API surface#127333
tannergooding merged 8 commits into
copilot/add-generic-complex-supportfrom
copilot/sub-pr-127331

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 23, 2026

Implements a generic Complex<T> where T : IFloatingPointIeee754<T>, IMinMaxValue<T> that mirrors the full public API of the existing Complex struct, as scoped by @tannergooding. The IComplexNumber<TSelf, T> interface and new members on non-generic Complex are deferred to a follow-up PR.

Description

New type: Complex<T>

Direct generic port of Complex in a new Complex.Generic.cs source file:

  • Arithmetic operators: all Complex<T>×Complex<T>, T×Complex<T>, and Complex<T>×T overloads for +, -, *, /, unary -/+, ++, --
  • Static properties: Zero, One, ImaginaryOne, NaN, Infinity (exposed as static properties per the approved API surface; INumberBase.One and INumberBase.Zero bind implicitly to the matching public properties)
  • Properties: Real, Imaginary
  • Instance methods: GetMagnitude(), GetPhase() (per approved API surface — exposed as named methods rather than properties)
  • Math: Abs, Conjugate, Reciprocal, Log/Log10, Exp, Sqrt, Pow, Sin/Cos/Tan, Sinh/Cosh/Tanh, Asin/Acos/Atan, FromPolarCoordinates
  • Predicates: full Is* set matching INumberBase<T>
  • Generic math: implements INumberBase<Complex<T>>, ISignedNumber<Complex<T>>, IAdditiveIdentity, IMultiplicativeIdentity, IEquality/Comparison operators
  • Parsing / formatting: full IParsable, ISpanParsable, IUtf8SpanParsable, ISpanFormattable, IUtf8SpanFormattable
  • Conversions: CreateChecked/CreateSaturating/CreateTruncating use internal TryConvertFrom*Core and TryConvertTo*Core helpers that correctly chain same-type, cross-type (ComplexComplex<T>), BigInteger, and general numeric type special cases per mode

Constraint rationale

IMinMaxValue<T> is added alongside IFloatingPointIeee754<T> because the ported Sqrt and Asin_Internal algorithms compute per-instantiation overflow thresholds from T.MaxValue (e.g., s_sqrtRescaleThreshold, s_asinOverflowThreshold). Every practical floating-point type (float, double, Half, BFloat16, NFloat) implements both interfaces.

Shared constants

Complex.DefaultNumberStyle and Complex.InvalidNumberStyles are promoted from private to internal in Complex.cs so that Complex<T> can reference them directly rather than maintaining duplicate definitions.

Code sharing between Complex and Complex<T>

To ensure the non-generic Complex and Complex<T> stay in sync, all Complex methods with more than 4 lines of implementation now delegate to the corresponding Complex<double> method. This covers:

  • Mixed-type operators: operator *(Complex, double), operator *(double, Complex), and all three / overloads
  • Trig/math functions: Asin, Acos, Tan, Sqrt, Pow(Complex, Complex)
  • Magnitude comparisons: MaxMagnitude, MinMagnitude
  • Formatting: ToString(string?, IFormatProvider?)
  • Explicit interface implementations MaxMagnitudeNumber, MinMagnitudeNumber, MultiplyAddEstimate: each has an internal static implementation on Complex<T>; Complex<T>'s explicit interface implementation delegates to it, and Complex's explicit interface implementation calls through Complex<double>
  • Conversion helpers TryConvertFrom*: Complex<T> exposes internal static TryConvertFromCheckedCore, TryConvertFromSaturatingCore, TryConvertFromTruncatingCore that implement the full conversion logic (same-type, ComplexComplex<T>, signed types via T.TryConvertFrom*, unsigned/decimal types via TOther.TryConvertTo*<T>); Complex.TryConvertFrom replaces its long explicit type chain with a Complex<double> special case followed by delegation to Complex<double>.TryConvertFromCheckedCore
  • Conversion helpers TryConvertTo*: Complex<T> exposes internal static TryConvertToCheckedCore, TryConvertToSaturatingCore, TryConvertToTruncatingCore that implement the full conversion logic (same-type fast path returning real/NaN, Complex output via double.Create*, BigInteger output with appropriate imaginary-part handling, general types via T.TryConvertTo* with fallback to TOther.TryConvertFrom*<T>); Complex's three long TryConvertTo* chains are replaced with a Complex<double> output special case followed by delegation to Complex<double>.TryConvertTo*Core

As a result, the now-unused private fields (s_sqrtRescaleThreshold, s_asinOverflowThreshold, s_log2) and helpers (Log1P, Asin_Internal) are removed from Complex.cs.

Cross-type conversion support

Both types now correctly support bi-directional conversion:

  • Complex.CreateChecked(new Complex<double>(1, 2))Complex accepts Complex<double> input
  • Complex<float>.CreateChecked(new Complex(1, 2))Complex<T> accepts Complex (non-generic) input, with mode-appropriate component conversion
  • int.CreateChecked(new Complex<double>(5, 0)) — real types can be extracted from Complex<T> via TryConvertToCheckedCore
  • int.CreateChecked(new Complex(5, 0)) — real types can be extracted from Complex via delegation to Complex<double>.TryConvertToCheckedCore

Example usage

Complex<float> z = Complex<float>.FromPolarCoordinates(2.0f, MathF.PI / 4);
float mag   = z.GetMagnitude();
float phase = z.GetPhase();
Complex<float> w = z * 3.0f + new Complex<float>(1.0f, -1.0f);
var product = Complex<float>.Sin(z) * Complex<double>.Exp(new Complex<double>(0, Math.PI));

// Cross-type conversions work in both directions:
Complex        c  = Complex.CreateChecked(new Complex<double>(3, 4));
Complex<float> cf = Complex<float>.CreateChecked(new Complex(3, 4));
int            n  = int.CreateChecked(new Complex<double>(5, 0));

// Static properties:
var zero = Complex<float>.Zero;
var one  = Complex<double>.One;

Files changed

File Change
src/System/Numerics/Complex.cs Promote DefaultNumberStyle and InvalidNumberStyles to internal; delegate long methods to Complex<double>; replace TryConvertFrom/TryConvertTo* chains with Complex<double>.*Core delegation
src/System/Numerics/Complex.Generic.cs New — full Complex<T> implementation with static properties for Zero/One/ImaginaryOne/NaN/Infinity; GetMagnitude()/GetPhase() methods; internal static shared implementations for MaxMagnitudeNumber, MinMagnitudeNumber, MultiplyAddEstimate, TryConvertFrom*Core, and TryConvertTo*Core
src/System.Runtime.Numerics.csproj Add new file to build
ref/System.Runtime.Numerics.cs Add Complex<T> public surface to ref assembly
tests/ComplexTests.cs Add ComplexTests_Generic with 37 tests

Note

This PR description was authored by GitHub Copilot.

@dotnet-policy-service
Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @dotnet/area-system-numerics
See info in area-owners.md if you want to be subscribed.

Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/6ae7397b-1811-41d7-a5d8-55ef50af02cd

Co-authored-by: tannergooding <10487869+tannergooding@users.noreply.github.com>
Copilot AI changed the title [WIP] Add Complex<T> and IComplexNumber<TSelf, T> API surface Add Complex<T> generic struct mirroring Complex API surface Apr 23, 2026
Copilot AI requested a review from tannergooding April 23, 2026 18:27
Comment thread src/libraries/System.Runtime.Numerics/src/System/Numerics/Complex.Generic.cs Outdated
Comment thread src/libraries/System.Runtime.Numerics/src/System/Numerics/Complex.Generic.cs Outdated
…se in Complex<T>

Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/e09763ab-e8b2-4ccf-8029-2cc8c6dbd47a

Co-authored-by: tannergooding <10487869+tannergooding@users.noreply.github.com>
… Complex.cs methods >4 lines to Complex<double>

Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/4edc4c27-249d-40a9-92b4-fda815b84714

Co-authored-by: tannergooding <10487869+tannergooding@users.noreply.github.com>
Comment thread src/libraries/System.Runtime.Numerics/src/System/Numerics/Complex.cs Outdated
…e to Complex<T>; delegate Complex explicit impls to them

Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/423a9dba-89a1-41d2-8884-5915b7ffc74d

Co-authored-by: tannergooding <10487869+tannergooding@users.noreply.github.com>
…-type conversion; share via Complex.TryConvertFrom delegation

Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/0b63e9f7-7efe-4068-b899-dfda38c4dc5a

Co-authored-by: tannergooding <10487869+tannergooding@users.noreply.github.com>
…T>; replace Complex.cs TryConvertTo* chains with delegation

Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/ee27c47e-3787-4c63-9823-23e289245e0e

Co-authored-by: tannergooding <10487869+tannergooding@users.noreply.github.com>
Copilot AI requested a review from tannergooding May 7, 2026 18:17
Comment thread src/libraries/System.Runtime.Numerics/src/System/Numerics/Complex.Generic.cs Outdated
…s to static properties in Complex<T>; remove redundant INumberBase.One/Zero explicit impls

Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/4daa6a5a-87a9-46b6-b055-56ce91e228a2

Co-authored-by: tannergooding <10487869+tannergooding@users.noreply.github.com>
@tannergooding tannergooding marked this pull request as ready for review May 13, 2026 15:47
@tannergooding tannergooding merged commit 1997f10 into copilot/add-generic-complex-support May 14, 2026
77 of 80 checks passed
@tannergooding tannergooding deleted the copilot/sub-pr-127331 branch May 14, 2026 00:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants