C# RNGCryptoServiceProvider:生成范围为[0,randomMax]的随机数
我编写了以下代码来生成[0,int.MaxValue)范围内的随机数,但我不确定如何在保持均匀分布的同时将范围限制为[0,randomMax]:C# RNGCryptoServiceProvider:生成范围为[0,randomMax]的随机数,c#,random,C#,Random,我编写了以下代码来生成[0,int.MaxValue)范围内的随机数,但我不确定如何在保持均匀分布的同时将范围限制为[0,randomMax]: private static int GetNextInt32(this RNGCryptoServiceProvider random) { var buffer = new byte[sizeof(int)]; random.GetBytes(buffer); return Math.Abs(BitConverter.ToInt32(b
private static int GetNextInt32(this RNGCryptoServiceProvider random)
{
var buffer = new byte[sizeof(int)];
random.GetBytes(buffer);
return Math.Abs(BitConverter.ToInt32(buffer, 0));
}
谢谢。这里有一种方法:。请参阅标题为“创建系统。随机替换”的部分
但是,请注意,使用模运算符可能不是确保良好分布的最佳方法。更好的方法可能是(int)(NextDouble()*(MaxValue-1));
您的代码存在潜在错误。如果缓冲区
包含十六进制值0080
,即int.MinValue
,Math.Abs
将引发异常
请注意,在
RNGCryptoServiceProvider
上调用GetBytes
比调用Random要慢得多。下一步
。最好调用GetBytes
来填充一个更大的缓冲区,然后从中提取随机数。我的示例演示了如何完成此操作。有一个合适算法的描述我在办公室
该算法反复拒绝任何会导致不均匀分布的值,然后重试。从理论上讲,这意味着在最坏的情况下,它可能会永远循环。实际上,它会非常快
下面是一个(完全未经测试的)C#翻译:
public static int GetNextInt32(this RNGCryptoServiceProvider rng, int maxValue)
{
if (maxValue < 1)
throw new ArgumentOutOfRangeException("maxValue", maxValue, "Value must be positive.");
var buffer = new byte[4];
int bits, val;
if ((maxValue & -maxValue) == maxValue) // is maxValue an exact power of 2
{
rng.GetBytes(buffer);
bits = BitConverter.ToInt32(buffer, 0);
return bits & (maxValue - 1);
}
do
{
rng.GetBytes(buffer);
bits = BitConverter.ToInt32(buffer, 0) & 0x7FFFFFFF;
val = bits % maxValue;
} while (bits - val + (maxValue - 1) < 0);
return val;
}
public static int GetNextInt32(此RNGCryptoServiceProvider rng,int maxValue)
{
如果(最大值<1)
抛出新ArgumentOutOfRangeException(“maxValue”,maxValue,“值必须为正”);
var buffer=新字节[4];
int位,val;
if((maxValue&-maxValue)==maxValue)//maxValue是2的精确幂吗
{
rng.GetBytes(缓冲区);
位=位转换器.ToInt32(缓冲区,0);
返回位&(maxValue-1);
}
做
{
rng.GetBytes(缓冲区);
位=位转换器.ToInt32(缓冲区,0)&0x7FFFFFFF;
val=位%maxValue;
}而(位-val+(最大值-1)<0);
返回val;
}
一篇MSDN杂志文章向您展示了如何创建使用加密RNG的随机
:
(这篇文章不再可以直接访问。它来自2007年9月的一期,标题是“CryptoRandom的故事”。你必须下载存档的一期。它是.chm,因此你必须在阅读它之前,将其从互联网上解锁。你也可以使用互联网存档。)如果你不需要太多的速度,也许你可以试试这个:
private static RNGCryptoServiceProvider _RNG = new RNGCryptoServiceProvider();
private static int GetNextRnd (int min, int max)
{
byte[] rndBytes = new byte[4];
_RNG.GetBytes(rndBytes);
int rand = BitConverter.ToInt32(rndBytes, 0);
const Decimal OldRange = (Decimal)int.MaxValue - (Decimal)int.MinValue;
Decimal NewRange = max - min;
Decimal NewValue = ((Decimal)rand - (Decimal)int.MinValue) / OldRange * NewRange + (Decimal)min;
return (int)NewValue;
}
这将根据您的值范围缩放整个范围int
number,以保持分布
我知道这是一篇老文章,但我遇到了一个类似的问题,这个解决方案对我很有效。Jim,
Next()%maxValue
是有偏差的;举个简单的例子,如果Next()
返回0、1、2或3均匀分布,Next()%3
返回0的频率是1或2的两倍。@Rawling:是的,我确实提到过使用模运算符可能会有问题。感谢您提供的具体示例。抱歉,我没有看到您的警告。