注意:为简洁起见,以下内容无法区分随机性和伪随机性.此外,在此上下文中,约束意味着给定的最小值和最大值之间)
本System.Random
类提供随机生成整数,双打和字节数组.使用Random.Next,可以轻松生成类型为布尔值,字符,(S)字节,(U)Int16,(U)Int32的随机约束值.使用时Random.NextDouble()
,可以类似地生成Double和Single类型的约束值(就我对此类型的理解而言).随机串生成(给定长度和字母的)已经 也 被 解决 之前.
考虑剩余的原始数据类型(不包括Object):Decimal和(U)Int64.他们的随机生成也已被解决(Decimal,(U)Int64使用Random.NextBytes()
),但不受限制.理论上可以使用拒绝采样(即循环直到生成的值是所需范围),但这显然不是一个实际的解决方案.归一化NextDouble()
不起作用,因为它没有足够的有效数字.
简而言之,我要求正确实现以下功能:
long NextLong(long min, long max)
long NextDecimal(decimal min, decimal max)
Run Code Online (Sandbox Code Playgroud)
请注意,由于System.DateTime
基于ulong,第一个函数也允许随机约束生成此类结构(类似于此处,仅在刻度而不是分钟内).
这应该做到这一点.对于十进制,我使用Jon Skeet的初始方法来生成随机decimal
s(无约束).因为long
我提供了一种产生随机非负long
s的方法,然后用它来创建随机范围内的a值.
请注意,decimal
由此产生的分布不是均匀分布[minValue, maxValue]
.它只是在小数的所有位表示中均匀,落在该范围内[minValue, maxValue]
.如果不使用拒绝采样,我没有看到一个简单的方法.
对于long
所得到的分布是均匀的上[minValue, maxValue)
.
static class RandomExtensions {
static int NextInt32(this Random rg) {
unchecked {
int firstBits = rg.Next(0, 1 << 4) << 28;
int lastBits = rg.Next(0, 1 << 28);
return firstBits | lastBits;
}
}
public static decimal NextDecimal(this Random rg) {
bool sign = rg.Next(2) == 1;
return rg.NextDecimal(sign);
}
static decimal NextDecimal(this Random rg, bool sign) {
byte scale = (byte)rg.Next(29);
return new decimal(rg.NextInt32(),
rg.NextInt32(),
rg.NextInt32(),
sign,
scale);
}
static decimal NextNonNegativeDecimal(this Random rg) {
return rg.NextDecimal(false);
}
public static decimal NextDecimal(this Random rg, decimal maxValue) {
return (rg.NextNonNegativeDecimal() / Decimal.MaxValue) * maxValue; ;
}
public static decimal NextDecimal(this Random rg, decimal minValue, decimal maxValue) {
if (minValue >= maxValue) {
throw new InvalidOperationException();
}
decimal range = maxValue - minValue;
return rg.NextDecimal(range) + minValue;
}
static long NextNonNegativeLong(this Random rg) {
byte[] bytes = new byte[sizeof(long)];
rg.NextBytes(bytes);
// strip out the sign bit
bytes[7] = (byte)(bytes[7] & 0x7f);
return BitConverter.ToInt64(bytes, 0);
}
public static long NextLong(this Random rg, long maxValue) {
return (long)((rg.NextNonNegativeLong() / (double)Int64.MaxValue) * maxValue);
}
public static long NextLong(this Random rg, long minValue, long maxValue) {
if (minValue >= maxValue) {
throw new InvalidOperationException();
}
long range = maxValue - minValue;
return rg.NextLong(range) + minValue;
}
}
Run Code Online (Sandbox Code Playgroud)
让我们假设您知道如何生成N个随机位.使用NextBytes
或重复调用Random.Next
具有适当的限制非常容易.
要在正确的范围内生成long/ulong,请确定范围的大小以及表示它所需的位数.然后,可以使用排斥采样,这将在最坏的情况(如果你想在范围[0,128],这意味着你将生成[0,255]多次的值例如)拒绝一半生成的值.如果你想要一个非零的范围,只需计算范围的大小,生成[0,大小)的随机值,然后添加基数.
生成一个随机小数显然更难,我相信 - 除了其他任何东西,你必须指定你想要的分布.
归档时间: |
|
查看次数: |
6621 次 |
最近记录: |