生成随机uint
我需要生成带有byte
, ushort
, sbyte
, short
, int
和uint
范围的随机数。 我能够使用C#中的Random方法为所有这些类型生成(例如values.Add((int)(random.Next(int.MinValue + 3, int.MaxValue - 2)));
)除了因为Random.Next
uint Random.Next
仅接受最多int值。
是否有一种简单的方法来生成随机uint
?
最简单的方法可能是使用两个调用:一个用于30位,一个用于最后两个。 这个答案的早期版本假设Random.Next()
具有int.MaxValue
的包含上限,但事实certificate它是独占的 – 所以我们只能获得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
。
何塞的日光骰子
或者有一种简单的方法来生成一个真正的随机uint?
我承认,这不是OQ。 很明显,有更快的方法来生成不是真实的随机uints。 尽管如此,我认为没有人对产生这些产品过于兴趣,除非出于某种原因需要非平面分布。 让我们从一些研究开始,在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)
:返回一个正的随机数,大于或等于零,小于max,max必须大于或等于零。 -
rand.Next(int min, int max)
:返回一个正的随机数,大于或等于min,小于max,max必须大于或等于min。
作业显示rand.Next()
大约是rand.Next(int max)
两倍。
第二:解决方案。
假设一个正int只有两位,忘记符号位,它为零, rand.Next()
以相同的概率返回三个不同的值:
00 01 10
对于真随机数,最低位经常为零,对于最高位是相同的。
为了使它适用于最低位使用: rand.Next(2)
假设int有三位, rand.Next()
返回七个不同的值:
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总的数量,包括零: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
平等概率? 想都别想。
结论:添加真随机数给出一个随机数,但不是真正的随机数。 扔两个公平的骰子......
使用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); }
public uint NextUInt() { uint x=int.MinValue; uint y; uint z; uint w; uint t= (x^(x<<11)); x=y; y=z; z=w; return (w= (w^(w>>19))^(t^(t>>8))); }
请尝试此function。