c++生成四行五列伪随机数列列的代码

C++ 如何生成大随机数?
由于C++rand()函数的最大值只有0x7FFF,写了一种方法类似于这样的:如果我想从0-999999中随机一个数,最好的方法当然是直接随机了,但是做不到,那么这样做,从0-999随机一个数,乘以1000,再加上0-999中随机一个数,这样做,跟直接随机的效果是一样的吗?
因为你并不一定知道原来的 rand() 是怎么实现的,所以这个问题并没有一定的回答。在现实中,简单地说,可以这样拼合,但要注意你的应用。如果原来的 rand() 函数实现得很理想,就是独立同均匀分布从 0 到 RAND_MAX,那你当然可以通过把两个随机数拼起来得到一个大的随机数。这种理想情况很容易算出新的随机变量也是独立同均匀分布的。不过事实上我们知道 C 运行时的 rand() 函数通常都是伪随机数发生器,我们还知道大部分就是线性同余算法。更确切地说,最大值 RAND_MAX == 0x7FFF 的是 VC 的运行时,我们甚至可以直接看到实现:int __cdecl rand (
_ptiddata ptd = _getptd();
return( ((ptd-&_holdrand = ptd-&_holdrand * 214013L
+ 2531011L) && 16) & 0x7fff );
就是一个线性同余随机发生器输出是取除最高位的高 15 位的结果(32 位整数先右移 16 位,再取低 15 位)。下面的讨论如果涉及具体范围,我们就假定 RAND_MAX 是上面的 32767。这种伪随机数两个拼起来,统计性质多少会所下降——至少我们知道重复周期会变短为原来的一半对吧。不过,经过适当选择迭代常数的线性同余算法,其高维联合分布的性质仍然是可接受的——这本来也是选择伪随机数算法参数的一个重要指标。VC 这里使用的库函数,实际就是 Intel 推荐的一个具体实现,简单分析可以看:从上面的二维直方图可以看出,这个函数的二维分布也可以通过直方图检验,因而像你说的这样使用没有大的问题。当然,应该是把两个 15bit 的随机数拼合成一个 30bit 的来使用。从上面的二维直方图可以看出,这个函数的二维分布也可以通过直方图检验,因而像你说的这样使用没有大的问题。当然,应该是把两个 15bit 的随机数拼合成一个 30bit 的来使用。在实践中,现代编译器所选择的运行时库,伪随机数发生器的质量都还不错,这与多年前的情况不大一样。当然,如果是对随机数要求比较高的场合,还是应该做更完整的测试或者选择更好的随机数发生器。但是等等,只要不溢出,这样当然可以取得很大的随机数,但却并不能取得我们需要的随机数。因为我们实际中使用的随机数范围,通常不会那么巧合就是
区间的整数,也不会是
区间的整数。我们需要的,可能是 [100, 155] 之间的整数,也可能是 [5.0, 27.0] 之间的浮点数。也就是说,rand() 函数得到的随机数只是固定区间上均匀分布的整数,我们需要把它映射为指定区间上指定分布的指定类型的随机数。这怎么办?指定分布涉及随机变量的数学变换,我们暂且放在一边。如果就是均匀分布,如何?对于均匀分布的整数,比如说 [100, 155],起点不是 0,终点也不是 RAND_MAX,怎么办?起点不是 0 好办,只要做一个加法平移,[0, RAND_MAX] 区间自然就变换为 [a, RAND_MAX+a] 区间了。但区间长度不同,一个是 155-100+1 = 56,一个是 RAND_MAX+1 = 32768,就需要放缩。人们对区间放缩想出了一些不同的办法,最简单的办法是取模。比如说,100 + rand() % 55 就是一个可以把 rand() 映射到 [100, 155] 区间上的一个办法。取模的办法虽然简单,但并不准确,因为你不能把 32768 按 56 长度等分(32768 / 56 = 585 余 8),那么必然最后一些数字比前面的出现概率要小一点——准确点儿说,前面 8 个数出现的概率是 586/32768,后面 48 个数出现的概率是 585/32768,后面的比前面的出现概率小 1/32768。为了避免这种问题,一种准确的办法就是,取到 rand() 为 [0, 32767] 区间内的整数后,先判断它是否超过 585*56=32760,如果超过了就舍去它重新取 rand(),否则才对 rand() 值取模(或者除以 585),得到准确均匀分布的随机数。——这种舍弃、重取的机制在理论上可能导致算法不终止,因为有可能每次随机数发生器总返回需要舍弃的数,但算法终止的概率随着步骤数而趋于 1(对于算法生成的伪随机数一定在有限步终止),并且只要舍弃的数比保留的数少,就能知道需要重复的步骤数期望小于 2。因而这是一个实用的算法,如 gcc 使用的 libstdc++ 库,大约就使用这种方式(见下节)。上面没有说清楚的是,如果 RAND_MAX 比需要的区间长度还小,那么就需要回到最开始的问题了:可以用两个、三个或更多的 rand() 函数,通过 (RAND_MAX+1) 进制数表示的方式拼合成一个大的随机数。前面已经说了这个大的随机数的分布实际就是几个小随机数的联合分布,也是均匀的。于是我们把新问题化归为一个已知的问题。浮点数的问题看起来稍显复杂。注意到机器浮点数的乘法放缩是准确的(误差最小),因此 [a, b) 区间的浮点随机数 x 是可以通过 [0, 1) 区间的浮点随机数 u 做线性变换得到,即 x = a + u * (b - a)。因此只要能生成 [0, 1) 区间的浮点随机数 u 就可以了。如果再知道 IEEE 754 标准中浮点数的定义,就知道一个浮点数由符号位、指数、尾数构成。如果符号位和指数均为 0,尾数部分就恰好是 [0, 1) 区间的数。因此一个 [0, 1) 区间的浮点数就是一个尾数位数的整数。例如对于双精度浮点数,尾数是 52bit,因此可以生成一个
区间的随机整数作为浮点数的尾数,就得到 [0, 1) 区间的随机浮点数。我们就又把问题化归为已知的问题了。做为餐后甜点,我们来看看另一个求 [a, b] 区间整数的办法:先生成一个 [0, 1) 区间的浮点数,然后用它来生成 [a, b+1) 区间的整数,最后用一个 floor 向负无穷大取整。在数学上,这个办法无懈可击(注意对于概率,开区间和闭区间并不影响)。Knuth 在 TAOCP 中就是这样描述随机区间生成方式的。但在现实中这样则不够准确,因为我们知道,所谓 [0, 1) 区间的双精度浮点数,其实只是一个 52 比特的整数而已,用它计算区间长度小于
的随机整数时,因为不能等分区间,就会造成不准确;而用它计算区间长度大于的随机整数时,还会因为区间不够大,会有一些数永远取不到。求固定区间浮点随机数时,我们追求的只是误差最小;而求随机整数时,我们就有理由追求完全准确了。另一个求 [a, b] 区间随机整数的常见用法是写x = a + (double)rand() / (RAND_MAX + 1) *这个办法其实就是前面说的先求 [0, 1) 区间浮点随机数,再线性映射到整数区间的办法,只是 RAND_MAX 通常没有
52bit 之多,因此精确度还不如前面的方法高。——更准确地说,这个方法的精确程度其实和直接取模差不多是一样的,只是概率较大和较小的数变得分散了一些而已。=====================================================================因为随机数生成器的使用对于大多数缺少相关专业知识的人来说是比较难的,在 C++ 11 标准中,又增加了 &random& 头文件,专门用来生成各种分布随机数,也可以更换其中的随机数发生器源。如果你使用支持 C++11 标准库的新版本的 VC、GCC、Clang 等编译器,就可以参考
来使用相应的函数。一方面,你可以不必考虑固定整数范围的基本的随机数源怎么用,直接使用 uniform_int_distribution 和 uniform_real_distribution 类来生成指定范围的随机整数或浮点数。另一方面,你也可以在使用 uniform_int_distribution 之类伪随机数类生成随机数时,选择内部状态空间更大、周期更长的发生器,如 mt19937(有 19937bit 状态空间)之类。甚至是基于硬件的真随机数发生器 random_device。
一句话总结:对于非 crypto 级别的随机数,用 uniform_int_distribution + mt19937 。
标准库已经越来越完美了。建议不要再用C Librarystd::random_device rd;
std::uniform_int_distribution&int& dist(0, 9999999);
std::cout&&dist(rd)&&std::endl;
如果再稍微加一些性能方面的考虑,不去在栈生成random_device.可以考虑封装成singleton.//random number generator RNG.hpp
//author : AntiMoron
#ifndef __RNG_HPP__
#define __RNG_HPP__
#include &memory&
#include &random&
class RNG {
const static std::size_t maxRand = std::random_device::max();
static RNG& getInstance() {
static RNG instance;
return instance;
std::size_t getInteger() noexcept{
return (*dist)(rd);
RNG() noexcept{
regen = std::make_shared&std::mt19937&(rd());
dist = std::make_shared(std::uniform_int_distribution&std::size_t& (0,maxRand));
std::random_device rd;
std::shared_ptr&std::mt19937& regen;
std::shared_ptr&std::uniform_int_distribution&std::size_t& & dist;
#define RAND_INT(x)
(RNG::getInstance().getInteger() % x)
徒手撸代码不知有错否。目测没问题。
别用那个不就行了。Boost里面有MT法,可以直接生成64位整形。
其实你想自己写线性同余法也没问题。。。
如果要求不那么苛刻的话,使用下面这个函数就行int random(int max_range = 1)
if (max_range == 1) return rand() && 16 | rand();
return (rand() && 16 | rand()) % max_range;
可参考numerical recipes一书。有一章专门讲这个。
已有帐号?
无法登录?
社交帐号登录C++如何生成随机数 - 博客频道 - CSDN.NET
fenxinzi557的博客
分类:C++成长之路
随机数的生成
1.最简单的随机数生成
只要产生随机数而不需要设定范围的话,只要用rand()就可以了,
rand()会返回一随机数值, 范围在0至RAND_MAX 间。
RAND_MAX定义在stdlib.h, 其值为。
代码如下:
# include &iostream&
using namespace std;
int main()
for(int i=0;i&10;i++)
cout&&rand()&&
运行结果生成10个随机数:
2.获取一定范围内的随机数的话,对上面生成随机数作取余操作即可;
代码如下:
# include &iostream&
using namespace std;
int main()
for(int i=0;i&10;i++)
cout&&rand()%10&&
运行结果:
3.获取随机生成的小数,在上面操作的基础上,作除法操作即可;
代码如下:
# include &iostream&
using namespace std;
int main()
for(int i=0;i&10;i++)
cout&&(rand()%NUMMOD)/NUMDEV&&
运行结果: NUMMOD 决定生成随机数的值的范围
NUMDEV 决定取余后生成的小数的范围
4.每次运行rand()函数,生成的随机数是不变的,如果用srand()函数就可以为rand()函数生成随机数种子,每次运行rand()函数的结果就会大不相同。
# include &iostream&
# include&ctime&
using namespace std;
int main()
srand(time(0));
for(int i=0;i&10;i++)
cout&&(rand()%NUMMOD)&&
system("pause");
这样,每次运行就会产生不同的随机数。
fenxinzi557
排名:千里之外
(17)(1)(27)(0)(0)(9)(10)(1)(0)(1)(1)2016年2月 C/C++大版内专家分月排行榜第三2016年1月 C/C++大版内专家分月排行榜第三
本帖子已过去太久远了,不再提供回复功能。C++生成随机数―生成任意范围内的等概率随机数方法
假如你想用C++来生成0――N-1之间的随机数,你会怎么做?你可能会说,很简单,看:
srand( (unsigned)time( NULL ) );rand() % N;
仔细想一下,这个结果是随机的吗(当然,我们不考虑rand()函数的伪随机性)?
不是的,因为rand()的上限是RAND_MAX,而一般情况下,RAND_MAX并不是N的整数倍,那么如果RAND_MAX % = r,则0――r之间的数值的概率就要大一些,而r+1――N-1之间的数值的概率就要小一些。还有,如果N & RAND_MAX,那该怎么办?
下面给出一种比较合适的方案,可以生成任意范围内的等概率随机数 result。最后还有一个更简单的方法。
&&&&&&&& R = RAND_MAX-(RAND_MAX+1)%N; //去除尾数&&&&&&&& t = rand();&&&&&&&& while( t & R ) t = rand();&&&&&&&& result = t % N; // 符合要求的随机数
2、如果 N&RAND_MAX,可以考虑分段抽样,分成[n/(RNAD_MAX+1)]段,先等概率得到段再得到每段内的某个元素,这样分段也类似地有一个尾数问题,不是每次都刚好分到整数段,一定或多或少有一个余数段,这部分的值如何选取?
选到余数段的数据拿出来选取,先进行一次选到余数段概率的事件发生,然后进行单独选取:
&&&&&&&& r = N % (RAND_MAX+1); //余数&&&&&&&& if ( happened( (double)r/N ) )//选到余数段的概率&&&&&&&&&&&& result = N-r+myrandom(r); // myrandom可以用情况1中的代码实现&&&&&&&& else&&&&&&&&&&&& result = rand()+myrandom(N/(RAND_MAX+1))*(RAND_MAX+1); // 如果选不到余数段再进行分段选取&&&&&&& 完整的代码:#include#include#includeconst double MinProb=1.0/(RAND_MAX+1);bool happened(double probability)//probability 0~1{&&& if(probability&=0)&&& {&&& }&&& if(probability&&& {&&&&&&& return rand()==0&&happened(probability*(RAND_MAX+1));&&& }&&& if(rand()&=probability*(RAND_MAX+1))&&& {&&&&&&&&&& }&&&}
long myrandom(long n)//产生0~n-1之间的等概率随机数{&&& t=0;&&& if(n&=RAND_MAX)&&& {&&&&&&& long R=RAND_MAX-(RAND_MAX+1)%n;//尾数&&&&&&& t = rand();&&&&&&& while ( t & r )&&&&&& {&&&&&&&&&&& t = rand();&&&&&& }&&&&&&& return t %&&& }&&& else&&& {&&&&&&& long r = n%(RAND_MAX+1);//余数&&&&&&& if( happened( (double)r/n ) )//取到余数的概率&&&&&& {&&&&&&&&&&& return n-r+myrandom(r);&&&&&& }&&&&&&& else&&&&&& {&&&&&&&&&&& return rand()+myrandom(n/(RAND_MAX+1))*(RAND_MAX+1);&&&&&& }&&& }}
&还有另外一种非常简单的方式,那就是使用
random_shuffle( RandomAccessIterator _First, RandomAccessIterator _Last ).
例如,生成0――N-1之间的随机数,可以这么写
#include #include
long myrandom( long N ){&&&&& std::vector vl( N ); // 定义一个大小为N的vector&&&&&& for ( long i=0; i&&&&&& {&&&&&&&&&&&&&& vl[i] =&&&&&& }
&&&&&& std::random_shuffle( vl.begin(), vl.end() );
&&&&&& return (*vl.begin());}
random_shuffle 还有一个三参数的重载版本
random_shuffle( RandomAccessIterator _First, RandomAccessIterator _Last, RandomNumberGenerator& _Rand )
第三个参数可以接受一个自定义的随机数生成器来把前两个参数之间的元素随机化。
这个方法的缺陷就是,如果只是需要一个随机数的话,当N很大时,空间消耗很大!
阅读本文后您有什么感想? 已有
人给出评价!
04-10-1504-10-1504-10-0804-10-0804-10-0804-10-0804-10-0704-10-07
注:您的评论需要经过审核才会显示出来
没有查询到任何记录。
Copyright &
PC6下载().All Rights Reserved
备案编号:湘ICP备号}

我要回帖

更多关于 伪随机数列 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信