有了这么多的铺垫,复数这个东西,应该很熟悉了。
但是这里总是有点问题,就是,我们明明知道,我们用的复数不是真的。它之所以必须写成a+bi的形式,终究是因为周期有多大是不知道的。一般来说就是太大了或者太小了,无法度量。
但是基于可数性的周期性的存在要求它必须是有数值的,就算无法度量也是有数值的。
我们把这个巨大的数量当成归零(0)的条件,那么比它小一个单位的,就认为是最大的可度量数值。
而这个数值就是0-1=-1,为了更精细的度量,我们对这个数值和单位1的乘积,求几何平方根,就得到虚数单位i,可是我们知道,它其实就是最大数值减去1之后再乘以1之后的平方根。
而反过来说,这个周期的大小就是虚数单位(半周期)的平方加一。
既然这些都已经知道了,那么对于一个我们无法直接给出度量的数量,实际上我们也有了可以度量的方式,虽然这种做法不一定正确(如何定义正确本身就是一个问题),但是这种做法完全可行。
既然如此,我们为什么不把这个周期记录下来作为复数的一部分,这时候这个复数就完整了。
这时候就可以写出,
n = a+bi=a+b*semicycle
按照这个想法,写出一个类,代码如下。
主要考虑的就是当两个周期性复数的周期不一样的时候,要怎么处理。
这里用了一个最简单的处理方法,就是向着更大的周期对齐。这种做法是处理量最小的做法。
因为如果向着更小的周期对齐,可能引入多余的卷曲。
写代码的好处,在于可以帮助人看出问题。
这个semicycle,也就是半周期,实际上就是虚数单位。
那么既然虚数单位已经给出有限数值,那么数值就有大小的问题。
我们知道复数的实部就是实数,它是不可能大于半周期的。
如果它比半周期大,就得把它模半周期并取余数作为新的实部。
而虚部则要加上它比上半周期的结果的取整数值。
这就使得半周期成了实部的上限。
另外,实部也不能比半周期的倒数小,若是比半周期的倒数还小,
它就应当被认为是0。
可见这里面,对于过大和过小的处理方式是不对称的。
而这一点正好和我们的神经系统处理信号的模式相似:
低于阈值的不触发神经脉冲,高于阈值的可多次触发神经脉冲。
从这个角度理解,数学描述的其实也不是自然规律,而是我们自己的神经系统的工作模式。
具体看代码吧。
using System.Numerics;
using System.Globalization;
public readonly struct CyclicalComplex(double real, double imaginary, double semicycle = CyclicalComplex.DefaultSemicycle) : IEquatable<CyclicalComplex>, IFormattable
{
private readonly double real = real;
private readonly double imaginary = imaginary;
private readonly double semicycle = semicycle > 1 ?
semicycle : throw new ArgumentOutOfRangeException(nameof(semicycle), "Semicycle must be greater than 1.")
;
private const double LOG_10_INV = 0.43429448190325;
public const double DefaultSemicycle = 1.34078079299426e+154;//Math.Sqrt(double.MaxValue)
public static readonly CyclicalComplex Zero = new(0.0, 0.0, DefaultSemicycle);
public static readonly CyclicalComplex One = new(1.0, 0.0, DefaultSemicycle);
public static readonly CyclicalComplex ImaginaryOne = new(0.0, 1.0, DefaultSemicycle);
public double Real => this.real;
public double Imaginary => this.imaginary;
public double Semicycle => this.semicycle;
public double SemicycleSquared => this.semicycle * this.semicycle;
public double SemicycleInverse => 1.0 / this.semicycle;
public double Cycle => this.SemicycleSquared + 1;
public double Magnitude => Abs(this);
public double Phase => Math.Atan2(this.imaginary, this.real);
public double PhaseDegrees => Phase * (180.0 / Math.PI);
public double Integral => Math.FusedMultiplyAdd(this.imaginary, this.semicycle, this.real);
public static CyclicalComplex FromPolarCoordinates(double magnitude, double phase, double semicycle = DefaultSemicycle)
{
NormalizePolars(ref magnitude, ref phase, semicycle);
return new(magnitude * Math.Cos(phase), magnitude * Math.Sin(phase), semicycle);
}
public static CyclicalComplex Negate(CyclicalComplex value)
=> -value
;
public static CyclicalComplex Add(CyclicalComplex left, CyclicalComplex right)
=> left + right
;
public static CyclicalComplex Subtract(CyclicalComplex left, CyclicalComplex right)
=> left - right
;
public static CyclicalComplex Multiply(CyclicalComplex left, CyclicalComplex right)
=> left * right
;
public static CyclicalComplex Divide(CyclicalComplex dividend, CyclicalComplex divisor)
=> dividend / divisor
;
public static CyclicalComplex operator -(CyclicalComplex value)
=> new(-value.real, -value.imaginary, value.semicycle)
;
public static double NormalizeSemicycle(ref CyclicalComplex left, ref CyclicalComplex right)
{
if (left.semicycle <= 1) throw new ArgumentOutOfRangeException(nameof(left), "Semicycle must be greater than 1.");
if (right.semicycle <= 1) throw new ArgumentOutOfRangeException(nameof(right), "Semicycle must be greater than 1.");
var newCycle = left.semicycle;
// 计算新的周期:以大周期为基准,小周期向大周期靠拢
if (left.semicycle == right.semicycle)
{
newCycle = left.semicycle;
}
else if (left.semicycle > right.semicycle)
{
// 如果左边的周期大于右边的周期,则需要将右边的周期调整为左边的周期
right = Scale(right, (newCycle = left.semicycle) / right.semicycle);
}
else if (left.semicycle < right.semicycle)
{
// 如果右边的周期大于左边的周期,则需要将左边的周期调整为右边的周期
left = Scale(left, (newCycle = right.semicycle) / left.semicycle);
}
return newCycle;
}
public static void NormalizeParts(ref double real, ref double imaginary, double semicycle)
{
if (semicycle <= 1) throw new ArgumentOutOfRangeException(nameof(semicycle), "Semicycle must be greater than 1.");
// 如果实部超过周期,则需要将其调整到周期范围内
if (Math.Abs(real) > semicycle)
{
var reminder = Math.IEEERemainder(real, semicycle);
imaginary += (real - reminder) / semicycle;
real = reminder;
}
var inverseSemicycle = 1.0 / semicycle;
if (Math.Abs(real) < inverseSemicycle)
{
real = 0.0;
}
}
public static void NormalizePolars(ref double magnitude, ref double phase, double semicycle)
{
var p = FromPolarCoordinates(magnitude, phase, semicycle);
magnitude = p.Magnitude;
phase = p.Phase;
}
/// <summary>
/// 当两者周期不同的时候,如何相加
/// 因为Sqrt(-1)=Sqrt(-1*1) 也就是1和无限的几何平方根,
/// 而无限在这里就是周期。当周期不同的时候,新的周期应当
/// 为两个周期的几何平方根。在新周期的基础上再重新计算
/// 两个复数,然后再相加,减法也是一样的。
/// 周期必须为正数。
/// </summary>
/// <param name="left"></param>
/// <param name="right"></param>
/// <returns></returns>
///
public static CyclicalComplex operator +(CyclicalComplex left, CyclicalComplex right)
{
var newCycle = NormalizeSemicycle(ref left, ref right);
var real = left.real + right.real;
var imaginary = left.imaginary + right.imaginary;
NormalizeParts(ref real, ref imaginary, newCycle);
return new (real, imaginary, newCycle);
}
public static CyclicalComplex operator -(CyclicalComplex left, CyclicalComplex right)
{
var newCycle = NormalizeSemicycle(ref left, ref right);
var real = left.real - right.real;
var imaginary = left.imaginary - right.imaginary;
NormalizeParts(ref real, ref imaginary, newCycle);
return new (real, imaginary, newCycle);
}
public static CyclicalComplex operator *(CyclicalComplex left, CyclicalComplex right)
{
var newCycle = NormalizeSemicycle(ref left, ref right);
var real = left.real * right.real - left.imaginary * right.imaginary;
var imaginary = left.imaginary * right.real + left.real * right.imaginary;
NormalizeParts(ref real, ref imaginary, newCycle);
return new(real, imaginary, newCycle);
}
public static CyclicalComplex operator /(CyclicalComplex left, CyclicalComplex right)
{
var newCycle = NormalizeSemicycle(ref left, ref right);
var real = left.real;
var imaginary = left.imaginary;
var real2 = right.real;
var imaginary2 = right.imaginary;
if (Math.Abs(imaginary2) < Math.Abs(real2))
{
var n = imaginary2 / real2;
real = (real + imaginary * n) / (real2 + imaginary2 * n);
imaginary = (imaginary - real * n) / (real2 + imaginary2 * n);
NormalizeParts(ref real, ref imaginary, newCycle);
return new(real, imaginary, newCycle);
}
else
{
var n = real2 / imaginary2;
real = (imaginary + real * n) / (imaginary2 + real2 * n);
imaginary = (-real + imaginary * n) / (imaginary2 + real2 * n);
NormalizeParts(ref real, ref imaginary, newCycle);
return new(real, imaginary, newCycle);
}
}
public static double Abs(CyclicalComplex value)
{
if (double.IsInfinity(value.real) || double.IsInfinity(value.imaginary)) return 0.0;
var nr = Abs(value.real);
var ni = Abs(value.imaginary);
if (nr > ni)
{
double m = ni / nr;
return nr * Math.Sqrt(1.0 + m * m);
}
if (ni == 0.0)
{
return nr;
}
var n = nr / ni;
return ni * Math.Sqrt(1.0 + n * n);
}
//共轭
public static CyclicalComplex Conjugate(CyclicalComplex value)
=> new(value.real, -value.imaginary, value.semicycle)
;
//倒数
public static CyclicalComplex Reciprocal(CyclicalComplex value)
=> value.real == 0.0 && value.imaginary == 0.0 ? Zero : One / value
;
//相等
public static bool operator ==(CyclicalComplex left, CyclicalComplex right)
=> left.real == right.real && left.imaginary == right.imaginary && left.semicycle == right.semicycle
;
//不等
public static bool operator !=(CyclicalComplex left, CyclicalComplex right)
=> left.real != right.real || left.imaginary != right.imaginary || left.semicycle != right.semicycle
;
public override bool Equals(object? o)
=> o is CyclicalComplex complex && this == complex
;
public bool Equals(CyclicalComplex value)
=> this.real.Equals(value.real)
&& this.imaginary.Equals(value.imaginary)
&& this.semicycle.Equals(this.semicycle)
;
public static implicit operator CyclicalComplex(short value)
=> new(value, 0.0, DefaultSemicycle)
;
public static implicit operator CyclicalComplex(int value)
=> new(value, 0.0, DefaultSemicycle)
;
public static implicit operator CyclicalComplex(long value)
=> new(value, 0.0, DefaultSemicycle)
;
public static implicit operator CyclicalComplex(ushort value)
=> new(value, 0.0, DefaultSemicycle)
;
public static implicit operator CyclicalComplex(uint value)
=> new(value, 0.0, DefaultSemicycle)
;
public static implicit operator CyclicalComplex(ulong value)
=> new(value, 0.0, DefaultSemicycle)
;
public static implicit operator CyclicalComplex(sbyte value)
=> new(value, 0.0, DefaultSemicycle)
;
public static implicit operator CyclicalComplex(byte value)
=> new(value, 0.0, DefaultSemicycle)
;
public static implicit operator CyclicalComplex(float value)
=> new((double)value, 0.0, DefaultSemicycle)
;
public static implicit operator CyclicalComplex(double value)
=> new((double)value, 0.0, DefaultSemicycle)
;
public static explicit operator CyclicalComplex(BigInteger value)
=> new((double)value, 0.0, DefaultSemicycle)
;
public override string ToString()
=> $"({this.real}, {this.imaginary}, {this.semicycle})"
;
public string ToString(string format)
=> $"({this.real.ToString(format, CultureInfo.CurrentCulture)}, {this.imaginary.ToString(format, CultureInfo.CurrentCulture)}, {this.semicycle.ToString(format, CultureInfo.CurrentCulture)})"
;
public string ToString(IFormatProvider provider) => string.Format(provider, "({0}, {1}, {2})",
this.real,
this.imaginary,
this.semicycle
);
public string ToString(string format, IFormatProvider provider) => string.Format(provider, "({0}, {1}, {2})",
this.real.ToString(format, provider),
this.imaginary.ToString(format, provider),
this.semicycle.ToString(format, provider)
);
public override int GetHashCode()
{
const int Factor = 99999997;
int n = this.real.GetHashCode() % Factor;
int hashCode = this.imaginary.GetHashCode();
return n ^ hashCode;
}
public static CyclicalComplex Sin(CyclicalComplex value)
{
var real = value.real;
var imaginary = value.imaginary;
real = Math.Sin(real) * Math.Cosh(imaginary);
imaginary = Math.Cos(real) * Math.Sinh(imaginary);
NormalizeParts(ref real, ref imaginary, value.semicycle);
return new(real, imaginary, value.semicycle);
}
public static CyclicalComplex Asin(CyclicalComplex value)
{
var io = new CyclicalComplex(0.0, 1.0, value.semicycle);
var ro = new CyclicalComplex(1.0, 0.0, value.semicycle);
return -io * Log(io * value + Sqrt(ro - value * value));
}
public static CyclicalComplex Sinh(CyclicalComplex value)
{
var real = value.real;
var imaginary = value.imaginary;
real = Math.Sinh(real) * Math.Cos(imaginary);
imaginary = Math.Cosh(real) * Math.Sin(imaginary);
NormalizeParts(ref real, ref imaginary, value.semicycle);
return new(real, imaginary, value.semicycle);
}
public static CyclicalComplex Cos(CyclicalComplex value)
{
var real = value.real;
var imaginary = value.imaginary;
real = Math.Cos(real) * Math.Cosh(imaginary);
imaginary = -(Math.Sin(real) * Math.Sinh(imaginary));
NormalizeParts(ref real, ref imaginary, value.semicycle);
return new(real, imaginary, value.semicycle);
}
public static CyclicalComplex Cosh(CyclicalComplex value)
{
var real = value.real;
var imaginary = value.imaginary;
real = Math.Cosh(real) * Math.Cos(imaginary);
imaginary = Math.Sinh(real) * Math.Sin(imaginary);
NormalizeParts(ref real, ref imaginary, value.semicycle);
return new(real, imaginary, value.semicycle);
}
public static CyclicalComplex Acos(CyclicalComplex value)
{
var io = new CyclicalComplex(0.0, 1.0, value.semicycle);
var ro = new CyclicalComplex(1.0, 0.0, value.semicycle);
return -io * Log(value + io * Sqrt(ro - value * value));
}
public static CyclicalComplex Tan(CyclicalComplex value)
=> Sin(value) / Cos(value)
;
public static CyclicalComplex Tanh(CyclicalComplex value)
=> Sinh(value) / Cosh(value)
;
public static CyclicalComplex Atan(CyclicalComplex value)
{
var right = new CyclicalComplex(2.0, 0.0, value.semicycle);
var io = new CyclicalComplex(0.0, 1.0, value.semicycle);
var ro = new CyclicalComplex(1.0, 0.0, value.semicycle);
return io / right * (Log(ro - io * value) - Log(ro + io * value));
}
public static CyclicalComplex Log(CyclicalComplex value)
{
var real = Math.Log(Abs(value));
var imaginary = Math.Atan2(value.imaginary, value.real);
NormalizeParts(ref real, ref imaginary, value.semicycle);
return new(real, imaginary, value.semicycle);
}
public static CyclicalComplex Log(CyclicalComplex value, double baseValue)
=> Log(value) / Log(baseValue)
;
public static CyclicalComplex Log10(CyclicalComplex value)
=> Scale(Log(value), LOG_10_INV)
;
public static CyclicalComplex Exp(CyclicalComplex value)
{
var num = Math.Exp(value.real);
var real = num * Math.Cos(value.imaginary);
var imaginary = num * Math.Sin(value.imaginary);
NormalizeParts(ref real, ref imaginary, value.semicycle);
return new(real, imaginary, value.semicycle);
}
public static CyclicalComplex Sqrt(CyclicalComplex value)
=> FromPolarCoordinates(Math.Sqrt(value.Magnitude), value.Phase / 2.0, value.semicycle)
;
public static CyclicalComplex Pow(CyclicalComplex value, CyclicalComplex power)
{
if (power == Zero)
{
return One;
}
else if (value == Zero)
{
return Zero;
}
var real = value.real;
var imaginary = value.imaginary;
var real2 = power.real;
var imaginary2 = power.imaginary;
var num1 = Abs(value);
var num2 = Math.Atan2(imaginary, real);
var num3 = real2 * num2 + imaginary2 * Math.Log(num1);
var num4 = Math.Pow(num1, real2) * Math.Pow(Math.E, -imaginary2 * num2);
real = num4 * Math.Cos(num3);
imaginary = num4 * Math.Sin(num3);
NormalizeParts(ref real, ref imaginary, value.semicycle);
return new(real, imaginary, value.semicycle);
}
public static CyclicalComplex Pow(CyclicalComplex value, double power)
=> Pow(value, new CyclicalComplex(power, 0.0, value.semicycle))
;
private static CyclicalComplex Scale(CyclicalComplex value, double factor)
{
var real = factor * value.real;
var imaginary = factor * value.imaginary;
NormalizeParts(ref real, ref imaginary, value.semicycle);
return new(real, imaginary, value.semicycle);
}
}