C# 复数类 Complex

1. 前言

在.net 中没有提供复数类的操作。第三方库Math.net中包含了复数的相关定义、矩阵、线性代数以及傅里叶变换等一整套数学操作。但当项目中只需简单计算复数时,引入库并非较好的选择,重新手写一个复数类效率更高,与项目的契合度也更好。

2. 复数类布局思路和代码实现

复数类编写不具有很大难度,但多数复数类均只支持使用实部虚部模式构造一个复数,而幅值相位模式也是构造复数的一个方式。现给出可以满足两种方法构造的复数类实现:

using System;
namespace MathUtil
{
    public struct Complex : IComparable, IFormattable, IComparable<Complex>, IEquatable<Complex>
    {
        //一些有用的常量
        private const double DoublePI = 2 * Math.PI;
        private const double NegativePI = -1 * Math.PI;

        public const double RadToDeg = 180.0 / Math.PI;
        public const double DegToRad = Math.PI / 180.0;
        //字段
        private double _real;
        private double _imag;
        private double _magnitude;
        private double _phase;
        //私有的构造函数,外部不能直接通过含参的构造函数创建复数
        private Complex(double real, double imag, double magnitude, double phase) : this()
        {
            _real = real;
            _imag = imag;
            _magnitude = magnitude;
            _phase = phase;
        }
        //实部虚部和幅值相位,获取时直接获取,设置时进行更新
        public double Real
        {
            get => _real;
            set
            {
                _real = value;
                this.UpdateFromRealImagMode();
            }
        }
        public double Imag
        {
            get => _imag;
            set
            {
                _imag = value;
                this.UpdateFromRealImagMode();
            }
        }

        public double Magnitude
        {
            get => _magnitude;
            set
            {
                _magnitude = value;
                this.UpdateFromMagniPhaseMode();
            }
        }
        public double Phase
        {
            get => _phase;
            set
            {
                _phase = value;
                this.UpdateFromMagniPhaseMode();
            }
        }
        //共轭复数,使用静态的工厂方法创建(工厂方法在下方)
        public Complex Conjugate => Complex.FromRealImagMode(this._real, -1 * this._imag);
        //判断值是否为非数字
        public bool IsNaN => Double.IsNaN(this._real) || Double.IsNaN(this._imag);
        //这里使用私有构造直接创建NaN的Complex
        public static Complex NaN => new Complex(Double.NaN, Double.NaN, Double.NaN, Double.NaN);
        //转换为NaN的Complex, 此处使用 ref 直接获取引用
        public static void ToNaN(ref Complex target)
        {
            target._real = Double.NaN;
            target._imag = Double.NaN;
            target._magnitude = Double.NaN;
            target._phase = Double.NaN;
        }
        //复制值, 此处使用 ref 直接获取引用
        public static void CopyValue(ref Complex target, ref Complex source)
        {
            target._real = source._real;
            target._imag = source._imag;
            target._magnitude = source._magnitude;
            target._phase = source._phase;
        }
        //静态的工厂方法,共两种
        public static Complex FromRealImagMode(double real, double imag = 0.0)
        {
            double magnitude = 0;
            double phase = 0;
            if (real != 0 || imag != 0)
            {
                magnitude = Math.Sqrt(real * real + imag * imag);
                phase = Math.Atan2(imag, real);
            }
            return new Complex(real, imag, magnitude, phase);
        }

        public static Complex FromMagniPhaseMode(double magnitude, double phase = 0.0)
        {
            double real = 0;
            double imag = 0;
            if (magnitude != 0)
            {
                if (phase != 0)
                {
                    real = magnitude * Math.Cos(phase);
                    imag = magnitude * Math.Sin(phase);
                }
                else
                {
                    real = magnitude;
                }
            }
            return new Complex(real, imag, magnitude, phase);
        }
        //静态的修改值的方法,适用于同时修改复数的两个部分,减少一次更新计算
        public static void ModifyFromRealImagMode(ref Complex complex, double real, double imag)
        {
            complex._real = real;
            complex._imag = imag;
            complex.UpdateFromRealImagMode();
        }

