随机数

来源:互联网 发布:金融的网络销售好做吗 编辑:程序博客网 时间:2024/04/27 02:09
多样化是生活的一大乐趣,而计算机却似乎完全是可预见的,因此显得较死板,随机数为计算机程序注入了不可预见的东西,因此可以让计算机更好地模拟外部事件。比如游戏,图形显示,计算机仿真,随机数增加了许多的乐趣,而且当计算机程序重复运行时,不会表现出跟它模仿的自然系统有什么不同之处。


我们打算设计一个class Random, 它的成员函数生成和返回各种各样的随机数。
将要生成随机数的思想是,从一个数出发,对它进行一系列的算术运算,产生一个与开始那个数没有明显的关系的一个数。因此通过这种方法产生的数实际上一点也不随机,因为每一个数都依赖于它之前的一个数,而且这种依赖是固定的。我们应该更确切地叫它伪随机数(pseudorandom)。那个开始的数叫做随机种子(seed).
如果程序每次都从同一个种子开始运行,那么得到的整个伪随机数序列将会是完全一样的。因此我们可以产生任意已经得到过的实验结果。然而,假如客户希望随机数不仅是不可预测(unpredicable),而且还要不可重复生成的(unproducible)。因此我们应该提供一个根据现在的时间(精确到秒)来产生随机种子。因为程序每次运行的时刻很可能是不同的,这种初始化的方式会使客户程序每一次运行产生不同的行为。
我们打算为class Random提供一个构造函数,用一个参数bool pseudo来提供两种初始化随机种子的方式。当pseudo==true, 将用预定义的种子来产生随机数,反之,当pseud==false, 我们将产生unproducible的随机数。这种情况下,客户也无需特别地去初始化随机种子,程序会自动根据当前时间来初始化之。

源代码
//使用类应包括下列头文件

#include<iostream>   //  cout, cin, NULL
#include<climits>     // <limits.h>   define INT_MAX
#include<ctime>      // or <time.h>
#include<cmath>     // or <math.h>
#include<iomanip>    // setprecision(std::streamsize)
using namespact std;

/*************************************************************************/
//类声明:

class Random {
public:
   Random(
bool pseudo = true);         // 构造函数
   double random_real();                // 产生0~1之间的实数
   int random_integer(int low, int high);  // 产生low ~~ high 之间的整形随机数
   int poisson(double mean);            // 泊松分布
 private:
   
int reseed();                        //  Re-randomize the seed.
   int seed,
       multiplier, add_on;              
//  constants for use in arithmetic operations
}
;


/*
核心函数是下面这个更新随机种子的reseed函数,给其他函数调用来产生随机化行为。
*/


int Random::reseed()
/*
Post: The seed is replaced by a pseudorandom successor.
*/

{
   seed 
= seed * multiplier + add_on;
   
return seed;
}


/* 常量multiplier和add_on保存在类得数据成员中,它们不应该随便选择,应该谨慎选择以保证结果的随机性,使其能多次变换。例如下面构造函数的值在16位机中表现得很好
*/

Random::Random(bool pseudo)
/*
Post: The values of seed, add_on, and multiplier are
      initialized.  The seed is initialized randomly only if pseudo == false.
*/

{
   
if (pseudo) seed = 1;
   
else seed = time(NULL) % INT_MAX;
   multiplier 
= 2743;
   add_on 
= 5923;
}


/*
为了产生不可测的种子,我们用到了函数time(),它是包含在time.h头文件中,它计算从1970年开始流逝过的时间,单位是秒。INT_MAX是int型变量的最大值
*/

double Random::random_real()
/*
Post: A random real number between 0 and 1 is returned.
*/

{
   
double max = INT_MAX + 1.0;
   
double temp = reseed();
   
if (temp < 0) temp = temp + max;
   
return temp / max;
}


/*
下面这个函数是产生的随机数形式是整形数。实际上,我们说随机整数是不准确的,因为整形数是无限的,而计算机表示的数是有限的。因此一个真正的随机数是计算机表示的数中的一个的概率是0。 而我们只考虑在low ~ high 之间的整数。
*/

int Random::random_integer(int low, int high)
/*
Post: A random integer between low and high (inclusive) is returned.
*/

{
   
if (low > high) return random_integer(high, low);
   
else return ((int) ((high - low + 1* random_real())) + low;
}


/*
泊松分布(Poisson distribution)
我们从称一个正实数为随机数的期望值(expected value)开始,如果一个非负整数序列满足期望值为v的泊松分布,那么足够长的子序列的平均值【mean(average) value】将趋近于v
例如期望值为1.5,我们可能读入一个序列: 1, 0, 2, 2, 1, 1, 3, 0, 1, 2, 0, 0, 2, 1, 3, 4, 2, 3, 1, 1, ....如果你计算子序列的平均值的话,你会发现有时小于1.5,有时大于,但慢慢地,它总的趋势会是1.5。
下面这个函数产生平均值为mean的泊松分布.  理论推导与证明省略。
*/

int Random::poisson(double mean)
/*
Post: A random integer, reflecting a Poisson distribution
      with parameter mean, is returned.
*/

{
   
double limit = exp(-mean);
   
double product = random_real();
   
int count = 0;
   
while (product > limit) {
      count
++;
      product 
*= random_real();
   }

   
return count;
}


/*************************************************************************/


C/C++头文件<cstdlib>(注:新版编译器支持) 或<stdlib.h>(注:旧式的头文件格式)提供了生成随机数的函数。 这些函数可以替代本文中的函数。但是系统生成的随机数有时不是很理想,因此值得研究怎么构造更好的随机数。
比如  
 
     srand((unsigned)time( NULL ) );    //Seed the random-number generator with current time so that the                                                                             //numbers will be different every time we run.
    int i=rand()%(r-p)+p;                           // rand() 返回0-RAND_MAX (32767)的伪随机数

这样得到i就会是p ~ r 之间的一个随机数.

原创粉丝点击