众所周知,用==比较浮点数通常是一个错误。我写道,在3D向量类中(具有浮点分量X,Y,Z),如果两个向量的距离被视为零,则它们被视为相等。

public override bool Equals(object obj)
{
    if (obj == null) {
        return false;
    }

    if (GetType () != obj.GetType ()) {
        return false;
    }

    float d = DistSq ((Vec) obj);

    return IsConsideredZero (d);
}

public float DistSq(Vec p)
{
    Vec d = this - p;
    return d.LengthSq ();
}

public float LengthSq()
{
    return X * X + Y * Y + Z * Z;
}

private const float VEC_COMPARE_EPSILON_ABS = 1E-05f;
public static bool IsConsideredZero(float f)
{
    return Math.Abs (f) < VEC_COMPARE_EPSILON_ABS;
}
到目前为止,一切正常。但是,现在我想获取向量的哈希码。我可以看到像hash = (int)X^(int)Y^(int)Z这样的东西注定会失败。
我能想到的最好的是:
public override int GetHashCode()
{
    return 0;
}
当然,这很烂。有什么方法可以获取合理的哈希码吗? NaN和其他特殊值是可能的,但如果很重要的话,则不太可能。

最佳答案

假设您要具有普通的哈希码/等于属性是不可能的:

  • 如果X = Y并且Y = Z,则X = Z(传递性)
  • 如果X = Y,则Y = X(可交换性)
  • X =所有X(反射性)的X

  • 第一条规则是问题-因为如果每个值都被认为等于下一个更大的可表示数字“等于”,那么最终所有数字都相等。例如,假设一个数字等于0.1以内的数字:

    0等于0.08
    0.08等于0.16
    0.16等于0.24

    => 0根据传递性规则等于0.16
    => 0根据传递性规则等于0.24

    (等等)

    如果您忽略传递性规则,那么您仍然(大概)希望“相等”的值具有相等的哈希码。这有效地执行了传递性规则-在上面的示例中,0和0.08必须具有相等的哈希码,而0和0.16则必须具有相等的哈希码。因此,0和0.16必须具有相等的哈希码,依此类推。因此,您将没有有用的哈希码-它必须是一个常量。

    关于floating-point - 有没有办法用epsilon获取浮点数的哈希码?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/580905/

    10-10 11:42