有效地生成随机数

时间:2011-11-26 14:01:24

标签: c# algorithm language-agnostic random

如何有效地生成随机数? 每次随机数程序启动时,它都会像以前一样开始吐出相同的数字。 (我猜因为随机数生成的准性质)
有没有办法,随机#生成变得不确定?除了生成之外,引入后生成的数字与最后一个序列的顺序不同。 (随机随机而不是准随机)
此外,例如,这种生成的范围是(m,n)使得n-m = x,在生成x-1个其他数之后,有可能下次出现数字'p'。但是接下来很多这样的x数字与最后一个数字的序列不一样。例如:
范围:1,5。代:2,4,5,1,3(第一)4,2,3,1,5(第二)...... 相同的数字 我出于困惑的心态写下了这个:

int num1 = (rand.Next(1, 440) *31* (int)DateTime.Now.Ticks *59* (DateTime.Now.Second * 100) % 439) + 1;
int num2 = (rand.Next(1, 440) *31* (int)DateTime.Now.Ticks *59* (DateTime.Now.Second * 100) % 439) + 1;

这里的范围是(1,440)。但是它仍然会产生超出界限和零的数字,而且它的频率也不是那么好。它是C#.NET代码。为什么这样?
您的答案可以是语言不可知/算法/分析。提前谢谢。

5 个答案:

答案 0 :(得分:2)

很少“随机”数字生成器实际上是随机的。几乎所有都是伪随机的,当以相同的seed value开始时遵循可预测的序列。许多pseudorandom number generators(PRNG)从他们的初始调用的日期和时间获得他们的种子。其他人从操作系统提供的随机数据源中获取种子,这些数据通常是从外部源生成的(例如,鼠标移动,键盘活动)。

种子好的随机数生成器的正确方法是不播种它。每个好的发电机都有一个默认的机制来供应种子,它通常比你想出的任何产品好得多。种子生成器的唯一真正原因是,如果您实际上想要相同的随机数序列(例如,当您尝试重复需要随机性的过程时)。

有关C#Random类的详细信息,请参阅http://msdn.microsoft.com/en-us/library/system.random.aspx,但基本上,它使用了一个众所周知且受人尊敬的算法,并将其与日期和时间一起种下。

要回答您的关键问题,只需使用rand.Next(min, max+1)即可始终获取minmax之间的随机数字序列。每次使用相同的种子时,序列都是相同的。但是rand = new Random()将使用当前时间,并且只要您的程序在时间上分开调用,它们就会有所不同。

答案 1 :(得分:1)

通过获取自午夜以来的秒数然后将其传递到“

”来“种子”随机数生成器
Random rand = new Random(secs);

这仍然不会产生完全随机的数字,但应该符合您的目的。

答案 2 :(得分:1)

反复生成相同的序列通常是一个功能,而不是bug,只要你控制它。生成可重复的序列使调试更容易。如果你真的想要一个不可重现的随机序列,你可以寻找一个安全的随机数发生器,将其作为设计目标。你已经标记了你的问题C#,但由于Java有http://docs.oracle.com/javase/1.4.2/docs/api/java/security/SecureRandom.html且windows API有http://en.wikipedia.org/wiki/CryptGenRandom,你可以在C#中找到一个等价物。

答案 3 :(得分:0)

我不太熟悉C#。 但我不认为这个问题会在Java中发生,因为Random类的默认构造函数使用基于当前时间和唯一计数标识符的种子.Below是来自 java.util.Random 类的代码。

private static volatile long seedUniquifier = 8682522807148012L;
public Random() { this(++seedUniquifier + System.nanoTime()); }

如果C#doesent支持这个开箱即用,你可以使用上面的代码每次都创建一个独特的种子。

P.S:请注意,由于对seedUniquifier的访问不同步,即使其易失性,相同种子用于多个Random对象的可能性也很小。来自Random类的javadoc:

  

“此构造函数将随机数生成器的种子设置为a   值很可能与此构造函数的任何其他调用不同。“

答案 4 :(得分:0)

您可以使用混乱地图生成随机数。下面的C ++代码(GenRandRea)使用所谓的" Tent map"返回随机数的向量。 (https://www.wikiwand.com/en/Tent_map)。种子是一个整数,用于生成x(作为0和1之间的数字)作为迭代映射的输入。不同的种子将产生不同的序列。

vector<double> GenRandRea(unsigned seed, int VecDim){
double x, y, f;
vector<double> retval;

x = 0.5*(abs(sin((double)seed)) + abs(cos((double)seed)));

for (int i = 0; i<(tentmap_delay + VecDim); i++) {
    if ((x >= 0.) && (x <= 0.5)) {
        f = 2 * tentmap_r * x;
    }
    else {
        f = 2 * tentmap_r * (1. - x);
    }

    if (i>=tentmap_delay) {
        y = (x*tentmap_const) - (int)(x*tentmap_const);
        retval.push_back(y);
    }
    x = f;
}
return retval;

}

const double tentmap_r = 0.75; //parameter for the tent map
const int tentmap_delay = 50; /*number of interactions in the tent map 
                              allowing for sorting */
const double tentmap_const = 1.e6; //constant for the tent map

VecDim是输出向量维度。 ideia至少迭代(tentmap_delay + VecDim)并将结果写入retval(双精度矢量)。

使用此代码:

vector<double> val;

val = GenRandRea(2, 10);
for (int kk=0; kk<10;kk++){
    cout << setprecision(9) << val[kk] << endl;
}

例如会产生:

0.767902586 0.848146121 0.727780818 0.408328773 0.88750684 0.83126026 0.253109609 0.620335586 0.569496621 0.145755069

问候!