A Simple Hash for Perlin Noise
marcospereira.me
marcospereira.me
1) I remember building a game in 90s where the locations of resources on a 2d game map were generated by successive calls to random() (and then were probably mod 1024ed or something). But, when we looked at the locations, they were clearly in a line pattern. Huh? After a while of confused debugging, we eventually discovered that the RNG was a linear congruential generator, which, when used the way we did to generate N-tuples, tends to produce points that tend to lie on a small number of N-1 dimensional surfaces! Oops.
2) I remember a big debate with a statistician at a company we were selling data analytics software to. We were putting random data elements into random groups to support certain types of statistical analysis. He was adamant that the randomization we were doing would introduce bias into the data and showed us similar tests he had done that "proved it". He told us that his company would be dropping our product because they couldn't trust it. I told him that there was no way bias was introduced and I took a closer look at his tests. It turns out the RNG in whatever tool he was using was just not very good and it had apparently shaken his very understanding of statistics :) Luckily, I told him that we were using MD5 for randomness (once bitten!) and that if he simply redid his experiments with MD5 he would see the bias disappear. To say he was skeptical would be an understatement, but, thankfully for our contract, his tests didn't actually crack MD5, all bias was gone, and we got a very generous email from the skeptic informing us that he would be trusting our software for everything from now on.
Yep, this is the "Random Numbers Fall Mainly in the Planes" problem that the late George Marsaglia of xorshift fame wrote about in 1968: https://www.ncbi.nlm.nih.gov/pmc/articles/PMC285899/
Great paper with one of the best titles I can remember :)
There are many skeptics who would rather disregard other assertions, than to admit their own possible flawed testing/experimental/verification methodologies.
When you need to admit you are wrong, your vis-a-vis will trust you more as a result. When the shoe is on the other foot, you learn who you can trust.
This is a surprisingly resistant belief. It may have been true once, but today FNV is not even close to being a fast hash function. Check the SMHasher benchmarks:
https://github.com/rurban/smhasher#smhasher
FNV1a almost 2x slower than blake3, a cryptographic hash function! More than 10x slower than modern hashers such as Farm, City, Spooky, ..., all of which have far better statistical quality than FNV1.
There is no good reason to use an FNV function nowadays.
Implementation simplicity?
Sometimes you need a hash function in an environment that's not a Real Programming Language.
It's hard to do both small and big data correctly, and FNV is one of the few that optimizes for small data.
For moderately small data, larger than around 4 bytes, xxh3 beats it handily. But for extremely small sizes, FNV is still the winner.
Honestly people should probably just try to switch to xxh3 if performance is a concern, but FNV is certainly competitive for integer-size keys.
https://github.com/Cyan4973/xxHash/wiki/Performance-comparis...
See for example http://jonkagstrom.com/bit-mixer-construction/index.html
When the input is an integer, they're very good hash functions on their own.
Although the most important factor may have been that FNV is just easier to find. Looking for a hash algorithm is hard, the names are weird and opaque and it's hard to find a user friendly ranking or clear directions on how to pick one.
cycles/map shows you that FNV1a is very good with hash tables, 4x faster than the blake3 monstrosity
Paper: https://www.csee.umbc.edu/~olano/papers/GPUTEA.pdf
Slides: https://highperformancegraphics.org/previous/www_2010/media/...
let intHash = x => {
x *= 0xed5ad4bb;
x ^= x >> 11;
x = Math.imul(x,0xac4c1b51);
x ^= x >> 15;
x = Math.imul(x,0x31848bab);
x ^= x >> 14;
return x;
}
With a little wrapper to blend it with a seed via intHash(x+inthash(x+seed))Used in a Perlin flame here http://fingswotidun.com/stackie/?code=x1x-*5*dx4**y3*p%2By!-...
Obligatory disclaimer: Don't use any of this in cryptographic contexts.
Perlin noise is how the lines flow togeher rather than crossing each other during the animations.
I have a technical write up that explains how it works at the bottom.
A random number generator using the same seed would still have to follow the same steps for all users, meaning generating the world from the origin.
A simple implementation in javascript https://stackoverflow.com/questions/521295/seeding-the-rando...
I use it for my generative art project https://bigf.art
You want the results to be repeatable. Now you could seed with something, but this has tradeoffs (e.g., you have to produce the same order of elements in order to get the same values out)