3

这可能已被广泛讨论,但我还找不到正确的答案。这是我的问题,我想在当前范围内输入一个数字,但该数字是随机的。我不使用

Random rand = new Random(); 
rand.Next(0,100);

数字来自GetHashCode(),,我必须把它放在* [0,someArray.Length)范围内;

我试过 :

int a = 12345;
int currentIndex = a.GetHashCode();
currentIndex % someArray.Length + someArrayLength

但它不起作用。我将不胜感激。

4

3 回答 3

4

我会去(hash & 0x7FFFFFFF) % modulus。掩码确保输入为正数,然后余数运算符%将其映射到目标范围。

替代方案包括:

result = hash % modulus;
if(result < 0)
    result += modulus;

result = ((hash % modulus) + modulus) % modulus

不幸的是,不起作用的是

result = Math.Abs(hash) % modulus

因为Math.Abs(int.MinValue)int.MinValue,因此是负的。要解决这种方法,可以转换为long

result = (int)(Math.Abs((long)hash)) % modulus)

所有这些方法都为某些输入范围和模值引入了微小的偏差,因为除非输入值的数量是模的整数倍,否则它们不能以相同的概率映射到每个输出值。在某些情况下,这可能是个问题,但对于哈希表来说没问题。

如果您主要关心性能,那么掩蔽解决方案更可取,因为与分支&相比便宜。%

于 2013-06-14T18:22:58.853 回答
1

处理负值的正确方法是使用双模。

int currentIndex = ((a.GetHashCode() % someArray.Length) + someArray.Length) % someArray.Length;

在混合中引入一些变量:

int len = someArray.Length;
int currentIndex = ((a.GetHashCode() % len) + len) % len;

这将首先使值范围从 -len 到 (len -1),所以当你添加 len 时,它的范围是从 0 到 len*2-1,然后你再次使用模数,这将把值在 0 到 len-1 的范围内,这就是你想要的。

此方法将处理 的所有有效值a.GetHashCode(),无需特殊处理int.MinValueint.MaxValue

请注意,此方法将确保如果您将 1 添加到输入(a.GetHashCode()在这种情况下,因此可能无关紧要),您最终会在输出中添加 1(当它到达末尾时将环绕为 0) . 使用Math.Abs或按位操作来确保正值的方法可能不像负数那样工作。这取决于你想要什么。

于 2013-06-14T18:21:23.807 回答
0

您应该能够使用:

int currentIndex = (a.GetHashCode() & 0x7FFFFFFF) % someArray.Length;

请注意,根据数组长度和 的实现GetHashCode,这可能不是随机分布。如果您Int32在示例代码中使用 as 则尤其如此,因为Int32.GetHashCode它只返回整数本身,因此无需调用GetHashCode.

于 2013-06-14T18:15:47.003 回答