        public static void ModifyFromMagniPhaseMode(ref Complex complex, double magnitude, double phase)
        {
            complex._magnitude = magnitude;
            complex._phase = phase;
            complex.UpdateFromMagniPhaseMode();
        }
        //加法
        public static Complex Addition(ref Complex complex1, ref Complex complex2)
        {
            Complex complex = new Complex
            {
                _real = complex1._real + complex2._real,
                _imag = complex1._imag + complex2._imag
            };
            complex.UpdateFromRealImagMode();
            return complex;
        }
        public static Complex Addition(ref Complex complex1, ref double value)
        {
            Complex complex = new Complex();
            if (value == 0)
            {
                Complex.CopyValue(ref complex, ref complex1);
                return complex;
            }
            complex._real = complex1._real + value;
            complex._imag = complex1._imag;
            complex.UpdateFromRealImagMode();
            return complex;
        }
        //加号运算符重载
        public static Complex operator +(Complex complex1, Complex complex2) => Complex.Addition(ref complex1, ref complex2);
        public static Complex operator +(Complex complex1, double value) => Complex.Addition(ref complex1, ref value);
        public static Complex operator +(double value, Complex complex1) => Complex.Addition(ref complex1, ref value);
        //减法
        public static Complex Subtraction(ref Complex complex1, ref Complex complex2)
        {
            Complex complex = new Complex
            {
                _real = complex1._real - complex2._real,
                _imag = complex1._imag - complex2._imag
            };
            complex.UpdateFromRealImagMode();
            return complex;
        }
        public static Complex Subtraction(ref Complex complex1, ref double value)
        {
            Complex complex = new Complex();
            if (value == 0)
            {
                Complex.CopyValue(ref complex, ref complex1);
                return complex;
            }
            complex._real = complex1._real - value;
            complex._imag = complex1._imag;
            complex.UpdateFromRealImagMode();
            return complex;
        }
        public static Complex Subtraction(ref double value, ref Complex complex1)
        {
            Complex complex = new Complex();
            if (value == 0)
            {
                Complex.CopyValue(ref complex, ref complex1);
                return complex;
            }
            complex._real = value - complex1._real;
            complex._imag = complex1._imag;
            complex.UpdateFromRealImagMode();
            return complex;
        }
        //减号运算符重载
        public static Complex operator -(Complex complex1, Complex complex2) => Complex.Subtraction(ref complex1, ref complex2);
        public static Complex operator -(Complex complex1, double value) => Complex.Subtraction(ref complex1, ref value);
        public static Complex operator -(double value, Complex complex1) => Complex.Subtraction(ref value, ref complex1);
        //乘法,当两复数相乘时,使用复数特性:复数相乘 = 幅值相乘 && 相角相加
        public static Complex Multiplication(ref Complex complex1, ref Complex complex2)
        {
            Complex complex = new Complex
            {
                _magnitude = complex1._magnitude * complex2._magnitude,
                _phase = complex1._phase + complex2._phase
            };
            EnsurePhaseInRange(ref complex._phase);
            complex.UpdateFromMagniPhaseMode();
            return complex;
        }
        public static Complex Multiplication(ref Complex complex1, ref double value)
        {
            Complex complex = new Complex();
            if (value == 0)
            {
                return complex;
            }
            else if (value == 1)
            {
                Complex.CopyValue(ref complex, ref complex1);
            }
            else
            {
                complex._real = value * complex1._real;
                complex._imag = value * complex1._imag;
                complex.UpdateFromRealImagMode();
            }
            return complex;
        }
        //乘号运算符重载
        public static Complex operator *(Complex complex1, Complex complex2) => Complex.Multiplication(ref complex1, ref complex2);
        public static Complex operator *(Complex complex1, double value) => Complex.Multiplication(ref complex1, ref value);
        public static Complex operator *(double value, Complex complex1) => Complex.Multiplication(ref complex1, ref value);
        //除法,当两复数相除时,使用复数特性:复数相除 = 幅值相除 && 相角相减;此处允许被除数为0,即允许结果为非数字或无穷
        public static Complex Division(ref Complex complex1, ref Complex complex2)
        {
            Complex complex = new Complex
            {
                _magnitude = complex1._magnitude / complex2._magnitude,
                _phase = complex1._phase - complex2._phase
            };
            EnsurePhaseInRange(ref complex._phase);
            complex.UpdateFromMagniPhaseMode();
            return complex;
        }
        public static Complex Division(ref Complex complex1, ref double value)
        {
            Complex complex = new Complex();
            if (value == 1)
            {
                Complex.CopyValue(ref complex, ref complex1);
            }
            else
            {
                complex._real = complex1._real / value;
                complex._imag = complex1._imag / value;
                complex.UpdateFromRealImagMode();
            }
            return complex;
        }
        public static Complex Division(ref double value, ref Complex complex1)
        {
            Complex complex = new Complex();
            if (value == 1)
            {
                Complex.CopyValue(ref complex, ref complex1);
            }
            else
            {
                complex._real = value / complex1._real;
                complex._imag = value / complex1._imag;
                complex.UpdateFromRealImagMode();
            }
            return complex;
        }
        //除号运算符重载
        public static Complex operator /(Complex complex1, Complex complex2) => Complex.Division(ref complex1, ref complex2);
        public static Complex operator /(Complex complex1, double value) => Complex.Division(ref complex1, ref value);
        public static Complex operator /(double value, Complex complex1) => Complex.Division(ref value, ref complex1);
        //隐式类型转换,允许double值隐式的转换为复数
        public static implicit operator Complex(double value) 
            => new Complex() { _real = value, _magnitude = value };
        //强制类型转换,可以使用强制类型转换将复数转换为double值,该double值为其幅值
        public static explicit operator double(Complex complex) 
            => complex._magnitude;
        //确保相位在闭区间 [-pi, pi] 之间
        private static void EnsurePhaseInRange(ref double phase)
        {
            if (phase < Complex.NegativePI || phase > Math.PI)
            {
                phase = phase - Math.Truncate(phase / Complex.DoublePI + 0.5) * Complex.DoublePI;
            }
        }
        //批量输出值
        public static void OutputRealImagValue(ref Complex complex, out double part1, out double part2)
        {
            part1 = complex._real;
            part2 = complex._imag;
        }

