1

如果我想为 Int32 可以包含的所有可能的数字生成一个随机数,那么下面的代码是一种合理的方法吗?有什么理由说明它可能不是一个好主意吗?(即均匀分布至少与 Random.Next() 本身一样好)

    public static int NextInt(Random Rnd) //-2,147,483,648 to 2,147,483,647
    {
         int AnInt;
         AnInt = Rnd.Next(System.Int32.MinValue, System.Int32.MaxValue);
         AnInt += Rnd.Next(2);
         return AnInt;
    }
4

4 回答 4

3

您可以使用Random.NextBytes获取 4 个字节,然后使用BitConverter.ToInt32将它们转换为int.

就像是:

byte[] buf = new byte[4];
Rnd.NextBytes(buf);
int i = BitConverter.ToInt32(buf,0);
于 2012-07-08T08:16:54.683 回答
2

您提出的解决方案会稍微扭曲分布。minValue 和 maxValue 的出现频率将低于内部值。例如,假设 int 的 MinValue 为 -2,MaxValue 为 1。以下是可能的初始值,每个初始值后跟 Random(2) 之后的结果值:

-2: -2 -1
-1: -1  0
 0:  0  1

负值 -2 的一半将被修改为 -1,只有一半的 0 将被修改为 1。因此值 -2 和 1 的出现频率低于 -1 和 0。

Damien的解决方案很好。另一种选择是:

if (Random(2) == 0) {
    return Random(int.MinValue, 0);
} else {
    return 1 + Random(-1, int.MaxValue);
}

另一种解决方案,类似于 Damiens 方法,比以前的方法更快

 int i = r.Next(ushort.MinValue, ushort.MaxValue + 1) << 16;
 i |= r.Next(ushort.MinValue, ushort.MaxValue + 1);
于 2012-07-08T08:26:53.053 回答
0

均匀分布并不意味着每个数字都只得到一次。为此,您需要一个排列

现在,如果你需要对所有40 亿个数字进行随机排列,你就有点卡住了。.NET 不允许对象大于 2GB。你可以解决这个问题,但我认为这并不是你真正需要的。

如果你在没有重复的情况下减少数字(比如 100 或 500 万,少于几十亿),你应该这样做:

维护一组整数,从空开始。选择一个随机数。如果它已经在集合中,请选择另一个随机数。如果它不在集合中,请将其添加并返回。

这样你就保证每个数字只会返回一次。

于 2012-07-08T08:10:44.780 回答
0

我有一个类,我将随机字节放入一个 8KB 缓冲区并通过将它们从随机字节转换来分配数字。这为您提供了完整的 int 分布。8KB 缓冲区用于您不需要为每个新的随机字节 [] 调用 NextBytes。

    // Get 4 bytes from the random buffer and cast to int (all numbers equally this way 
    public int GetRandomInt()
    {
        CheckBuf(sizeof(int));
        return BitConverter.ToInt32(_buf, _idx);
    }

    // Get bytes for your buffer. Both random class and cryptoAPI support this
    protected override void GetNewBuf(byte[] buf)
    {
        _rnd.NextBytes(buf);
    }

    // cyrptoAPI does better random numbers but is slower
    public StrongRandomNumberGenerator()
    {
        _rnd = new RNGCryptoServiceProvider();
    }
于 2012-07-08T08:22:11.673 回答