File: System\Numerics\Complex.cs
Web Access
Project: src\runtime\src\libraries\System.Runtime.Numerics\src\System.Runtime.Numerics.csproj (System.Runtime.Numerics)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Buffers;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;

namespace System.Numerics
{
    /// <summary>
    /// A complex number z is a number of the form z = x + yi, where x and y
    /// are real numbers, and i is the imaginary unit, with the property i2= -1.
    /// </summary>
    [Serializable]
    [TypeForwardedFrom("System.Numerics, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
    public readonly struct Complex
        : IEquatable<Complex>,
          IFormattable,
          INumberBase<Complex>,
          ISignedNumber<Complex>,
          IUtf8SpanFormattable
    {
        internal const NumberStyles DefaultNumberStyle = NumberStyles.Float | NumberStyles.AllowThousands;

        internal const NumberStyles InvalidNumberStyles = ~(NumberStyles.AllowLeadingWhite | NumberStyles.AllowTrailingWhite
                                                         | NumberStyles.AllowLeadingSign | NumberStyles.AllowTrailingSign
                                                         | NumberStyles.AllowParentheses | NumberStyles.AllowDecimalPoint
                                                         | NumberStyles.AllowThousands | NumberStyles.AllowExponent
                                                         | NumberStyles.AllowCurrencySymbol | NumberStyles.AllowHexSpecifier
                                                         | NumberStyles.AllowTrailingInvalidCharacters);

        public static readonly Complex Zero = new(0.0, 0.0);
        public static readonly Complex One = new(1.0, 0.0);
        public static readonly Complex ImaginaryOne = new(0.0, 1.0);
        public static readonly Complex NaN = new(double.NaN, double.NaN);
        public static readonly Complex Infinity = new(double.PositiveInfinity, double.PositiveInfinity);

        private const double InverseOfLog10 = 0.43429448190325; // 1 / Log(10)

        // Do not rename, these fields are needed for binary serialization
        private readonly double m_real; // Do not rename (binary serialization)
        private readonly double m_imaginary; // Do not rename (binary serialization)

        public Complex(double real, double imaginary)
        {
            m_real = real;
            m_imaginary = imaginary;
        }

        public double Real { get { return m_real; } }
        public double Imaginary { get { return m_imaginary; } }

        public double Magnitude { get { return Abs(this); } }
        public double Phase { get { return Math.Atan2(m_imaginary, m_real); } }

        public static Complex FromPolarCoordinates(double magnitude, double phase)
        {
            (double sin, double cos) = Math.SinCos(phase);
            return new Complex(magnitude * cos, magnitude * sin);
        }

        public static Complex Negate(Complex value)
        {
            return -value;
        }

        public static Complex Add(Complex left, Complex right)
        {
            return left + right;
        }

        public static Complex Add(Complex left, double right)
        {
            return left + right;
        }

        public static Complex Add(double left, Complex right)
        {
            return left + right;
        }

        public static Complex Subtract(Complex left, Complex right)
        {
            return left - right;
        }

        public static Complex Subtract(Complex left, double right)
        {
            return left - right;
        }

        public static Complex Subtract(double left, Complex right)
        {
            return left - right;
        }

        public static Complex Multiply(Complex left, Complex right)
        {
            return left * right;
        }

        public static Complex Multiply(Complex left, double right)
        {
            return left * right;
        }

        public static Complex Multiply(double left, Complex right)
        {
            return left * right;
        }

        public static Complex Divide(Complex dividend, Complex divisor)
        {
            return dividend / divisor;
        }

        public static Complex Divide(Complex dividend, double divisor)
        {
            return dividend / divisor;
        }

        public static Complex Divide(double dividend, Complex divisor)
        {
            return dividend / divisor;
        }

        public static Complex operator -(Complex value)  /* Unary negation of a complex number */
        {
            return new Complex(-value.m_real, -value.m_imaginary);
        }

        public static Complex operator +(Complex left, Complex right)
        {
            return new Complex(left.m_real + right.m_real, left.m_imaginary + right.m_imaginary);
        }

        public static Complex operator +(Complex left, double right)
        {
            return new Complex(left.m_real + right, left.m_imaginary);
        }

        public static Complex operator +(double left, Complex right)
        {
            return new Complex(left + right.m_real, right.m_imaginary);
        }

        public static Complex operator -(Complex left, Complex right)
        {
            return new Complex(left.m_real - right.m_real, left.m_imaginary - right.m_imaginary);
        }

        public static Complex operator -(Complex left, double right)
        {
            return new Complex(left.m_real - right, left.m_imaginary);
        }

        public static Complex operator -(double left, Complex right)
        {
            return new Complex(left - right.m_real, -right.m_imaginary);
        }

        public static Complex operator *(Complex left, Complex right)
        {
            // Multiplication:  (a + bi)(c + di) = (ac -bd) + (bc + ad)i
            double result_realpart = (left.m_real * right.m_real) - (left.m_imaginary * right.m_imaginary);
            double result_imaginarypart = (left.m_imaginary * right.m_real) + (left.m_real * right.m_imaginary);
            return new Complex(result_realpart, result_imaginarypart);
        }

        public static Complex operator *(Complex left, double right)
        {
            Complex<double> result = new Complex<double>(left.m_real, left.m_imaginary) * right;
            return new Complex(result.Real, result.Imaginary);
        }

        public static Complex operator *(double left, Complex right)
        {
            Complex<double> result = left * new Complex<double>(right.m_real, right.m_imaginary);
            return new Complex(result.Real, result.Imaginary);
        }

        public static Complex operator /(Complex left, Complex right)
        {
            Complex<double> result = new Complex<double>(left.m_real, left.m_imaginary) / new Complex<double>(right.m_real, right.m_imaginary);
            return new Complex(result.Real, result.Imaginary);
        }

        public static Complex operator /(Complex left, double right)
        {
            Complex<double> result = new Complex<double>(left.m_real, left.m_imaginary) / right;
            return new Complex(result.Real, result.Imaginary);
        }

        public static Complex operator /(double left, Complex right)
        {
            Complex<double> result = left / new Complex<double>(right.m_real, right.m_imaginary);
            return new Complex(result.Real, result.Imaginary);
        }

        public static double Abs(Complex value)
        {
            return double.Hypot(value.m_real, value.m_imaginary);
        }

        public static Complex Conjugate(Complex value)
        {
            // Conjugate of a Complex number: the conjugate of x+i*y is x-i*y
            return new Complex(value.m_real, -value.m_imaginary);
        }

        public static Complex Reciprocal(Complex value)
        {
            // Reciprocal of a Complex number : the reciprocal of x+i*y is 1/(x+i*y)
            if (value.m_real == 0 && value.m_imaginary == 0)
            {
                return Zero;
            }
            return One / value;
        }

        public static bool operator ==(Complex left, Complex right)
        {
            return left.m_real == right.m_real && left.m_imaginary == right.m_imaginary;
        }

        public static bool operator !=(Complex left, Complex right)
        {
            return left.m_real != right.m_real || left.m_imaginary != right.m_imaginary;
        }

        public override bool Equals([NotNullWhen(true)] object? obj)
        {
            return obj is Complex other && Equals(other);
        }

        public bool Equals(Complex value)
        {
            return m_real.Equals(value.m_real) && m_imaginary.Equals(value.m_imaginary);
        }

        public override int GetHashCode() => HashCode.Combine(m_real, m_imaginary);

        public override string ToString() => ToString(null, null);

        public string ToString([StringSyntax(StringSyntaxAttribute.NumericFormat)] string? format) => ToString(format, null);

        public string ToString(IFormatProvider? provider) => ToString(null, provider);

        public string ToString([StringSyntax(StringSyntaxAttribute.NumericFormat)] string? format, IFormatProvider? provider)
            => new Complex<double>(m_real, m_imaginary).ToString(format, provider);

        public static Complex Sin(Complex value)
        {
            (double sin, double cos) = Math.SinCos(value.m_real);
            return new Complex(sin * Math.Cosh(value.m_imaginary), cos * Math.Sinh(value.m_imaginary));
            // There is a known limitation with this algorithm: inputs that cause sinh and cosh to overflow, but for
            // which sin or cos are small enough that sin * cosh or cos * sinh are still representable, nonetheless
            // produce overflow. For example, Sin((0.01, 711.0)) should produce (~3.0E306, PositiveInfinity), but
            // instead produces (PositiveInfinity, PositiveInfinity).
        }

        public static Complex Sinh(Complex value)
        {
            // Use sinh(z) = -i sin(iz) to compute via sin(z).
            Complex sin = Sin(new Complex(-value.m_imaginary, value.m_real));
            return new Complex(sin.m_imaginary, -sin.m_real);
        }

        public static Complex Asin(Complex value)
        {
            Complex<double> result = Complex<double>.Asin(new Complex<double>(value.m_real, value.m_imaginary));
            return new Complex(result.Real, result.Imaginary);
        }

        public static Complex Cos(Complex value)
        {
            (double sin, double cos) = Math.SinCos(value.m_real);
            return new Complex(cos * Math.Cosh(value.m_imaginary), -sin * Math.Sinh(value.m_imaginary));
        }

        public static Complex Cosh(Complex value)
        {
            // Use cosh(z) = cos(iz) to compute via cos(z).
            return Cos(new Complex(-value.m_imaginary, value.m_real));
        }

        public static Complex Acos(Complex value)
        {
            Complex<double> result = Complex<double>.Acos(new Complex<double>(value.m_real, value.m_imaginary));
            return new Complex(result.Real, result.Imaginary);
        }

        public static Complex Tan(Complex value)
        {
            Complex<double> result = Complex<double>.Tan(new Complex<double>(value.m_real, value.m_imaginary));
            return new Complex(result.Real, result.Imaginary);
        }

        public static Complex Tanh(Complex value)
        {
            // Use tanh(z) = -i tan(iz) to compute via tan(z).
            Complex tan = Tan(new Complex(-value.m_imaginary, value.m_real));
            return new Complex(tan.m_imaginary, -tan.m_real);
        }

        public static Complex Atan(Complex value)
        {
            Complex two = new(2.0, 0.0);
            return (ImaginaryOne / two) * (Log(One - ImaginaryOne * value) - Log(One + ImaginaryOne * value));
        }

        public static bool IsFinite(Complex value) => double.IsFinite(value.m_real) && double.IsFinite(value.m_imaginary);

        public static bool IsInfinity(Complex value) => double.IsInfinity(value.m_real) || double.IsInfinity(value.m_imaginary);

        public static bool IsNaN(Complex value) => !IsInfinity(value) && !IsFinite(value);

        public static Complex Log(Complex value)
        {
            return new Complex(Math.Log(Abs(value)), Math.Atan2(value.m_imaginary, value.m_real));
        }

        public static Complex Log(Complex value, double baseValue)
        {
            return Log(value) / Log(baseValue);
        }

        public static Complex Log10(Complex value)
        {
            Complex tempLog = Log(value);
            return Scale(tempLog, InverseOfLog10);
        }

        public static Complex Exp(Complex value)
        {
            double expReal = Math.Exp(value.m_real);
            return FromPolarCoordinates(expReal, value.m_imaginary);
        }

        public static Complex Sqrt(Complex value)
        {
            Complex<double> result = Complex<double>.Sqrt(new Complex<double>(value.m_real, value.m_imaginary));
            return new Complex(result.Real, result.Imaginary);
        }

        public static Complex Pow(Complex value, Complex power)
        {
            Complex<double> result = Complex<double>.Pow(new Complex<double>(value.m_real, value.m_imaginary), new Complex<double>(power.m_real, power.m_imaginary));
            return new Complex(result.Real, result.Imaginary);
        }

        public static Complex Pow(Complex value, double power)
        {
            return Pow(value, new Complex(power, 0));
        }

        private static Complex Scale(Complex value, double factor)
        {
            double realResult = factor * value.m_real;
            double imaginaryResuilt = factor * value.m_imaginary;
            return new Complex(realResult, imaginaryResuilt);
        }

        //
        // Explicit Conversions To Complex
        //

        public static explicit operator Complex(decimal value)
        {
            return new Complex((double)value, 0.0);
        }

        /// <summary>Explicitly converts a <see cref="Int128" /> value to a double-precision complex number.</summary>
        /// <param name="value">The value to convert.</param>
        /// <returns><paramref name="value" /> converted to a double-precision complex number.</returns>
        public static explicit operator Complex(Int128 value)
        {
            return new Complex((double)value, 0.0);
        }

        public static explicit operator Complex(BigInteger value)
        {
            return new Complex((double)value, 0.0);
        }

        /// <summary>Explicitly converts a <see cref="UInt128" /> value to a double-precision complex number.</summary>
        /// <param name="value">The value to convert.</param>
        /// <returns><paramref name="value" /> converted to a double-precision complex number.</returns>
        [CLSCompliant(false)]
        public static explicit operator Complex(UInt128 value)
        {
            return new Complex((double)value, 0.0);
        }

        //
        // Implicit Conversions To Complex
        //

        public static implicit operator Complex(byte value)
        {
            return new Complex(value, 0.0);
        }

        /// <summary>Implicitly converts a <see cref="char" /> value to a double-precision complex number.</summary>
        /// <param name="value">The value to convert.</param>
        /// <returns><paramref name="value" /> converted to a double-precision complex number.</returns>
        public static implicit operator Complex(char value)
        {
            return new Complex(value, 0.0);
        }

        public static implicit operator Complex(double value)
        {
            return new Complex(value, 0.0);
        }

        /// <summary>Implicitly converts a <see cref="Half" /> value to a double-precision complex number.</summary>
        /// <param name="value">The value to convert.</param>
        /// <returns><paramref name="value" /> converted to a double-precision complex number.</returns>
        public static implicit operator Complex(Half value)
        {
            return new Complex((double)value, 0.0);
        }

        /// <summary>Implicitly converts a <see cref="BFloat16" /> value to a double-precision complex number.</summary>
        /// <param name="value">The value to convert.</param>
        /// <returns><paramref name="value" /> converted to a double-precision complex number.</returns>
        public static implicit operator Complex(BFloat16 value)
        {
            return new Complex((double)value, 0.0);
        }

        public static implicit operator Complex(short value)
        {
            return new Complex(value, 0.0);
        }

        public static implicit operator Complex(int value)
        {
            return new Complex(value, 0.0);
        }

        public static implicit operator Complex(long value)
        {
            return new Complex(value, 0.0);
        }

        /// <summary>Implicitly converts a <see cref="IntPtr" /> value to a double-precision complex number.</summary>
        /// <param name="value">The value to convert.</param>
        /// <returns><paramref name="value" /> converted to a double-precision complex number.</returns>
        public static implicit operator Complex(nint value)
        {
            return new Complex(value, 0.0);
        }

        [CLSCompliant(false)]
        public static implicit operator Complex(sbyte value)
        {
            return new Complex(value, 0.0);
        }

        public static implicit operator Complex(float value)
        {
            return new Complex(value, 0.0);
        }

        [CLSCompliant(false)]
        public static implicit operator Complex(ushort value)
        {
            return new Complex(value, 0.0);
        }

        [CLSCompliant(false)]
        public static implicit operator Complex(uint value)
        {
            return new Complex(value, 0.0);
        }

        [CLSCompliant(false)]
        public static implicit operator Complex(ulong value)
        {
            return new Complex(value, 0.0);
        }

        /// <summary>Implicitly converts a <see cref="UIntPtr" /> value to a double-precision complex number.</summary>
        /// <param name="value">The value to convert.</param>
        /// <returns><paramref name="value" /> converted to a double-precision complex number.</returns>
        [CLSCompliant(false)]
        public static implicit operator Complex(nuint value)
        {
            return new Complex(value, 0.0);
        }

        //
        // IAdditiveIdentity
        //

        /// <inheritdoc cref="IAdditiveIdentity{TSelf, TResult}.AdditiveIdentity" />
        static Complex IAdditiveIdentity<Complex, Complex>.AdditiveIdentity => new(0.0, 0.0);

        //
        // IDecrementOperators
        //

        /// <inheritdoc cref="IDecrementOperators{TSelf}.op_Decrement(TSelf)" />
        public static Complex operator --(Complex value) => value - One;

        //
        // IIncrementOperators
        //

        /// <inheritdoc cref="IIncrementOperators{TSelf}.op_Increment(TSelf)" />
        public static Complex operator ++(Complex value) => value + One;

        //
        // IMultiplicativeIdentity
        //

        /// <inheritdoc cref="IMultiplicativeIdentity{TSelf, TResult}.MultiplicativeIdentity" />
        static Complex IMultiplicativeIdentity<Complex, Complex>.MultiplicativeIdentity => new(1.0, 0.0);

        //
        // INumberBase
        //

        /// <inheritdoc cref="INumberBase{TSelf}.One" />
        static Complex INumberBase<Complex>.One => new(1.0, 0.0);

        /// <inheritdoc cref="INumberBase{TSelf}.Radix" />
        static int INumberBase<Complex>.Radix => 2;

        /// <inheritdoc cref="INumberBase{TSelf}.Zero" />
        static Complex INumberBase<Complex>.Zero => new(0.0, 0.0);

        /// <inheritdoc cref="INumberBase{TSelf}.Abs(TSelf)" />
        static Complex INumberBase<Complex>.Abs(Complex value) => Abs(value);

        /// <inheritdoc cref="INumberBase{TSelf}.CreateChecked{TOther}(TOther)" />
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static Complex CreateChecked<TOther>(TOther value)
            where TOther : INumberBase<TOther>
        {
            Complex result;

            if (typeof(TOther) == typeof(Complex))
            {
                result = (Complex)(object)value;
            }
            else if (!TryConvertFrom(value, out result) && !TOther.TryConvertToChecked(value, out result))
            {
                ThrowHelper.ThrowNotSupportedException();
            }

            return result;
        }

        /// <inheritdoc cref="INumberBase{TSelf}.CreateSaturating{TOther}(TOther)" />
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static Complex CreateSaturating<TOther>(TOther value)
            where TOther : INumberBase<TOther>
        {
            Complex result;

            if (typeof(TOther) == typeof(Complex))
            {
                result = (Complex)(object)value;
            }
            else if (!TryConvertFrom(value, out result) && !TOther.TryConvertToSaturating(value, out result))
            {
                ThrowHelper.ThrowNotSupportedException();
            }

            return result;
        }

        /// <inheritdoc cref="INumberBase{TSelf}.CreateTruncating{TOther}(TOther)" />
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static Complex CreateTruncating<TOther>(TOther value)
            where TOther : INumberBase<TOther>
        {
            Complex result;

            if (typeof(TOther) == typeof(Complex))
            {
                result = (Complex)(object)value;
            }
            else if (!TryConvertFrom(value, out result) && !TOther.TryConvertToTruncating(value, out result))
            {
                ThrowHelper.ThrowNotSupportedException();
            }

            return result;
        }

        /// <inheritdoc cref="INumberBase{TSelf}.IsCanonical(TSelf)" />
        static bool INumberBase<Complex>.IsCanonical(Complex value) => true;

        /// <inheritdoc cref="INumberBase{TSelf}.IsComplexNumber(TSelf)" />
        public static bool IsComplexNumber(Complex value) => (value.m_real != 0.0) && (value.m_imaginary != 0.0);

        /// <inheritdoc cref="INumberBase{TSelf}.IsEvenInteger(TSelf)" />
        public static bool IsEvenInteger(Complex value) => (value.m_imaginary == 0) && double.IsEvenInteger(value.m_real);

        /// <inheritdoc cref="INumberBase{TSelf}.IsImaginaryNumber(TSelf)" />
        public static bool IsImaginaryNumber(Complex value) => (value.m_real == 0.0) && double.IsRealNumber(value.m_imaginary);

        /// <inheritdoc cref="INumberBase{TSelf}.IsInteger(TSelf)" />
        public static bool IsInteger(Complex value) => (value.m_imaginary == 0) && double.IsInteger(value.m_real);

        /// <inheritdoc cref="INumberBase{TSelf}.IsNegative(TSelf)" />
        public static bool IsNegative(Complex value)
        {
            // since complex numbers do not have a well-defined concept of
            // negative we report false if this value has an imaginary part

            return (value.m_imaginary == 0.0) && double.IsNegative(value.m_real);
        }

        /// <inheritdoc cref="INumberBase{TSelf}.IsNegativeInfinity(TSelf)" />
        public static bool IsNegativeInfinity(Complex value)
        {
            // since complex numbers do not have a well-defined concept of
            // negative we report false if this value has an imaginary part

            return (value.m_imaginary == 0.0) && double.IsNegativeInfinity(value.m_real);
        }

        /// <inheritdoc cref="INumberBase{TSelf}.IsNormal(TSelf)" />
        public static bool IsNormal(Complex value)
        {
            // much as IsFinite requires both part to be finite, we require both
            // part to be "normal" (finite, non-zero, and non-subnormal) to be true

            return double.IsNormal(value.m_real)
                && ((value.m_imaginary == 0.0) || double.IsNormal(value.m_imaginary));
        }

        /// <inheritdoc cref="INumberBase{TSelf}.IsOddInteger(TSelf)" />
        public static bool IsOddInteger(Complex value) => (value.m_imaginary == 0) && double.IsOddInteger(value.m_real);

        /// <inheritdoc cref="INumberBase{TSelf}.IsPositive(TSelf)" />
        public static bool IsPositive(Complex value)
        {
            // since complex numbers do not have a well-defined concept of
            // negative we report false if this value has an imaginary part

            return (value.m_imaginary == 0.0) && double.IsPositive(value.m_real);
        }

        /// <inheritdoc cref="INumberBase{TSelf}.IsPositiveInfinity(TSelf)" />
        public static bool IsPositiveInfinity(Complex value)
        {
            // since complex numbers do not have a well-defined concept of
            // positive we report false if this value has an imaginary part

            return (value.m_imaginary == 0.0) && double.IsPositiveInfinity(value.m_real);
        }

        /// <inheritdoc cref="INumberBase{TSelf}.IsRealNumber(TSelf)" />
        public static bool IsRealNumber(Complex value) => (value.m_imaginary == 0.0) && double.IsRealNumber(value.m_real);

        /// <inheritdoc cref="INumberBase{TSelf}.IsSubnormal(TSelf)" />
        public static bool IsSubnormal(Complex value)
        {
            // much as IsInfinite allows either part to be infinite, we allow either
            // part to be "subnormal" (finite, non-zero, and non-normal) to be true

            return double.IsSubnormal(value.m_real) || double.IsSubnormal(value.m_imaginary);
        }

        /// <inheritdoc cref="INumberBase{TSelf}.IsZero(TSelf)" />
        static bool INumberBase<Complex>.IsZero(Complex value) => (value.m_real == 0.0) && (value.m_imaginary == 0.0);

        /// <inheritdoc cref="INumberBase{TSelf}.MaxMagnitude(TSelf, TSelf)" />
        public static Complex MaxMagnitude(Complex x, Complex y)
        {
            Complex<double> result = Complex<double>.MaxMagnitude(new Complex<double>(x.m_real, x.m_imaginary), new Complex<double>(y.m_real, y.m_imaginary));
            return new Complex(result.Real, result.Imaginary);
        }

        /// <inheritdoc cref="INumberBase{TSelf}.MaxMagnitudeNumber(TSelf, TSelf)" />
        static Complex INumberBase<Complex>.MaxMagnitudeNumber(Complex x, Complex y)
        {
            Complex<double> result = Complex<double>.MaxMagnitudeNumber(new Complex<double>(x.m_real, x.m_imaginary), new Complex<double>(y.m_real, y.m_imaginary));
            return new Complex(result.Real, result.Imaginary);
        }

        /// <inheritdoc cref="INumberBase{TSelf}.MinMagnitude(TSelf, TSelf)" />
        public static Complex MinMagnitude(Complex x, Complex y)
        {
            Complex<double> result = Complex<double>.MinMagnitude(new Complex<double>(x.m_real, x.m_imaginary), new Complex<double>(y.m_real, y.m_imaginary));
            return new Complex(result.Real, result.Imaginary);
        }

        /// <inheritdoc cref="INumberBase{TSelf}.MinMagnitudeNumber(TSelf, TSelf)" />
        static Complex INumberBase<Complex>.MinMagnitudeNumber(Complex x, Complex y)
        {
            Complex<double> result = Complex<double>.MinMagnitudeNumber(new Complex<double>(x.m_real, x.m_imaginary), new Complex<double>(y.m_real, y.m_imaginary));
            return new Complex(result.Real, result.Imaginary);
        }

        /// <inheritdoc cref="INumberBase{TSelf}.MultiplyAddEstimate(TSelf, TSelf, TSelf)" />
        static Complex INumberBase<Complex>.MultiplyAddEstimate(Complex left, Complex right, Complex addend)
        {
            Complex<double> result = Complex<double>.MultiplyAddEstimate(new Complex<double>(left.m_real, left.m_imaginary), new Complex<double>(right.m_real, right.m_imaginary), new Complex<double>(addend.m_real, addend.m_imaginary));
            return new Complex(result.Real, result.Imaginary);
        }

        /// <inheritdoc cref="INumberBase{TSelf}.Parse(ReadOnlySpan{char}, NumberStyles, IFormatProvider?)" />
        public static Complex Parse(ReadOnlySpan<char> s, NumberStyles style, IFormatProvider? provider)
        {
            if (!TryParse(s, style, provider, out Complex result))
            {
                ThrowHelper.ThrowOverflowException();
            }
            return result;
        }

        /// <inheritdoc cref="INumberBase{TSelf}.Parse(ReadOnlySpan{byte}, NumberStyles, IFormatProvider?)" />
        public static Complex Parse(ReadOnlySpan<byte> utf8Text, NumberStyles style, IFormatProvider? provider)
        {
            if (!TryParse(utf8Text, style, provider, out Complex result))
            {
                ThrowHelper.ThrowOverflowException();
            }
            return result;
        }

        /// <inheritdoc cref="INumberBase{TSelf}.Parse(string, NumberStyles, IFormatProvider?)" />
        public static Complex Parse(string s, NumberStyles style, IFormatProvider? provider)
        {
            ArgumentNullException.ThrowIfNull(s);
            return Parse(s.AsSpan(), style, provider);
        }

        /// <inheritdoc cref="INumberBase{TSelf}.TryConvertFromChecked{TOther}(TOther, out TSelf)" />
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        static bool INumberBase<Complex>.TryConvertFromChecked<TOther>(TOther value, out Complex result)
        {
            return TryConvertFrom<TOther>(value, out result);
        }

        /// <inheritdoc cref="INumberBase{TSelf}.TryConvertFromSaturating{TOther}(TOther, out TSelf)" />
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        static bool INumberBase<Complex>.TryConvertFromSaturating<TOther>(TOther value, out Complex result)
        {
            return TryConvertFrom<TOther>(value, out result);
        }

        /// <inheritdoc cref="INumberBase{TSelf}.TryConvertFromTruncating{TOther}(TOther, out TSelf)" />
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        static bool INumberBase<Complex>.TryConvertFromTruncating<TOther>(TOther value, out Complex result)
        {
            return TryConvertFrom<TOther>(value, out result);
        }

        private static bool TryConvertFrom<TOther>(TOther value, out Complex result)
            where TOther : INumberBase<TOther>
        {
            if (typeof(TOther) == typeof(Complex<double>))
            {
                Complex<double> actualValue = (Complex<double>)(object)value;
                result = new Complex(actualValue.Real, actualValue.Imaginary);
                return true;
            }

            if (Complex<double>.TryConvertFromCheckedCore(value, out Complex<double> intermediate))
            {
                result = new Complex(intermediate.Real, intermediate.Imaginary);
                return true;
            }

            result = default;
            return false;
        }

        /// <inheritdoc cref="INumberBase{TSelf}.TryConvertToChecked{TOther}(TSelf, out TOther)" />
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        static bool INumberBase<Complex>.TryConvertToChecked<TOther>(Complex value, [MaybeNullWhen(false)] out TOther result)
        {
            if (typeof(TOther) == typeof(Complex<double>))
            {
                result = (TOther)(object)new Complex<double>(value.m_real, value.m_imaginary);
                return true;
            }

            return Complex<double>.TryConvertToCheckedCore(new Complex<double>(value.m_real, value.m_imaginary), out result);
        }

        /// <inheritdoc cref="INumberBase{TSelf}.TryConvertToSaturating{TOther}(TSelf, out TOther)" />
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        static bool INumberBase<Complex>.TryConvertToSaturating<TOther>(Complex value, [MaybeNullWhen(false)] out TOther result)
        {
            if (typeof(TOther) == typeof(Complex<double>))
            {
                result = (TOther)(object)new Complex<double>(value.m_real, value.m_imaginary);
                return true;
            }

            return Complex<double>.TryConvertToSaturatingCore(new Complex<double>(value.m_real, value.m_imaginary), out result);
        }

        /// <inheritdoc cref="INumberBase{TSelf}.TryConvertToTruncating{TOther}(TSelf, out TOther)" />
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        static bool INumberBase<Complex>.TryConvertToTruncating<TOther>(Complex value, [MaybeNullWhen(false)] out TOther result)
        {
            if (typeof(TOther) == typeof(Complex<double>))
            {
                result = (TOther)(object)new Complex<double>(value.m_real, value.m_imaginary);
                return true;
            }

            return Complex<double>.TryConvertToTruncatingCore(new Complex<double>(value.m_real, value.m_imaginary), out result);
        }

        /// <inheritdoc cref="INumberBase{TSelf}.TryParse(ReadOnlySpan{char}, NumberStyles, IFormatProvider?, out TSelf)" />
        public static bool TryParse(ReadOnlySpan<char> s, NumberStyles style, IFormatProvider? provider, out Complex result)
        {
            Unsafe.SkipInit(out result);
            return Complex<double>.TryParse(MemoryMarshal.Cast<char, Utf16Char>(s), style, provider, out Unsafe.As<Complex, Complex<double>>(ref result), out _);
        }

        /// <inheritdoc cref="INumberBase{TSelf}.TryParse(ReadOnlySpan{byte}, NumberStyles, IFormatProvider?, out TSelf)" />
        public static bool TryParse(ReadOnlySpan<byte> utf8Text, NumberStyles style, IFormatProvider? provider, out Complex result)
        {
            Unsafe.SkipInit(out result);
            return Complex<double>.TryParse(MemoryMarshal.Cast<byte, Utf8Char>(utf8Text), style, provider, out Unsafe.As<Complex, Complex<double>>(ref result), out _);
        }

        /// <inheritdoc cref="INumberBase{TSelf}.TryParse(string, NumberStyles, IFormatProvider?, out TSelf, out int)" />
        static bool INumberBase<Complex>.TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, out Complex result, out int charsConsumed)
        {
            Unsafe.SkipInit(out result);
            return Complex<double>.TryParse(MemoryMarshal.Cast<char, Utf16Char>(s.AsSpan()), style, provider, out Unsafe.As<Complex, Complex<double>>(ref result), out charsConsumed);
        }

        /// <inheritdoc cref="INumberBase{TSelf}.TryParse(ReadOnlySpan{byte}, NumberStyles, IFormatProvider?, out TSelf, out int)" />
        static bool INumberBase<Complex>.TryParse(ReadOnlySpan<byte> utf8Text, NumberStyles style, IFormatProvider? provider, out Complex result, out int bytesConsumed)
        {
            Unsafe.SkipInit(out result);
            return Complex<double>.TryParse(MemoryMarshal.Cast<byte, Utf8Char>(utf8Text), style, provider, out Unsafe.As<Complex, Complex<double>>(ref result), out bytesConsumed);
        }

        /// <inheritdoc cref="INumberBase{TSelf}.TryParse(ReadOnlySpan{char}, NumberStyles, IFormatProvider?, out TSelf, out int)" />
        static bool INumberBase<Complex>.TryParse(ReadOnlySpan<char> s, NumberStyles style, IFormatProvider? provider, out Complex result, out int charsConsumed)
        {
            Unsafe.SkipInit(out result);
            return Complex<double>.TryParse(MemoryMarshal.Cast<char, Utf16Char>(s), style, provider, out Unsafe.As<Complex, Complex<double>>(ref result), out charsConsumed);
        }

        /// <inheritdoc cref="INumberBase{TSelf}.TryParse(string, NumberStyles, IFormatProvider?, out TSelf)" />
        public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, out Complex result)
        {
            return TryParse(s.AsSpan(), style, provider, out result);
        }

        //
        // IParsable
        //

        /// <inheritdoc cref="IParsable{TSelf}.Parse(string, IFormatProvider?)" />
        public static Complex Parse(string s, IFormatProvider? provider) => Parse(s, DefaultNumberStyle, provider);

        /// <inheritdoc cref="IParsable{TSelf}.TryParse(string?, IFormatProvider?, out TSelf)" />
        public static bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, out Complex result) => TryParse(s, DefaultNumberStyle, provider, out result);

