标准库rand()函数的缺陷以及Blitz++随机数生成的简介

原创 2004年09月15日 06:44:00

标准库rand()函数的缺陷以及Blitz++随机数生成的简介

newsuppy, 转载请注明出处)

当我们需要在某个任务中使用随机数,通常我们习惯于使用标准库的rand函数。像这样:srand(time(0)); // 时间种子

        rand() % MAX_RAND

标准库的rand函数使用线性同余算法,是生成速度相当快的一种随机数生成算法。在多数情况下也确实能满足我们的要求,但是对于一些特殊目的应用这个算法生成的随机数是不行的,比如某些加密算法,蒙特卡罗积分等(在.NET中创建随机密码的加密安全随机数就不能使用Random类的线性同余随机数,而要使用System.Security.Cryptography命名空间中的相关随机数生成类)。

这个线性同余算法的实现可以在很多书籍中找到。下面我给出一个The C Programming Langurage 2nd中的一个实现,这也是普遍使用的标准库随机数算法的实现:

   unsigned long int next = 1;

 

   /* rand:  return pseudo-random integer on 0..32767 */

   int rand(void)

   {

       next = next * 1103515245 + 12345;

       return (unsigned int)(next/65536) % 32768;

   }

 

   /* srand:  set seed for rand() */

   void srand(unsigned int seed)

   {

       next = seed;

   }

 

这个实现的问题在于rand函数return行中的那个32768,在标准库中这个数字定义为RAND_MAX宏,在VisualC++Mingw32编译器的stdlib.h头文件(或者cstdlib)中你都可以发现RAND_MAX的值为32768。也就是说这个算法的随机数分布在0--RAND_MAX中,而在一般编译器中就是0--32768。假设你的算法需要的是300000多个的随机数,那么使用rand函数会产生重负次数近30次的随机数!

所以在这里我将简单介绍一下如何使用Blitz++库中的随机数生成类。不过在这里我不能够证明Blitz++随机数算法相对于标准库有什么优越性。Blitz++的源代码是开放的,你可以完全了解它的随机数算法的实现

Blitz++中随机数类组织在ranlib namespace中,使用方法也非常简单,seed成员函数种入种子后,再用random成员函数就可以了。Blitz++中包括了产生各种概率分布情况的随机数,列举如下:均匀分布(Uniform),正态分布(Normal),指数分布(Exponential),Beta分布,Gamma分布,Χ方分布,F分布,离散均匀分布。具体地可以参考Blitz++文档的第九章。本文将会演示正态分布的随机数类。

NormalUnit<>()   标准正态分布,μ = 0, σ = 1; 

Normal<>(T mean, T standardDeviation) 正态分布,N(μ, σ^2),其中mean就是μ,standardDeviation就是σ

Blitz++中随机数类的seed是共享的,调用一个类的seed后,其他类也同样种入了相同的种子。对于种子的来源,Blitz++文档中有这样一个注意事项:

Note: you may be tempted to seed the random number generator from a static initializer. Don't do it! Due to an oddity of C++, there is no guarantee on the order of static initialization when templates are involved. Hence, you may seed the RNG before its constructor is invoked, in which case your program will crash. If you don't know what a static initializer is, don't worry -- you're safe!

(幸运的是我也不太清楚static initializer具体指什么,:- )

1,先来看一个标准正态分布的例子,根据3σ法则(正态分布的随机数几乎全部落在(μ-3σ,μ+3σ)),这些随机数应该大部分落在(-3, 3)之间。

下面的程序产生10000个正态分布随机数,然后导入Matlab生成图形,横坐标是随机数的序数,纵坐标是随机数值。很显然,大部分点在3σ区间内。在区间(μ-σ,μ+σ)中数据点最密。

#include <random/uniform.h>

#include <random/normal.h>

#include <iostream>

#include <fstream>

#include <ctime>

#include <cstdlib>

using namespace std;

using namespace ranlib;

 

int main()

{

    const size_t MAXGEN = 10000;

    NormalUnit<float> rnd;

 

    rnd.seed(time(0));

 

    ofstream file("c://file.txt");

 

    // generator Normal distribution random number

    for (size_t i=0; i<MAXGEN; ++i)

    {

        file << rnd.random() << " ";

    }

}

2下面是一个服从于μ= 10,σ= 2的正态分布,根据3σ法则,大部分点应该落在(4,16)之间。

#include <random/uniform.h>

#include <random/normal.h>

#include <iostream>

#include <fstream>

#include <ctime>

#include <cstdlib>

using namespace std;

using namespace ranlib;

 

int main()

{

    const size_t MAXGEN = 1000000;

    const int mu = 10;

    const int sigma = 2;

    Normal<float> rnd(mu,sigma);

 

    rnd.seed(time(0));

 

    ofstream file("c://file.txt");

 

    // generator Normal distribution random number

    for (size_t i=0; i<MAXGEN; ++i)

    {

        file << rnd.random() << " ";

    }

}

 

3,生成前述正态分布的钟型曲线(PDF)。

这里产生1M的float随机数,然后乘以10转型为整数,统计在区间0-170之间随机数出现的概率,这样再导入Matlab生成图形就是一个近似的正态分布的钟型曲线了。

 

 

#include <random/uniform.h>

#include <random/normal.h>

#include <iostream>

#include <fstream>

#include <ctime>

#include <cstdlib>

using namespace std;

using namespace ranlib;

 

