我是否在结构比较中使用 IEquatable Equals()?



我正在为复数制作一个简单的结构,我想通过比较分量来检查它们是否相等。

目前我有:

public struct Complex
{
public float Re;
public float Img;
public Complex(float real, float imaginary)
{
Re = real;
Img = imaginary;
}
public static bool operator ==(Complex a, Complex b)
{
return Mathf.Approximately(a.Re - b.Re, 0) && Mathf.Approximately(a.Img - b.Img, 0);
}
public static bool operator !=(Complex a, Complex b) => !(a == b);
}

但是我已经看到了人们将IEquatableEquals函数一起使用的其他代码。我应该在这里使用它还是我的代码是正确的方法?我目前有点不确定何时使用该界面,何时不使用该界面。

这是如何正确实现结构的IEquatable<>IFormattable

以下基于以下答案

  • https://stackoverflow.com/a/5221407/380384
  • https://stackoverflow.com/a/58168800/380384

法典

public struct Complex : IEquatable<Complex>, IFormattable
{
public Complex(float real, float imaginary)
{
Real=real;
Imaginary=imaginary;
}
public float Real { get; }
public float Imaginary { get; }
#region IEquatable Members
/// <summary>
/// Equality overrides from <see cref="System.Object"/>
/// </summary>
/// <param name="obj">The object to compare this with</param>
/// <returns>False if object is a different type, otherwise it calls <code>Equals(Complex)</code></returns>
public override bool Equals(object obj)
{
if (obj is Complex item)
{
return Equals(item);
}
return false;
}
/// <summary>
/// Checks for equality among <see cref="Complex"/> classes
/// </summary>
/// <returns>True if equal</returns>
public bool Equals(Complex other)
{
return Real.Equals(other.Real)
&& Imaginary.Equals(other.Imaginary);
}
/// <summary>
/// Calculates the hash code for the <see cref="Complex"/>
/// </summary>
/// <returns>The int hash value</returns>
public override int GetHashCode()
{
unchecked
{
int hc = -1817952719;
hc = (-1521134295)*hc + Real.GetHashCode();
hc = (-1521134295)*hc + Imaginary.GetHashCode();
return hc;
}
}
public static bool operator ==(Complex target, Complex other) { return target.Equals(other); }
public static bool operator !=(Complex target, Complex other) { return !target.Equals(other); }
#endregion
#region IFormattable Members
public override string ToString() => ToString("g");
public string ToString(string formatting) => ToString(formatting, CultureInfo.CurrentCulture.NumberFormat);
public string ToString(string formatting, IFormatProvider provider)
{
if (Imaginary!=0)
{
return Imaginary>0
? $"{Real.ToString(formatting, provider)}+{Imaginary.ToString(formatting, provider)}i"
: $"{Real.ToString(formatting, provider)}-{(-Imaginary).ToString(formatting, provider)}i";
}
else
{
return Real.ToString(formatting, provider);
}
}
#endregion
}

这确保了==意味着完全平等。如果要实现近似等于,请添加方法.ApproxEquals(Complex other, float delta)或类似方法来实现该功能。

对于值为1.0的最小增量2^(-22) = 0.00000023842

另请注意,.GetHashCode()不是对称的,如果您交换值,如果RealImaginary,它将返回不同的结果。这是一个关键特征,很多人只是返回Real.GetHashCode() ^ Imaginary.GetHashCode()就搞砸了,这使得它对称,因为XOR运算符^是可交换的。

最后,转换为字符串由.ToString()根据需要使用各种重载进行处理。最佳做法是引用默认格式提供程序的.NumberFormat

出于性能原因,您最好使用 IEquatable。这是因为运算符需要对结构进行装箱和拆箱,而 IEquatable Equals 不需要 - 它只是函数成本本身。对于任何涉及大量数字和比较的数学,您绝对应该使用 IEquatable 选项。

最新更新