        //
        // ISignedNumber
        //

        /// <inheritdoc cref="ISignedNumber{TSelf}.NegativeOne" />
        static Complex ISignedNumber<Complex>.NegativeOne => new(-1.0, 0.0);

        //
        // ISpanFormattable
        //

        /// <inheritdoc cref="ISpanFormattable.TryFormat(Span{char}, out int, ReadOnlySpan{char}, IFormatProvider?)" />
        public bool TryFormat(Span<char> destination, out int charsWritten, [StringSyntax(StringSyntaxAttribute.NumericFormat)] ReadOnlySpan<char> format = default, IFormatProvider? provider = null) =>
            TryFormat(MemoryMarshal.Cast<char, Utf16Char>(destination), out charsWritten, format, provider);

        /// <inheritdoc cref="IUtf8SpanFormattable.TryFormat(Span{byte}, out int, ReadOnlySpan{char}, IFormatProvider?)" />
        public bool TryFormat(Span<byte> utf8Destination, out int bytesWritten, [StringSyntax(StringSyntaxAttribute.NumericFormat)] ReadOnlySpan<char> format = default, IFormatProvider? provider = null) =>
            TryFormat(MemoryMarshal.Cast<byte, Utf8Char>(utf8Destination), out bytesWritten, format, provider);

