【发布时间】:2015-01-28 23:09:15
【问题描述】:
我有一个非常具体的问题:
我在 15x50 网格上均匀分布随机值,我想要散列的样本对应于以任何可能的网格位置为中心的 5x5 单元格的正方形。
因此,样本数量可以从 25(大多数情况下远离边界)到 20、15(靠近边界)再到最少 9(在角落)。
因此,即使像元值是随机的,位置也会在序列长度中引入确定性变化。
哈希表大小很小,通常在 50 到 20 之间。
该函数将在大量随机生成的网格(数百/数千)上运行,并且每个网格可能被调用数千次。网格上的位置可以认为是随机的。
我想要一个可以尽可能均匀分布 15x50 个可能样本的函数。
我试过下面的伪代码:
int32 hash = 0;
int i = 0; // I guess i could take any initial value and even be left uninitialized, but fixing one makes the function deterministic
foreach (value in block)
{
hash ^= (value << (i%28))
i++
}
hash %= table_size
但是结果,虽然不是很不平衡,但对我来说似乎不是很顺利。也许是因为样本太小了,但是这种情况使得在更大的样本上运行代码变得很困难,如果一些精通计算机的人已经为我准备好了答案,我宁愿不必编写完整的测试工具:)。
我不确定将值两两配对并使用通用字节散列策略是最佳解决方案,尤其是因为值的数量可能是奇数。
我一直坚持使用第 17 个值来表示离网单元格,但这似乎会引入偏差(来自靠近边界的单元格的序列会有很多“离网”值)。
我也不确定测试各种解决方案效率的最佳方法是什么(例如,我应该生成多少个网格来了解性能)。
【问题讨论】:
-
如果这些值真的是均匀分布的(并且是独立的),你就不需要散列了。只需取第一个(或最后一个,或任何一个)八个 4 位值,将它们解释为单个无符号 32 位整数,然后对表大小取模。
-
注意:
i未初始化。注2:一切顺利。但是:移位,不要取模,除了最后。 -
@wildplasser 实际上我可能在开始时是随机的,因为它会被模数限制为 [0..27],但是初始化它会使函数具有确定性(我只是忘了这样做它 :))。至于模数,你是对的,但我发现模数更具可读性。我对性能的兴趣不如对同质性的兴趣。
-
如果您为四位值的序列/_blocks_ 而非每个四位值寻找哈希函数,请在标题和问题开头附近说明。做随机性测试,如果他们表明哈希值的序列很可能来自一个统一的随机源,那就最好了。 随机输入没有得到均匀分布。请证实
the results … do not seem very smooth to me. -
也许这就是灰胡子的目的,但这里有一个快速的实验可以尝试。计算介于 0(含)和表大小(不含)之间的均匀随机(加密质量伪随机)数的直方图。这对你来说还不够吗?