C# 更好的64位字节数组哈希

C# 更好的64位字节数组哈希,c#,hashcode,C#,Hashcode,我需要一个哈希算法,该算法生成的64位哈希代码比String.GetHashCode长,冲突更少,而且速度快,对加密函数的调用也不昂贵。这是一个实现,在测试了200万个随机字符串后,仍然显示了3%的冲突。我需要这个数字低一点 void Main() { const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!#@$%^&*()_+}{\":?><,./;'[]01234567

我需要一个哈希算法,该算法生成的64位哈希代码比String.GetHashCode长,冲突更少,而且速度快,对加密函数的调用也不昂贵。这是一个实现,在测试了200万个随机字符串后,仍然显示了3%的冲突。我需要这个数字低一点

void Main()
{
    const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!#@$%^&*()_+}{\":?><,./;'[]0123456789\\";
    const int n = 2000000;
    var random = new Random();
    var hashes = new HashSet<long>();
    int collisions = 0;
    for(int i = 0; i < n; i++)
    {
        var len = random.Next(chars.Length);
        var str = new char[len];
        for (int j = 0; j < len; j++)
        {
            str[j] = chars[random.Next(chars.Length)];
        }
        var s = new String(str);
        if(!hashes.Add(Get64BitHash( s ))) collisions++;
    }
    Console.WriteLine("Collision Percentage after " + n + " random strings: " + ((double)collisions * 100 / n));
}


public long Get64BitHash(string str)
{
  unchecked
  {
     byte[] data = new byte[str.Length * sizeof(char)];
     System.Buffer.BlockCopy(str.ToCharArray(), 0, data, 0, data.Length);

     const ulong p = 1099511628211UL;
     var hash = 14695981039346656037UL;
     foreach(var d in data)
     {
        hash ^= d;
        hash *= p;
     }
     return (long) hash;
  }
}
3%与仅调用String.GetHashCode的冲突百分比相同

也许这是理论上的最佳选择。内置的哈希代码不错。与SHA2一起尝试,以确认这是您所能做到的最好的

由于测试字符串是随机的,所以哈希代码可能也分布得很好

通过不创建两个似乎没有任何用途的临时缓冲区来优化功能。只需直接访问字符str[0]。这样,您可以保存副本,并在每次迭代中处理两个字节

3%与仅调用String.GetHashCode的冲突百分比相同

也许这是理论上的最佳选择。内置的哈希代码不错。与SHA2一起尝试,以确认这是您所能做到的最好的

由于测试字符串是随机的,所以哈希代码可能也分布得很好


通过不创建两个似乎没有任何用途的临时缓冲区来优化功能。只需直接访问字符str[0]。这样,您可以保存副本并在每次迭代中处理两个字节。

问题在于字符串不是随机的。
在对字符串进行第二次散列之前测试它。

问题在于字符串不是随机的。
在对字符串进行第二次散列之前,请先对其进行测试。

您应该计算真正的散列冲突,因为大多数冲突都是由字符串冲突造成的

声明如下:

var hashesString = new HashSet<string>();
int collisionsString = 0 ;
int testedCollisions = 0 ;

我用更新后的代码运行了一次,没有真正的冲突,只有60000个重复的字符串

您应该计算真正的哈希冲突,因为大多数冲突都是由字符串冲突造成的

声明如下:

var hashesString = new HashSet<string>();
int collisionsString = 0 ;
int testedCollisions = 0 ;


我用更新后的代码运行了一次,没有真正的冲突,只有60000个重复的字符串

如果你能指定你想要达到的目标,特别是它需要比3%好多少?没有昂贵的加密函数调用,永远不会。卷你的拥有安全性。您可以查看MurMHHASH的64位变体,或者简单地取128位中最不重要的64位。为什么您的函数GET64 BithHASH的调用不算昂贵?如果您可以指定您要命中的目标,它可能会有帮助——具体地说,它需要比3%好多少?没有昂贵的调用。加密函数-从不。卷你的拥有安全性。您可以查看MurMHHASH的64位变体,或者简单地取128位中最不重要的64位。为什么您的函数GET64 BithHASH不考虑昂贵的问题?如果您计划保留或传输值,那么一个重要问题。String.GetHashCode仅保证在同一AppDomain中为您提供相同的值,如果保存该值并重新运行该程序,或将该值发送到另一台运行该程序的计算机,则GetHashCode调用可能不会返回相同的值。@usr将字符串处理两次是什么意思?@3-14159265358979323846264在相同的数据上运行两次循环。如果3%的哈希冲突,那么3%的散列也会发生冲突吗?还是我还不明白?!很晚了,所以可能是我!好的,你说得有道理:我不是要散列——我是指两次循环传递而不重置散列。但你的观点是正确的。不过,两次传递可以更好地洗牌位,这可能会给哈希表带来优势。如果您计划持久化或传输值,这是一个重要的问题。String.GetHashCode仅保证在同一AppDomain中为您提供相同的值,如果保存该值并重新运行该程序,或将该值发送到另一台运行该程序的计算机,则GetHashCode调用可能不会返回相同的值。@usr将字符串处理两次是什么意思?@3-14159265358979323846264在相同的数据上运行两次循环。如果3%的哈希冲突,那么3%的散列也会发生冲突吗?还是我还不明白?!很晚了,所以可能是我!好的,你说得有道理:我不是要散列——我是指两次循环传递而不重置散列。但你的观点是正确的。不过,两次传递会更好地洗牌位,这可能会给哈希表带来优势。为什么它们不是随机的呢?它们对我来说似乎很随机。运行字符串生成器for循环将创建重复的字符串。此外,它将创建一个空字符串。哈希算法冲突与将无限长字符串哈希到固定长度的可能性有关,因此多个字符串可以哈希到相同的结果。好的,这是真的。可能会有短串发生碰撞。接得好。是的,@Droksy是对的。这些不是完全随机的字符串。检查重复项后,情况有了很大改善
.为什么不是随机的?它们对我来说似乎很随机。运行字符串生成器for循环将创建重复的字符串。此外,它将创建一个空字符串。哈希算法冲突与将无限长字符串哈希到固定长度的可能性有关,因此多个字符串可以哈希到相同的结果。好的,这是真的。可能会有短串发生碰撞。接得好。是的,@Droksy是对的。这些不是完全随机的字符串。检查重复项后,情况有了很大改善。
   if(hashesString.Add(s))
   { // Count collisions only for new strings
     testedCollisions++ ;
     if (!hashes.Add(Get64BitHash( s ))) collisions++;
   }
 }
 Console.WriteLine("Collision Percentage after " + testedCollisions + " random strings: " + ((double)collisions * 100 / testedCollisions));