int main()

{

    const size_t MAXGEN = 1000000;

    const int mu = 10;

    const int sigma = 2;

    Normal<float> rnd(mu,sigma);

 

    rnd.seed(time(0));

 

    ofstream file("c://file.txt");

 

    float *rndArray = new float[MAXGEN];

    // generator Normal distribution random number

    for (size_t i=0; i<MAXGEN; ++i)

    {

        rndArray[i] = rnd.random();

    }

 

    int *rndConvertIntArray = new int[MAXGEN];

    int multiple = 10;

    // convert float random number to integer

    for (size_t i=0; i<MAXGEN; ++i)

    {

        rndConvertIntArray[i] = int(rndArray[i] * multiple);

    }

 

    const size_t PDFSIZE = (mu + 3 * sigma) * multiple;

    const size_t redundancy = 10;

    int *pdf = new int[PDFSIZE+redundancy];

    for (size_t i=0; i<PDFSIZE+redundancy; ++i)

    {

        pdf[i] = 0;

    }

 

    // generator PDF(Probability Distribution Function), Normal distribution is a "bell" shape

    for (size_t i=0; i<MAXGEN; ++i)

    {

        if (rndConvertIntArray[i] <= PDFSIZE+redundancy-1)

        {

            ++pdf[rndConvertIntArray[i]];

        }

    }

 

    for (size_t i=0; i<PDFSIZE+redundancy; ++i)

    {

        file << pdf[i]  << " ";

    }

 

    delete[] rndArray;

    delete[] rndConvertIntArray;

    delete[] pdf;

}

 

钟型曲线,当然不是特别光滑(J),大部分随机数都出现在(416)区间内。

 

总结,Blitz++的随机数生成类应该说是值得信任的。

[参考文献]

1,  概率论与数理统计(3rd), 浙江大学 盛骤 谢式千 潘承毅 高等教育出版社

2,  C数值算法(2nd), [] William H. Press, Saul A. Teukolsky, William T. Vetterling,

                         Brian P. Flannery

                      傅祖芸 赵梅娜 丁岩石 等译,傅祖芸 审校

3Matlab 6.5的文档    The MathWorks, Inc.

每次rand出来都是41?说好的随机数呢?!

rand()函数是C++标准函数库提供的随机数生成器,生成0-RAND_MAX之间的一个“伪随机”整数,理论上可以产生的最大数值为2^16-1,即32767。 rand()函数不接受参数,默认以1为种...
  • dcrmg
  • dcrmg
  • 2016年07月30日 20:41
  • 1522

SQL中随机数函数rand()

在SQL Server中,有个随机函数rand(),
  • u014053368
  • u014053368
  • 2014年04月18日 00:50
  • 1460

标准库rand()函数的缺陷以及Blitz++随机数生成的简介

标准库rand()函数的缺陷以及Blitz++随机数生成的简介 分类: C++ 2004-09-15 06:44 5167人阅读 评论(2) 收藏 举报 randomgener...
  • BPSSY
  • BPSSY
  • 2013年12月08日 12:55
  • 1192

SQL server 内置函数之随机函数newid()和rand()

从A表随机取2条记录,用SELECT TOP 10 * FROM ywle order by newid() order by 一般是根据某一字段排序,newid()的返回值 是uniqueiden...
  • qq_16769857
  • qq_16769857
  • 2016年07月07日 12:35
  • 6634

rand函数的实现原理

rand函数的实现原理rand函数产生的是伪随机数,也就是说它不是一个真实的随机数。那么伪随机数是怎么实现的呢?原理大概如下:如果约定:a1=f(seed),an+1=f(an)a_1 = f(see...
  • Cashey1991
  • Cashey1991
  • 2015年04月14日 14:59
  • 10490

为什么rand()每次产生的随机数都一样

之所以rand()每次的随机数都一样是因为rand()函数使用不正确。各种编程语言返回的随机数(确切地说是伪随机数)实际上都是根据递推公式计算的一组数值,当序列足够长,这组数值近似满足均匀分布。如果计...
  • buku2010
  • buku2010
  • 2014年02月18日 12:51
  • 4232

产生随机数:sand()和rand()函数用法

个人认为较为可靠的产生随机数的代码范例: 例如产生 min~max 范围的整数随机数 #include   #include   #include   # define MIN 10...
  • xiongchuquan
  • xiongchuquan
  • 2014年03月23日 21:42
  • 779

C语言如何产生一个随机数,rand函数的使用

C语言中用于产生随机数的函数是rand(),下面我用程序说明一下如何在C语言下产生随机数。 示例代码如下: #include #include #include int main(int...
  • rookie_wei
  • rookie_wei
  • 2014年08月10日 01:24
  • 7328

产生随机数————srand函数与rand函数的使用

rand()的使用方法,srand(value)的使用方法,rand()与srand(value)的关系,rand()产生随机数的原理与细节分析...
  • zl_130
  • zl_130
  • 2016年08月22日 18:02
  • 1491

CUDA的随机数生成方法

CUDA Runtime API 没有提供用于生成随机数的接口,但是CURAND这个库提供了通过GPU生成随机数的接口,详细内容可参考点击打开链接...
  • hws912
  • hws912
  • 2014年02月26日 10:12
  • 2949
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:标准库rand()函数的缺陷以及Blitz++随机数生成的简介
举报原因:
原因补充:

(最多只允许输入30个字)