【问题标题】:C# collisions with Double.GetHashCode() [closed]C# 与 Double.GetHashCode() 的冲突 [关闭]
【发布时间】:2021-01-29 11:54:12
【问题描述】:

我需要为具有唯一哈希码的未知对象类型生成一系列“默认值”。 (可以是结构或类,重写 GetHashCode 使其默认构造始终返回相同的哈希值。)

为了处理大多数此类情况,我使用反射来查找可以排序的数字字段/属性。因此,例如,如果我能找到一个双字段,我可以继续为该字段返回具有不同值的新对象,这通常会改变哈希值。

那么如何形成这个值序列呢?起初我以为我只需要坚持整数分辨率的范围,并且每次迭代都可以继续添加 1.0。基于this answer,我选择了-1E50到1E50的范围。但事实证明 Double.GetHashCode 为 -1E50 和 (-1E50 + 1.0) 返回相同的哈希值。将范围降低到 -1E15 到 1E15 似乎可以解决它,但我仍然不知道我正在做的事情是否安全。 (我不需要这么大的范围,但我确实需要知道我不会发生碰撞。)

所以我的问题是,我可以使用什么范围的双精度值(每次递增 1.0 或其他数量)来保证不同的哈希结果?对于浮点数或其他数字类型,此答案是否会改变?

【问题讨论】:

  • 如果一个类有 int a;字符串 s;数据成员 - 我们不要(在 GetHashCode 覆盖中)类似 - return a.GetHashCode() ^ s.GetHashCode(); ——这有什么问题?
  • @Prateek OP 缺少 -1E50-1E50 + 1 成为相同值的点。
  • 不,它不安全,双打不能保持那种精度。
  • 请注意,您应该将GetHashCode 返回的值用于潜在相等。因为你在归类更大的价值,所以总会有碰撞的空间。您需要检查实际值以确认相等。

标签: c# hash double


【解决方案1】:

预计哈希值会发生冲突,因此尝试预测 GetHashCode 的某些未记录实现是否具有特定属性是一个坏主意。如果您需要哈希函数的特定属性/保证 - 自己实现一个(使用内置类型,您可能必须先将它们包装到另一个结构中)。

更具体到你的情况

  • GetHashCode for double(或float)通常不是有用的方法,因为浮点计算不精确,并且使用表达式的值在由浮点数索引的字典中查找几乎肯定会一直失败。
  • 您从 (1E50) 开始的特定范围没有足够的精度来表示相差 1 的值,实际上更小的范围将能够表示所有整数 - 您可以从 MSDN-floating numbers 中看到,对于 double 您可以获得精度“15 -17 位数字”。所以是的,-1E15 到 1E15 的所有整数值都带有唯一的浮点数。

如果您想要一个“浮点”类型,它对整数值具有可靠且有保证的唯一哈希码,您可以使用自定义结构,将四舍五入的值作为哈希返回:

  struct MyDouble
  { 
      private double innerValue;
   
      // add implicit conversion to/from double

      public int override GetHashCode() { return (int)innerValue;}
      public bool oeverride Equal(object right) { return innerValue == (double)right;}
  }

注意:equal 需要更好地实现真实类,以及需要添加所有其他比较。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-15
    相关资源
    最近更新 更多