22

我需要生成范围为byteushortsbyteshortint和的随机数uint。我可以使用 C# 中的 Random 方法(例如values.Add((int)(random.Next(int.MinValue + 3, int.MaxValue - 2)));)为所有这些类型生成除 uint 之外的所有类型,因为Random.Next它只接受 int 值。

有没有一种简单的方法来生成随机数uint

4

4 回答 4

28

最简单的方法可能是使用两个调用:一个用于 30 位,一个用于最后两个。此答案的早期版本假设Random.Next()具有 的包容性上限int.MaxValue,但事实证明它是独占的 - 所以我们只能获得 30 个统一位。

uint thirtyBits = (uint) random.Next(1 << 30);
uint twoBits = (uint) random.Next(1 << 2);
uint fullRange = (thirtyBits << 2) | twoBits;

(当然,您可以将其取为两个 16 位值,作为替代方案……或介于两者之间的各种选项。)

或者,您可以使用NextBytes填充 4 字节数组,然后使用BitConverter.ToUInt32.

于 2013-06-13T05:59:23.970 回答
20

何塞的日光骰子

还是有一种简单的方法来生成真正的随机 uint?

我承认,这不是 OQ。很明显,有更快的方法来生成不真实的随机 uint。尽管如此,我认为没有人对生成这些太感兴趣,除非由于某种原因需要非平面分布。让我们从一些研究开始,以便在 C# 中轻松快速地完成它。当我编写代码时,简单和快速通常表现得像同义词。

第一:一些重要的属性

请参阅MSDN

Random构造函数:

  • Random()Random:使用与时间相关的默认种子值初始化类的新实例。
  • Random(int seed)Random:使用指定的种子值初始化类的新实例。

为了提高性能,创建一个Random对象以随着时间的推移生成许多随机数,而不是重复创建新Random对象以生成一个随机数,因此:

private static Random rand = new Random();

Random方法:

  • rand.Next():返回一个正随机数,大于等于零,小于int.MaxValue
  • rand.Next(int max):返回一个正随机数,大于等于0,小于max,max必须大于等于0。
  • rand.Next(int min, int max):返回一个正随机数,大于等于min,小于max,max必须大于等于min。

作业显示,rand.Next()它的速度大约是 的两倍rand.Next(int max)

第二:解决方案。

假设一个正整数只有两位,忘记符号位,它是零,rand.Next()以相等的概率返回三个不同的值:

00
01
10

对于真正的随机数,最低位为零的频率与最高位相同的频率为一。
为了使它适用于最低位使用:rand.Next(2)

假设一个 int 有 3 个位,rand.Next()返回 7 个不同的值:

000
001
010
011
100
101
110

要使其适用于最低两位,请使用:rand.Next(4)

假设一个 int 有n位。
要使其适用于n位,请使用:rand.Next(1 << n)

要使其在最多 30 位上工作,请使用:rand.Next(1 << 30)
它是最大值,1 << 31 大于int.MaxValue.

这导致了一种生成真正随机 uint 的方法:

private static uint rnd32()
{
    return (uint)(rand.Next(1 << 30)) << 2 | (uint)(rand.Next(1 << 2));
}

快速检查:产生零的机会是什么?

1 << 2 = 4 = 2 2 , 1 << 30 = 2 30

为零的机会是:1/2 2 * 1/2 30 = 1/2 32 uint 的总数,包括零:2 32
就像白天一样清晰,没有烟雾警报,不是吗?

最后:一个误导性的想法。

是否可以更快地使用rand.Next()

                            int.Maxvalue is:    (2^31)-1
   The largest value rand.Next() returns is:    (2^31)-2 
                           uint.MaxValue is:    (2^32)-1

rand.Next()使用两次并将结果相加时,最大可能值为:

2*((2^31)-2) = (2^32)-4 

与 uint.MaxValue 的区别在于:

(2^32)-1 - ((2^32)-4) = 3

要达到,必须添加uint.MaxValue另一个值,因此我们得到:rand.Next(4)

rand.Next() + rand.Next() + rand.Next(4)

产生零的机会是什么?

大约: 1/2 31 * 1/2 31 * 1/4 = 1/2 64,应该是 1/2 32

等一下,怎么样:

2 * rand.Next() + rand.Next(4)

同样,产生零的机会是什么?

大约: 1/2 31 * 1/4 = 1/2 33,太小而不能真正随机。

另一个简单的例子:

rand.Next(2) + rand.Next(2),所有可能的结果:

       0 + 0 = 0
       0 + 1 = 1
       1 + 0 = 1
       1 + 1 = 2

等概率?想都别想。

结论:真随机数相加得到一个随机数,但不是真随机数。掷两个公平的骰子...

于 2013-08-20T10:05:18.410 回答
5

生成随机数的最简单方法uint

uint ui = (uint) new Random().Next(-int.MaxValue, int.MaxValue);
于 2021-04-08T11:25:15.057 回答
1

使用 System.Random 设置范围,“uint u0 <= 返回值 <= uint u1”

从“零”(含)到“u”(含)的范围更容易开始。
你可以看看我的另一个 答案。 如果您对更快/更有效的方式感兴趣:
范围内的统一伪随机数。(这是相当多的代码/文本)。

在“rnd32(uint u)”下方返回: 0 <= value <= u 。
最困难的情况是:“u = int.MaxValue”。那么“do-loops”的第一次迭代
(外部和内部“do-loop”的单次迭代)返回有效值的机会是 50%。
两次迭代后,概率为 75%,以此类推。

外部“do-loop”迭代不止一次的机会很小。
在“u = int.MaxValue”的情况下:0%。

很明显:“rnd32(uint u0, uint u1)”返回一个介于 u0 (incl) 和 u1 (incl) 之间的值。

private static Random rand = new Random();

private static uint rnd32(uint u)                                 //  0 <= x <= u
{
    uint x;
    if (u < int.MaxValue) return (uint)rand.Next((int)u + 1);
    do                                         
    {
        do x = (uint)rand.Next(1 << 30) << 2;
        while (x > u);
        x |= (uint)rand.Next(1 << 2);
    }
    while (x > u);
    return x;
}

private static uint rnd32(uint u0, uint u1)                      // set the range
{
    return u0 < u1 ? u0 + rnd32(u1 - u0) : u1 + rnd32(u0 - u1);
}
于 2013-09-08T20:12:45.713 回答