创建两个数字的哈希码

16 浏览
0 Comments

创建两个数字的哈希码

我正在尝试为C#中的复数类<(a + b)>创建一个快速哈希码函数。\n我反复看到了方法。\n但这将为<(a,b)>和<(b,a)>给出相同的哈希码。\n有没有标准的算法可以解决这个问题,并且.Net框架中是否有任何函数可以帮助?

0
0 Comments

问题的出现原因:

问题是如何创建两个数字的哈希码。为了解决这个问题,可以使用一个标准的方法,即使用一个简单的算法来创建哈希码。这个算法使用了两个数字和两个常数23和37进行计算。通过将两个数字分别乘以37,并将结果相加,可以得到一个唯一的哈希码。这个算法的实现简单,但是存在碰撞的风险。

解决方法:

为了解决碰撞的问题,可以选择不同的常数作为乘数。23和37是互质的,但也可以使用其他互质的数字。通过选择不同的乘数可以减少碰撞的可能性。

如果v1和v2是复杂类型而不是整数类型,可以使用v1.GetHashCode()v2.GetHashCode()替换代码中的v1v2。对于大多数非平凡类型,GetHashCode已经是一个截断的结果。

通过使用一个简单的算法,可以创建两个数字的哈希码。这个算法使用了两个数字和两个互质的常数,并通过将数字乘以常数并将结果相加来计算哈希码。然而,这个算法可能会导致碰撞,因此可以选择不同的常数来减少碰撞的可能性。如果数字是复杂类型,可以使用GetHashCode方法来获取哈希码。这个方法已经是一个截断的结果,适用于大多数非平凡类型。

0
0 Comments

在上述内容中,我们可以看到有一个问题被提到了:如何为两个数字创建一个哈希码。下面是该问题出现的原因以及解决方法的总结。

问题的原因:

在某些情况下,我们需要为两个数字创建一个唯一的哈希码。这种情况可能发生在数据库中,当我们有两个自动生成的主键数字,我们需要为它们创建一个唯一的哈希码。然而,直接使用数字本身作为哈希码可能不够唯一,因此我们需要找到一种方法来创建一个更加唯一的哈希码。

解决方法:

在上述内容中,给出了一个可能的解决方法。该方法考虑到了数字的顺序。具体实现如下:

public int GetHashCode()
{
    return a.GetHashcode() ^ b.GetHashcode().RotateLeft(16);
}
public static uint RotateLeft(this uint value, int count)
{
    return (value << count) | (value >> (32 - count))
}

上述代码是一个示例实现,返回的哈希码是根据数字a和b计算得到的。其中,RotateLeft方法是一个扩展方法,用于对哈希码进行左移操作。

此解决方法对于数字值有一定的倾斜性(例如,它们倾向于较小的一侧,因为它们是数据库中的自动生成主键)是最佳的。但是,如果a和b是除了int之外的其他类型(如uint),那么调用GetHashCode()是必要的,因为它们是包含类的GetHashCode()方法的返回类型。

通过以上的讨论,我们了解到了为两个数字创建一个哈希码的问题以及解决方法。这种方法可以确保哈希码的唯一性,并且考虑到了数字的顺序。如果你对这个问题感兴趣,你可以查看.NET 4.0中的Complex类的源代码,了解更多关于哈希码的实现方式。

0
0 Comments

问题的原因是作者想要创建两个数字的哈希码,并且作者展示了一种常见的方法来创建多个可哈希项的哈希码。解决方法是使用一个初始的哈希值,并且对每个可哈希项应用一系列操作,最后得到一个组合哈希值。这种方法可以避免哈希冲突,并且在处理特定的整数值时可能更加高效。

文章的内容如下:

通常我用来为一组可哈希项创建哈希码的方法如下:

int hash = 23;
hash = hash * 31 + item1Hash;
hash = hash * 31 + item2Hash;
hash = hash * 31 + item3Hash;
hash = hash * 31 + item4Hash;
hash = hash * 31 + item5Hash;
// etc

在你的情况下,item1Hash可以是a,item2Hash可以是b。

23和31的具体值并不重要,只要它们是质数(或至少互质)即可。

显然仍然会有哈希冲突,但是你不会遇到以下常见的问题:

hash(a, a) == hash(b, b)
hash(a, b) == hash(b, a)

如果你对a和b的实际值有更多了解,你可能能够做得更好,但这是一个很好的初始实现,容易记住和实现。请注意,如果有可能使用“检查算术溢出/下溢”的选项来构建程序集,则应将所有代码放在未经检查的块中(对于这个算法来说,溢出是可以接受的)。

“只要它们是质数(或至少互质)” - 我认为初始状态可以是任何值(如果31的倍数是不好的,那么当你碰巧在计算过程中遇到这样的值时会发生什么?)。然后乘数只需要是奇数(以避免早期值对结果的低位没有影响),并且不能是1,以避免交换性。难道我完全没有理解吗?

我不敢说我理解为什么这些数字应该是互质的逻辑 - 但这是我一直看到的这种模式的建议,这些建议来自比我聪明的人(比如Josh Bloch)。

不能怪你听从你的老板的老板的老板的话;-)这是他写的一个hashCode方法的示例,初始状态为0,尽管它只是作为一个完全不同的示例的一部分:209.85.229.132/search?q=cache:3H-Bb8E4sDEJ:developers.sun.com/…。也许我应该读一下《Effective Java》...

对于特定情况下的两个整数值,只有在所有值等可能的情况下,这才是最优的解决方案。如果值偏向于较小的数字(例如自动生成的主键值),那么这种解决方案产生冲突的可能性比其他解决方案更大。

为什么不从int hash = 713 + item1Hash;开始,因为你总是将23乘以31?

:为了简化阅读 - 保持一致性。

我认为这不应该是最好的答案,因为当哈希3个整数向量(x,y,z)时,它很快就会发生冲突((0, 1, 0)和(0, 0, 31)具有相同的哈希值685224)。

:注意:“如果你对a和b的实际值有更多了解,你可能能够做得更好。”你的例子属于这种情况。

在寻找如何完成这个任务时,我偶然发现了这个问题。然后我看到了一个对于.Net Core 2.1及以上版本来说非常有用的VS快捷提示,它指向了System.HashCode.Combine的存在。它似乎被重载以接收最多7个泛型参数,并为您组合它们。

0