I'm running into an issue with the random number generator I wrote for a game. I need a fast pseudorandom field generator. It does not need to be cryptographically secure, it just needs to take in a vector and a seed, and give a hashed value that's random enough to fool cursory human inspection.
However, this code is failing to produce "pseudorandom" output when I give a 2d vector and mod the result by 2. It produces a mostly checkerboard pattern.
I'm not sure why, and honestly, it would be cool to know, but I won't sweat it if I never figure it out. Mostly, I just figured that this way of generating random numbers was too terrible, so I wanted to know of an alternate way of approaching this problem. Ie, I was really seeking resources or pointers on what would be a good, alternate way to generate random numbers in this manner, rather than asking "what am I doing wrong?"
Basically, I'm trying to generate an "infinite" 2D noise field (think, white noise) that I can get back, if I put in the same inputs.
The code I wrote is (it's supposed to be an fnv hash, please excuse the template stuff. I kinda just pulled this out of the code. I'll clean it up a bit later).
//Static random number generator, will generate a random number based off of a seed and a coordinate
template<typename T, typename... TL>
uint32_t static_random_u32(T const& d, TL const&... rest) {
return fnv_hash32(d, rest..., 2938728349u); //I'm a 32-bit prime!
}
template<typename T, typename... TL>
uint32_t fnv_hash32(T const& v, TL const&... rest) {
uint32_t hash;
fnv_hash32_init(hash);
fnv_hash32_types(hash, v, rest...);
return hash;
}
inline void fnv_hash32_init(uint32_t& hash) {
hash = 2166136279u; //another 32-bit prime
}
// Should produce predictable values regardless of endianness of architecture
template<typename T, typename... TL>
void fnv_hash32_types(uint32_t& hash, T const& v, TL const&... rest) {
#if LITTLE_ENDIAN
fnv_hash32_bytes(hash, (char*)&v, sizeof(v), true);
#else
fnv_hash32_bytes(hash, (char*)&v, sizeof(v), false);
#endif
fnv_hash32_types(hash, rest...);
}
inline void fnv_hash32_types(uint32_t& hash) {}
inline void fnv_hash32_bytes(uint32_t& hash, char const* bytes, size_t len, bool swapOrder = false) {
if (swapOrder) {
for (size_t i = len; i > 0; --i)
fnv_hash32_next(hash, bytes[i - 1]);
} else {
for (size_t i = 0; i < len; ++i)
fnv_hash32_next(hash, bytes[i]);
}
}
inline void fnv_hash32_next(uint32_t& hash, char byte) {
hash ^= byte;
hash *= 16777619u;
}