        private bool TryFormat<TChar>(Span<TChar> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider? provider)
            where TChar : unmanaged, IUtfChar<TChar>
        {
            Debug.Assert(typeof(TChar) == typeof(Utf8Char) || typeof(TChar) == typeof(Utf16Char));

            // We have at least 6 more characters for: <0; 0>
            if (destination.Length >= 6)
            {
                if ((typeof(TChar) == typeof(Utf8Char))
                    ? m_real.TryFormat(Unsafe.BitCast<Span<TChar>, Span<byte>>(destination.Slice(1)), out int realChars, format, provider)
                    : m_real.TryFormat(Unsafe.BitCast<Span<TChar>, Span<char>>(destination.Slice(1)), out realChars, format, provider))
                {
                    destination[0] = TChar.CastFrom('<');
                    destination = destination.Slice(1 + realChars); // + 1 for <

                    // We have at least 4 more characters for: ; 0>
                    if (destination.Length >= 4)
                    {
                        if ((typeof(TChar) == typeof(Utf8Char))
                            ? m_imaginary.TryFormat(Unsafe.BitCast<Span<TChar>, Span<byte>>(destination.Slice(2)), out int imaginaryChars, format, provider)
                            : m_imaginary.TryFormat(Unsafe.BitCast<Span<TChar>, Span<char>>(destination.Slice(2)), out imaginaryChars, format, provider))
                        {
                            // We have 1 more character for: >
                            if ((uint)(2 + imaginaryChars) < (uint)destination.Length)
                            {
                                destination[0] = TChar.CastFrom(';');
                                destination[1] = TChar.CastFrom(' ');
                                destination[2 + imaginaryChars] = TChar.CastFrom('>');

                                charsWritten = realChars + imaginaryChars + 4;
                                return true;
                            }
                        }
                    }
                }
            }

            charsWritten = 0;
            return false;
        }

