我正致力于生成不同类型的渐变噪音。这种噪声所需的一个因素是给定位置向量的随机向量的生成。
此位置矢量可以是单个int,2D位置,3D位置,4D位置等任何位置。
除此之外,还有一个额外的种子"价值是必要的。
需要的是将这些n + 1个整数的哈希值转换为一个唯一的整数,我可以用它来为PRNG提供种子。这些值非常重要,因为每次使用相同的值时我都需要能够检索原始种子。
到目前为止,我已尝试过Fowler-Noll-Vo的实施;但这对我的目的来说太慢了。
我也试过使用连续调用配对功能:
int pairing_function(int x, int y)
{
return(0.5*(x+y)*(x+y+1) + x);
}
即:
int hash = pairing_function(pairing_function(x,y),seed);
但似乎发生的事情是,如果种子数量足够大,则值会超出int的大小(甚至更大的类型)。
实现我在这里尝试做的事情的好方法是什么?重要的是速度超过任何加密问题,以及不返回大于原始数据类型的数字。
我使用的是C ++,但只要任何代码都可读,我就可以把它搞定。
答案 0 :(得分:1)
听起来你使用的FNV可能由于其使用方式而效率低下。这里(我认为,我还没有测试过)同样的事情,可以简单地内联。
inline uint32_t hash(uint32_t h, uint32_t x) {
for (int i = 0; i < 4; i++) {
h ^= x & 255;
x >>= 8;
h = (h << 24) + h * 0x193;
}
return h;
}
我认为调用hash(hash(2166136261, seed), x)
或hash(hash(hash(2166136261, seed), x), y)
会给你相同的结果(假设是little-endian)作为库函数。
但是,为了提高散列质量的成本,您可以尝试这样的更改:
inline uint32_t hash(uint32_t h, uint32_t x) {
for (int i = 0; i < 2; i++) {
h ^= x & 65535;
x >>= 16;
h = (h << 24) + h * 0x193;
}
return h;
}
甚至:
inline uint32_t hash(uint32_t h, uint32_t x) {
h ^= x;
h = (h << 24) + h * 0x193;
return h;
}
这些变化会稍微削弱低阶位,因此您希望遵循标准惯例优先使用高阶位。例如,如果您只需要16位,那么将最终结果右移16,而不是用0xffff
掩盖它;
h = ...
行会定期溢出一个int,但它依赖于标准的mod-2 ** 32行为。如果这是一个问题,那么您将要用不同的东西替换该行,并且可能在您的散列中接受更少的有用位。也许是h = (h >> 4) + (h & 0x7fffff) * 0x193;
,但这只是一个随机的调整,我还没有检查它的哈希质量。
答案 1 :(得分:0)
奇怪的是,FNV 方式太慢因为每个字节数据只有1 xor和1个整数乘积。来自Wikipedia [it is] 旨在快速计算。
如果你想要一些非常快的东西,你可以试试这些实现,其中乘法被编码为移位和加法:
丹·伯恩斯坦执行:unsigned long
hash(unsigned char *str)
{
unsigned long hash = 5381;
int c;
while (c = *str++)
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
return hash;
}
sdbm实现(hash(i)= hash(i - 1)* 65599 + str [i]):
static unsigned long
sdbm(str)
unsigned char *str;
{
unsigned long hash = 0;
int c;
while (c = *str++)
hash = c + (hash << 6) + (hash << 16) - hash;
return hash;
}
答案 2 :(得分:0)
我会在
上挑战你到目前为止,我已尝试过Fowler-Noll-Vo的实施;但这对我的目的来说太慢了。
在一些简单的基准测试中,我已经完成了FNV哈希是最快的。我假设你已经尝试了所有哈希的基准测试?
对于基准测试,我只是简单地测量了MVSC ++ 2013中使用两个32位unsigned int
输入的10亿个哈希值的各种算法所花费的时间:
pairing_function()
= 175M哈希/秒x + (y << 10)
= 170M哈希/秒hash()
pairing_function()
函数使用int pairing_function(int x, int y)
{
return((x+y)*(x+y+1)/2 + x);
}
= 167M哈希/秒显然这些是非常基本的基准测试结果,我不一定非常信任他们。看到一些算法在不同平台和编译器上运行得更快/更慢,我不会感到惊讶。
总的来说,尽管FNV在这种情况下是最快的,但在最快和最慢之间只有两个差异因素。如果这确实对你的情况有所影响,我建议你再看一下你的问题,看它是否可以重新设计,不需要哈希,或者至少减少对哈希速度的依赖。
注意:我将您的配对功能更改为:
double
对于上述基准。使用您的版本会导致转换为hash()
,导致x5变慢,#define FNV_32_PRIME 16777619u
unsigned int FNVHash32(const int input1, const int input2)
{
unsigned int hash = 2166136261u;
const unsigned char* pBuf = (unsigned char *) &input1;
for (int i = 0; i < 4; ++i)
{
hash *= FNV_32_PRIME;
hash ^= *pBuf++;
}
pBuf = (unsigned char *) &input2;
for (int i = 0; i < 4; ++i)
{
hash *= FNV_32_PRIME;
hash ^= *pBuf++;
}
return hash;
}
函数x8变慢。
<强>更新强>
对于FNV哈希,我找到了一个source online并从那里修改它直接在2个整数上工作(假设一个32位整数):
<input type="file" webkitdirectory="webkitdirectory" directory="directory" multiple="multiple"/>
由于FNV仅适用于字节,因此您可以将其扩展为使用任意数量的整数或其他数据。