当我刚接触C#时,我真的不想乱用Random()很长一段时间试图得到我想要的东西,而且我也想知道它做了我需要做的事情而不给它在测试中花了很长时间。如何随机获得0.5%的概率(1/200)?这段代码会吗? Random是多么随机...这不是“随机是多么随机”的问题所以不要发布重复,但它是一个关于如何做到这一点的问题。
我的问题不是“随机是多么随机,如果这段代码是最好的工作方式,它会实现我想要实现的目标。”
var random = new Random();
var randomNumber = random.Next(1, 200);
if (randomNumber == 87)
{
// I can put any number inbetween 1 and 200, will this work?
// If we reach this if statement we have got a 0.5 chance?
}
答案 0 :(得分:3)
首先,您应该将机会转换为介于0.0和1.0之间的标准化值。这是概率的数学概念。
对于您的情况,这会给您double probability = 0.005;
。
然后您可以执行以下操作:
if (rng.NextDouble() < probability)
{
...
这是有效的,因为Random.NextDouble()
会返回在半开区间[0.0, 1.0)
内均匀分布的随机数(即最多但不包括1.0
。)
因此,如果您的概率为0.0
,if
的正文将永远不会被执行,如果您的概率为1.0
,那么它将始终执行。
使用归一化概率的优点是它可以任意概率,而不仅仅是积分概率。
如果您碰巧有百分比概率,则可以非常简单地将其转换为标准化概率 - 将其除以100.0
。
附录:
使用Random.Next(int min, int max)
代替它没有什么好处,因为这只适用于整数概率。在幕后,Random.Next(int min, int max)
实现如下:
public virtual int Next(int minValue, int maxValue) {
if (minValue>maxValue) {
throw new ArgumentOutOfRangeException("minValue",Environment.GetResourceString("Argument_MinMaxValue", "minValue", "maxValue"));
}
Contract.EndContractBlock();
long range = (long)maxValue-minValue;
if( range <= (long)Int32.MaxValue) {
return ((int)(Sample() * range) + minValue);
}
else {
return (int)((long)(GetSampleForLargeRange() * range) + minValue);
}
}
NextDouble()
实现为:
public virtual double NextDouble() {
return Sample();
}
请注意,这两个实现都会调用Sample()
。
最后我只想指出内置的Random类不是特别好 - 它没有很长的时间。我使用基于128位XOR-Shift的RNG,速度非常快,并产生非常“好”的随机数。
(我使用基于this XORSHIFT+ generator的。)