        public static void OutputMagniPhaseValue(ref Complex complex, out double part1, out double part2)
        {
            part1 = complex._magnitude;
            part2 = complex._phase;
        }
        //以角度制获取相位值
        public double GetDegreeOfPhase()
        {
            return this._phase == 0 || Double.IsNaN(this._phase) 
                ? this._phase 
                : this._phase * Complex.RadToDeg;
        }
        //以角度制设置相位值
        public void SetDegreeOfPhase(double phaseInDegreeUnit)
        {
            this._phase = phaseInDegreeUnit == 0 || Double.IsNaN(phaseInDegreeUnit) 
                ? phaseInDegreeUnit 
                : phaseInDegreeUnit * Complex.DegToRad;
            this.UpdateFromMagniPhaseMode();
        }
        //用于更新值的方法
        private void UpdateFromRealImagMode()
        {
            if (_real == 0 && _imag == 0)
            {
                _magnitude = 0;
                _phase = 0;
            }
            else if (_imag == 0)
            {
                _magnitude = _real;
                _phase = 0;
            }
            else
            {
                _magnitude = Math.Sqrt(_real * _real + _imag * _imag);
                _phase = Math.Atan2(_imag, _real);
            }
        }

        private void UpdateFromMagniPhaseMode()
        {
            if (_magnitude == 0)
            {
                _real = 0;
                _imag = 0;
                return;
            }
            if (_phase == 0)
            {
                _real = _magnitude;
                _imag = 0;
                return;
            }
            _real = _magnitude * Math.Cos(_phase);
            _imag = _magnitude * Math.Sin(_phase);
        }
        //接口实现
        public int CompareTo(object obj)
        {
            return this._magnitude.CompareTo(obj);
        }

        public override string ToString() 
            => string.Format("/{{0},{1}/}", this._real, this._imag);

        public string ToString(string format, IFormatProvider formatProvider)
        {
            return string.Format(
                format,
                string.Format(
                    "/{{0},{1}/}",
                    this._real.ToString(formatProvider),
                    this._imag.ToString(formatProvider)
                    )
                );
        }

        public int CompareTo(Complex other)
        {
            return this._magnitude.CompareTo(other._magnitude);
        }

        public bool Equals(Complex other)
        {
            return this._real == other._real && this._imag == other._imag;
        }
    }
}

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容