        //
        // ISpanParsable
        //

        /// <inheritdoc cref="ISpanParsable{TSelf}.Parse(ReadOnlySpan{char}, IFormatProvider?)" />
        public static Complex Parse(ReadOnlySpan<char> s, IFormatProvider? provider) => Parse(s, DefaultNumberStyle, provider);

        /// <inheritdoc cref="ISpanParsable{TSelf}.TryParse(ReadOnlySpan{char}, IFormatProvider?, out TSelf)" />
        public static bool TryParse(ReadOnlySpan<char> s, IFormatProvider? provider, out Complex result) => TryParse(s, DefaultNumberStyle, provider, out result);

        //
        // IUnaryPlusOperators
        //

        /// <inheritdoc cref="IUnaryPlusOperators{TSelf, TResult}.op_UnaryPlus(TSelf)" />
        public static Complex operator +(Complex value) => value;

        //
        // IUtf8SpanParsable
        //

        /// <inheritdoc cref="IUtf8SpanParsable{TSelf}.Parse(ReadOnlySpan{byte}, IFormatProvider?)" />
        public static Complex Parse(ReadOnlySpan<byte> utf8Text, IFormatProvider? provider) => Parse(utf8Text, DefaultNumberStyle, provider);

        /// <inheritdoc cref="IUtf8SpanParsable{TSelf}.TryParse(ReadOnlySpan{byte}, IFormatProvider?, out TSelf)" />
        public static bool TryParse(ReadOnlySpan<byte> utf8Text, IFormatProvider? provider, out Complex result) => TryParse(utf8Text, DefaultNumberStyle, provider, out result);
    }
}