问题
I'm trying to use an Avalanche mixer to hash integer coordinates. I've been using Murmur3's 32bit and 64bit avalanche mixers to do so (and not the actual total hash function). For my application the entire hash function is not needed, only the Avalanche Mixer seen here:
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;
}
These appear fast on my machine, I take two uint32_ts and mix them into these functions to produce avalanched results, this produces a psuedorandom distribution to my liking.
I want to introduce more coordinates to this system (ie z and w), so I want to use larger avalanche mixers to hash my coordinates. I believe for my puroposes the max value I want to see come out of the function itself is uint64_t, collisions themselves are not a problem, but the randomness of the results are.
It does not appear that murmur3 has a larger avalanche mixer than 64. I've looked at this website and this one to get a few clues on some alternative avalanche hashes:
Jenkins lookup3
Hsieh SuperFastHash
Spooky Hash
City Hash
The quality of these avalanches seem to be good enough for my application but I'm particularly interested in City hash's murmur inspirations.
In CityHash, they have a "murmur inspired" mixer:
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;
}
This seems quite fast for two 64 bit numbers. I'm confused as to how they derived their own "inspired" hash from Murmur. How would one go about creating their own 2^n bit murmur avalanche mixer?
回答1:
If you really are interested not in collisions, but in the randomness of the results, then you should try to use PRNG with 128bits state and 64bits output.
And pretty good is well-known PRNG called Xoroshiro128+ - fast, quite good randomness.
Code could be found here
UPDATE
Yes, looks like problem to use it for caching due to the fact RNG returns first just a sum modulo 264. Wondering if simple modification (basically, moving result computation after the rotations/xors) will help
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];
}
来源:https://stackoverflow.com/questions/45218741/how-to-create-a-custom-murmur-avalanche-mixer