我需要在C#中生成0到1之间的随机数。它不需要比单个小数位更精确,但如果是,则不是问题。
我可以Random.Next(0, 10) / 10.0
或Random.NextDouble()
。
我找不到任何一种方法的时间复杂性的具体信息。我假设Random.Next()
将像Java一样更高效,但是除法的加法(其复杂性将取决于C#使用的方法)使事情变得复杂。
是否有可能从理论的角度找出哪种更有效?我意识到我可以通过一系列测试来计算时间,但是想要理解为什么一个测试的复杂性要高于另一个测试。
答案 0 :(得分:3)
查看implmenentation source code,NextDouble()
会更有效率。
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纳秒仍然有所不同,那么第二种方法会快一点。