【问题标题】:How to create a custom Murmur Avalanche Mixer?如何创建自定义的 Murmur Avalanche 混合器?
【发布时间】:2017-12-26 09:19:47
【问题描述】:

我正在尝试使用 Avalanche 混合器来散列整数坐标。我一直在使用Murmur3's 32 位和 64 位雪崩混频器来这样做(而不是实际的总哈希函数)。对于我的应用程序,不需要整个哈希函数,只需要这里看到的 Avalanche Mixer:

uint32_t murmurmix32( uint32_t h )
{
  h ^= h >> 16;
  h *= 0x85ebca6b;
  h ^= h >> 13;
  h *= 0xc2b2ae35;
  h ^= h >> 16;

  return h;
}


uint64_t murmurmix64( uint64_t h )
{
  h ^= h >> 33;
  h *= 0xff51afd7ed558ccdULL;
  h ^= h >> 33;
  h *= 0xc4ceb9fe1a85ec53ULL;
  h ^= h >> 33;

  return h;
}

这些在我的机器上看起来很快,我将两个 uint32_ts 混合到这些函数中以产生雪崩结果,这会产生我喜欢的伪随机分布。

我想为这个系统引入更多坐标(即 z 和 w),所以我想使用更大的雪崩混合器来散列我的坐标。我相信出于我的目的,我希望从函数本身中看到的最大值是 uint64_t,碰撞本身不是问题,但结果的随机性是。

似乎 murmur3 的雪崩混合器没有比 64 更大。我查看了 this websitethis one 以获得一些关于一些替代雪崩哈希的线索:

这些雪崩的质量似乎足以满足我的申请,但我对 City hash 的杂音灵感特别感兴趣。

在 CityHash 中,他们有一个“杂音灵感”的混音器:

uint64 Hash128to64(const uint64_t& x_high, const uint64_t& x_low) {
  // Murmur-inspired hashing.
  const uint64 kMul = 0x9ddfea08eb382d69ULL;
  uint64 a = (x_low ^ x_high) * kMul;
  a ^= (a >> 47);
  uint64 b = (x_high ^ a) * kMul;
  b ^= (b >> 47);
  b *= kMul;
  return b;
}

这对于两个 64 位数字来说似乎相当快。我对他们如何从 Murmur 中获得自己的“灵感”哈希感到困惑。如何创建自己的 2^n 位杂音雪崩混频器?

【问题讨论】:

  • 我认为它需要大量的实验。您需要进行一些可逆的转换(例如与奇数相乘,与自身右移异或等),然后将它们按某种顺序排列,然后测量雪崩。注意:如果我没记错的话,你的噪音发生器需要这个。在这种情况下,你的输出比你的输入少,所以这些通用哈希函数做的太多了。所以也许你可以找到一个更简单一点的哈希函数,它只对低 X 位具有良好的雪崩特性。
  • @geza 是的,我需要这个来消除噪音。对于我正在查看的尺寸,我还没有找到任何更简单的雪崩混合器。目前我正在使用 murmur 3,它运行良好且速度很快,murmur 似乎是我能管理的最快并且仍然获得良好的雪崩行为。

标签: c++ random hash murmurhash


【解决方案1】:

如果您真的对冲突不感兴趣,而是对结果的随机性感兴趣,那么您应该尝试使用具有 128 位状态和 64 位输出的 PRNG。

而且相当不错的是众所周知的 PRNG,称为 Xoroshiro128+ - 速度快,随机性非常好。

代码可以在here找到

更新

是的,由于 RNG 首先返回一个模 264 的总和,因此使用它进行缓存似乎有问题。想知道简单的修改(基本上,在旋转/异或之后移动结果计算)是否会有所帮助

static inline uint64_t rotl(const uint64_t x, int k) {
    return (x << k) | (x >> (64 - k));
}

uint64_t next(uint64_t* s) {
    const uint64_t s0 = s[0];
    uint64_t s1 = s[1];

    s1 ^= s0;
    s[0] = rotl(s0, 55) ^ s1 ^ (s1 << 14); // a, b
    s[1] = rotl(s1, 36); // c

    return s[0] + s[1];
}

【讨论】:

  • 请参阅my previous question,了解为什么 PRNG 通常不适用于在输出顶部添加另一个散列函数的情况下。虽然它们在产生良好 PRNG 输出的任意种子上做得很好,但由于不良的雪崩行为(PRNG 通常不需要),如果你有一个只有一点差异的种子,你通常会得到非常糟糕的 PRNG 结果。在我之前的帖子中,即使 Xorshift+ 产生奇数输出的效果也很差。
  • @snb poor avalanching behavior (which is not needed typically for PRNG) - 过去是这样,但现在不再是这样了,人们正在添加类似于良好雪崩行为的 PRNG 特性测试,而 Xoroshiro128+ 全部通过了。代码就在这里,试试看吧……
  • 请注意,潜在的问题是随机数是在播种 PRNG 后直接生成的。在xoroshiro128+(和xorshift128+)的情况下,该随机数只是种子的两半之和,mod 2^64。
  • @PeterO。那么,这是一个很容易解决的问题 - 跳过第一个数字并从第二个开始
  • @PeterO 好吧,那是错误的陈述,你是对的,对于哈希目的,返回总和是不好的。更新了答案。
【解决方案2】:

Pelle Evensen 在mostlymangling.blogspot.com 的博文中已经在很大程度上回答了您的问题“如何创建自定义的 Murmur Avalanche 混合器”,尤其是以下两个:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-11
    相关资源
    最近更新 更多