有没有一种方法来得到一个与epsilon的float的哈希码? [英] Is there a way to get a hashcode of a float with epsilon?

查看:152
本文介绍了有没有一种方法来得到一个与epsilon的float的哈希码?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

 < ($ obj == null){
return false; code> public override bool Equals(object obj)
{
if(obj == null) $(


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;

$ / code>

到目前为止,一切正常。但是,现在我想要得到一个向量的哈希码。我可以看到像 hash =(int)X ^(int)Y ^(int)Z 这样的东西肯定会失败。



最好的办法是:
$ b $ pre $ public override int GetHashCode()
{
返回0;
}

当然,这样做很糟糕。有什么办法可以得到一个合理的哈希码? NaNs和其他特殊的价值是可能的,但不太可能,万一​​这一点很重要。

解决方案

假设你想拥有正常的hashcode / equal属性:

$ ul
如果X = Y和Y = Z那么X = Z(传递性)

  • 如果X = Y,那么Y = X(交换性)
    X对于所有的X(反射性)


    第一个规则是问题 - 因为如果每个值被认为与下一个更大的可表示数字相等,那么最后所有的数字都是相等的。例如,假设一个数字与另一个数字相等,它们在0.1之内:

    <0>等于0.08
    0.08等于0.16
    0.16等于0.24



    => 0等于传统性规则$ 0.16,传递性规则
    => 0等于0.24

    (等)

    如果你忽略了传递规则,那么你仍然(可能)想要相等的值有相同的hashcode。这有效地强制了传递规则 - 在上面的例子中,0和0.08必须具有相同的哈希码,0和0.16也是一样。因此0和0.16必须具有相同的哈希码,等等。因此,你可以没有有用的哈希码 - 它必须是一个常量。


    It is well known that comparing floats by == is usually a mistake. In a 3D-vector class (with float components X, Y, Z) i wrote, two vectors are considered equal if their distance is considered zero.

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

    So far, everything worked fine. However, now i'd like to get a hashcode of the vector. I can see that something like hash = (int)X^(int)Y^(int)Z is bound to fail.

    The best i could come up with was:

        public override int GetHashCode()
        {
            return 0;
        }
    

    This, of course, kind of sucks. Is there any way to get a reasonable hashcode? NaNs and other special values are possible, but unlikely, in case that is important.

    解决方案

    It's impossible assuming you want to have the normal hashcode/equality properties:

    • If X = Y and Y = Z then X = Z (transitivity)
    • If X = Y then Y = X (commutivity)
    • X = X for all X (reflexivity)

    The first rule is the problem - because if each value is deemed "equal" to the next greater representable number, you end up with all numbers being equal. For instance, suppose a number is deemed equal to another they're within 0.1:

    0 equals 0.08 0.08 equals 0.16 0.16 equals 0.24

    => 0 equals 0.16 by the transitivity rule => 0 equals 0.24 by the transitivity rule

    (etc)

    If you ignore the transitivity rule, then you still (presumably) want "equal" values to have equal hashcodes. This effectively enforces the transitivity rule - in the above example, 0 and 0.08 have to have equal hashcodes, as do 0 and 0.16. Therefore 0 and 0.16 have to have equal hashcodes, and so on. Therefore you can have no useful hashcode - it has to be a constant.

    这篇关于有没有一种方法来得到一个与epsilon的float的哈希码?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    相关文章
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