Random.Next()与Random.NextDouble()的效率

时间:2018-03-15 13:41:24

标签: c# performance random time-complexity

我需要在C#中生成0到1之间的随机数。它不需要比单个小数位更精确,但如果是,则不是问题。

我可以Random.Next(0, 10) / 10.0Random.NextDouble()

我找不到任何一种方法的时间复杂性的具体信息。我假设Random.Next()将像Java一样更高效,但是除法的加法(其复杂性将取决于C#使用的方法)使事情变得复杂。

是否有可能从理论的角度找出哪种更有效?我意识到我可以通过一系列测试来计算时间,但是想要理解为什么一个测试的复杂性要高于另一个测试。

2 个答案:

答案 0 :(得分:3)

查看implmenentation source codeNextDouble()会更有效率。

NextDouble()只需调用Sample()方法:

public virtual double NextDouble() {
    return Sample();
}

Next(maxValue)对maxvalue进行比较,调用Sample(),将值乘以maxvalue,将其转换为int并返回:

public virtual int Next(int maxValue) {
    if (maxValue<0) {
        throw new ArgumentOutOfRangeException("maxValue", Environment.GetResourceString("ArgumentOutOfRange_MustBePositive", "maxValue"));
    }
    Contract.EndContractBlock();
    return (int)(Sample()*maxValue);
}

因此,正如您所看到的,Next(maxValue)正在执行与NextDouble()相同的工作,然后再做更多工作,因此NextDouble()将更有效地返回0到1之间的数字

对于Mono用户,您可以在此处查看NextDouble()Next(maxValue)实施。 Mono做的有点不同,但它基本上涉及与官方实施相同的步骤。

正如佐兰所说,你需要产生大量的随机数来注意差异。

答案 1 :(得分:2)

无论哪种方式,你每秒都能产生数百万甚至数十亿的随机数。你真的需要那么多吗?

在更具体的层面上,两种变体都具有时间复杂度O(1),这意味着您可以测量两种方法之间的时间差异,即可。

Random generator = new Random();

int count = 1_000_000;
Stopwatch sw = new Stopwatch();
sw.Start();
double res;
for (int i = 0; i < count; i++)
    res = generator.Next(0, 10) / 10.0;
sw.Stop();

Stopwatch sw1 = new Stopwatch();
sw1.Start();
for (int i = 0; i < count; i++)
    res = generator.NextDouble();
sw1.Stop();

Console.WriteLine($"{sw.ElapsedMilliseconds} - {sw1.ElapsedMilliseconds}");

此代码在我的计算机上打印44毫秒:29毫秒。而且 - 我不认为你应该优化一项操作,这项操作在一百万次执行中需要44毫秒。

如果每次执行15纳秒仍然有所不同,那么第二种方法会快一点。