是否可以生成2个双精度数之间的随机数?
例:
public double GetRandomeNumber(double minimum, double maximum)
{
return Random.NextDouble(minimum, maximum)
}
然后,我将其称为:
double result = GetRandomNumber(1.23, 5.34);
任何想法将不胜感激。
是否可以生成2个双精度数之间的随机数?
例:
public double GetRandomeNumber(double minimum, double maximum)
{
return Random.NextDouble(minimum, maximum)
}
然后,我将其称为:
double result = GetRandomNumber(1.23, 5.34);
任何想法将不胜感激。
Answers:
是。
Random.NextDouble返回一个介于0和1之间的双精度值。然后将其乘以您需要进入的范围(最大值和最小值之差),然后将其加到基数(最小值)。
public double GetRandomNumber(double minimum, double maximum)
{
Random random = new Random();
return random.NextDouble() * (maximum - minimum) + minimum;
}
实际代码应具有随机的静态成员。这将节省创建随机数生成器的成本,并使您可以非常频繁地调用GetRandomNumber。由于我们在每次通话时都会初始化一个新的RNG,因此如果您调用得足够快,以至于两次通话之间的系统时间都不会改变,则RNG将使用完全相同的时间戳进行播种,并生成相同的随机数流。
public double GetRandomNumber(this Random random, double minimum, double maximum) {...}
Johnny5建议创建一个扩展方法。这是一个更完整的代码示例,显示如何执行此操作:
public static class RandomExtensions
{
public static double NextDouble(
this Random random,
double minValue,
double maxValue)
{
return random.NextDouble() * (maxValue - minValue) + minValue;
}
}
现在,您可以像调用Random
类中的方法一样调用它:
Random random = new Random();
double value = random.NextDouble(1.23, 5.34);
请注意,您不应Random
在循环中创建许多新对象,因为这将使您有可能连续多次获得相同的值。如果您需要大量随机数,请创建一个实例Random
并重新使用它。
注意:如果要在random
内部生成循环(例如)for(int i = 0; i < 10; i++)
,请不要将new Random()
声明放入循环内。
从MSDN:
随机数生成从种子值开始。如果重复使用相同的种子,则会生成相同的数字序列。产生不同序列的一种方法是使种子值与时间相关,从而在每个新的Random实例中产生不同的序列。默认情况下,Random类的无参数构造函数使用系统时钟生成其种子值...
因此,基于此事实,请执行以下操作:
var random = new Random();
for(int d = 0; d < 7; d++)
{
// Actual BOE
boes.Add(new LogBOEViewModel()
{
LogDate = criteriaDate,
BOEActual = GetRandomDouble(random, 100, 1000),
BOEForecast = GetRandomDouble(random, 100, 1000)
});
}
double GetRandomDouble(Random random, double min, double max)
{
return min + (random.NextDouble() * (max - min));
}
这样一来,您可以保证获得不同的double值。
我参加聚会有点晚了,但是我需要实施一个通用的解决方案,结果证明这些解决方案都无法满足我的需求。
公认的解决方案适用于小范围;但是,maximum - minimum
对于较大范围,可以是无穷大。因此,更正的版本可以是以下版本:
public static double NextDoubleLinear(this Random random, double minValue, double maxValue)
{
// TODO: some validation here...
double sample = random.NextDouble();
return (maxValue * sample) + (minValue * (1d - sample));
}
即使在double.MinValue
和之间,这也会很好地生成随机数double.MaxValue
。但这引入了另一个“问题”,在本文中很好地介绍了这个问题:如果我们使用如此大的范围,则值似乎太“不自然”。例如,生成10,000个随机双精度double.MaxValue
值后,0之间的所有值都在2.9579E + 304和1.7976E + 308之间。
因此,我还创建了另一个版本,该版本以对数刻度生成数字:
public static double NextDoubleLogarithmic(this Random random, double minValue, double maxValue)
{
// TODO: some validation here...
bool posAndNeg = minValue < 0d && maxValue > 0d;
double minAbs = Math.Min(Math.Abs(minValue), Math.Abs(maxValue));
double maxAbs = Math.Max(Math.Abs(minValue), Math.Abs(maxValue));
int sign;
if (!posAndNeg)
sign = minValue < 0d ? -1 : 1;
else
{
// if both negative and positive results are expected we select the sign based on the size of the ranges
double sample = random.NextDouble();
var rate = minAbs / maxAbs;
var absMinValue = Math.Abs(minValue);
bool isNeg = absMinValue <= maxValue ? rate / 2d > sample : rate / 2d < sample;
sign = isNeg ? -1 : 1;
// now adjusting the limits for 0..[selected range]
minAbs = 0d;
maxAbs = isNeg ? absMinValue : Math.Abs(maxValue);
}
// Possible double exponents are -1022..1023 but we don't generate too small exponents for big ranges because
// that would cause too many almost zero results, which are much smaller than the original NextDouble values.
double minExponent = minAbs == 0d ? -16d : Math.Log(minAbs, 2d);
double maxExponent = Math.Log(maxAbs, 2d);
if (minExponent == maxExponent)
return minValue;
// We decrease exponents only if the given range is already small. Even lower than -1022 is no problem, the result may be 0
if (maxExponent < minExponent)
minExponent = maxExponent - 4;
double result = sign * Math.Pow(2d, NextDoubleLinear(random, minExponent, maxExponent));
// protecting ourselves against inaccurate calculations; however, in practice result is always in range.
return result < minValue ? minValue : (result > maxValue ? maxValue : result);
}
一些测试:
以下是Double.MaxValue
两种策略在0和0之间生成10,000个随机双数的排序结果。结果使用对数刻度显示:
尽管乍看之下线性随机值似乎是错误的,但统计数据表明它们中的任何一个都不比另一个“好”:即使线性策略也具有均匀的分布,并且两种策略的值之间的平均差异几乎相同。
在不同的范围内玩游戏可知,线性策略变得“理智”,范围介于0和ushort.MaxValue
“合理”最小值为10.78294704(对于ulong
范围,最小值为3.03518E + 15 ; int
: 353341)。这些是两种策略以不同的比例显示的相同结果:
编辑:
最近,我使我的库开源,可以随时RandomExtensions.NextDouble
通过完整的验证查看该方法。
如果值之一为负怎么办?更好的主意是:
double NextDouble(double min, double max)
{
if (min >= max)
throw new ArgumentOutOfRangeException();
return random.NextDouble() * (Math.Abs(max-min)) + min;
}
Math.Abs()
是多余的。由于您确保了min >= max
,因此max - min
无论如何都必须是一个非负数。
如果您需要[[ double.MinValue
; double.MaxValue
]
// Because of:
double.MaxValue - double.MinValue == double.PositiveInfinity
// This will be equals to NaN or PositiveInfinity
random.NextDouble() * (double.MaxValue - double.MinValue)
改用:
public static class RandomExtensions
{
public static double NextDoubleInMinMaxRange(this Random random)
{
var bytes = new byte[sizeof(double)];
var value = default(double);
while (true)
{
random.NextBytes(bytes);
value = BitConverter.ToDouble(bytes, 0);
if (!double.IsNaN(value) && !double.IsInfinity(value))
return value;
}
}
}
关于在循环中调用它时生成相同的随机数的一个不错的解决方案是,将循环外的新Random()对象声明为全局变量。
注意,如果要在循环中运行此类,则必须在GetRandomInt函数之外声明Random类的实例。
“为什么是这样?” 你问。
好吧,Random类实际上会生成伪随机数,而随机化器的“种子”是系统时间。如果您的循环足够快,则系统时钟时间将不会与随机化器不同,并且Random类的每个新实例都将从相同的种子开始,并为您提供相同的伪随机数。
来源在这里:http : //www.whypad.com/posts/csharp-get-a-random-number-between-x-and-y/412/
使用静态随机数,否则由于系统时钟为它们播种,因此数字倾向于在紧密/快速循环中重复。
public static class RandomNumbers
{
private static Random random = new Random();
//=-------------------------------------------------------------------
// double between min and the max number
public static double RandomDouble(int min, int max)
{
return (random.NextDouble() * (max - min)) + min;
}
//=----------------------------------
// double between 0 and the max number
public static double RandomDouble(int max)
{
return (random.NextDouble() * max);
}
//=-------------------------------------------------------------------
// int between the min and the max number
public static int RandomInt(int min, int max)
{
return random.Next(min, max + 1);
}
//=----------------------------------
// int between 0 and the max number
public static int RandomInt(int max)
{
return random.Next(max + 1);
}
//=-------------------------------------------------------------------
}
另请参阅:https : //docs.microsoft.com/zh-cn/dotnet/api/system.random?view=netframework-4.8
Random random = new Random();
double NextDouble(double minimum, double maximum)
{
return random.NextDouble()*random.Next(minimum,maximum);
}