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;
}
}
}