高效随机数生成

 //CreateData.cpp

// Taest.cpp : 湪义控制台訉用程序灸入口俱ィ
//

#include "stdafx.h"


#include "stdafx.h "
#include "memory.h "
#include "stdlib.h "
#include "windows.h "
#include<stdio.h>
#include<iostream>
#include<fstream>
#include <stdlib.h>
#include <Windows.h>
#include <Mmsystem.h>

typedef  unsigned  char  BYTE;
typedef  unsigned  long  DWORD;


void CreateRandDataAndWrite(char *fileNameBuff, DWORD seed)
{
 DWORD   i,c;
 DWORD   idx;
 BYTE    *pMask;
 BYTE    maskArr[]={1,2,4,8,16,32,64,128};

 FILE *fp;
 fp=fopen(fileNameBuff,"wb");
 if(!fp)
 {
  printf("FILE OPEN ERROR!");
  exit(1);
 }

 c=(seed+7)/8;
 pMask=new BYTE[c];

 memset(pMask,0,sizeof(BYTE)*c);

 for( i=1; i<seed; )
 {
  idx=(rand()<<15)+rand();
  idx%=seed;
  if((pMask[idx/8]&maskArr[idx%8])==0)
  {
   pMask[idx/8]|= maskArr[idx%8];
   fprintf(fp,"%ld ",idx);
   i++;
  }
 }

 delete[]   pMask;
 
}

 

int _tmain(int argc, _TCHAR* argv[])
{

 DWORD   t=GetTickCount();
 
 
 char *buffName =new char[15];
 for(int i=0;i<20;i++)
 {
  memset(buffName,0,sizeof(buffName));
  strcpy(buffName,"testA.dat");
  char p = i+65;
  buffName[4] = p;
  CreateRandDataAndWrite(buffName,4294967295);
 }
 

 t=GetTickCount()-t;

 printf( "It take %ld ms\n ",t);

 return   0;
}

 

思想:

2011移动开发者大会亮点之二:七大论坛神秘嘉宾闪亮登场!                “IT适合你吗?”智力挑战

C/C++中产生随机数(rand,srand用法)

分类: C/C++ 2011-07-02 20:12 78人阅读 评论(0) 收藏 举报

计算机的随机数都是由伪随机数,即是由小M多项式序列生成的,其中产生每个小序列都有一个初始值,即随机种子。(注意: 小M多项式序列的周期是65535,即每次利用一个随机种子生成的随机数的周期是65535,当你取得65535个随机数后它们又重复出现了。) 

 

我们知道rand()函数可以用来产生随机数,但是这不是真正意义上的随机数,是一个伪随机数,是根据一个数(我们可以称它为种子)为基准以某 个递推公式推算出来的一系列数,当这系列数很大的时候,就符合正态公布,从而相当于产生了随机数,但这不是真正的随机数,当计算机正常开机后,这个种子的 值是定了的,除非你破坏了系统。

 

1.rand()

功能:随机数发生器

 

用法:int rand(void)

 

所在头文件: stdlib.h

 

rand()的内部实现是用线性同余法做的,它不是真的随机数,因其周期特别长,故在一定的范围里可看成是随机的。

 

rand()返回一随机数值的范围在0至RAND_MAX 间。RAND_MAX的范围最少是在32767之间(int)。用unsigned int 双字节是65535,四字节是4294967295的整数范围。0~RAND_MAX每个数字被选中的机率是相同的。rand()最小产生0,最大产生RAND_MAX,即闭区间【 0,RAND_MAX】 。

 

用户未设定随机数种子时,系统默认的随机数种子为1。

 

rand()产生的是伪随机数字,每次执行时是相同的;若要不同,用函数srand()初始化它。

 

2.srand()

功能:初始化随机数发生器

 

用法: void srand(unsigned int seed)

 

所在头文件: stdlib.h

 

srand()用来设置rand()产生随机数时的随机数种子。参数seed必须是个整数,如果每次seed都设相同值,rand()所产生的随机数值每次就会一样。

 

3.使用当前时钟作为随机数种子

rand()产生的随机数在每次运行的时候都是与上一次相同的。若要不同,用函数srand()初始化它。可以利用srand((unsigned int)(time(NULL))的方法,产生不同的随机数种子,因为每一次运行程序的时间是不同的。

 

4.产生随机数的用法
1) 给srand()提供一个种子,它是一个unsigned int类型;
2) 调用rand(),它会根据提供给srand()的种子值返回一个随机数(在0到RAND_MAX之间);
3) 根据需要多次调用rand(),从而不间断地得到新的随机数;
4) 无论什么时候,都可以给srand()提供一个新的种子,从而进一步“随机化”rand()的输出结果。

 

0~RAND_MAX之间的随机数程序

#include <iostream> 
#include <stdlib.h> 
#include <time.h> 

using namespace std; 

int main() 

        srand((unsigned)time(NULL)); 
        for (int i = 0; i < 10;i++ ) 
                cout << rand() << '/t'; 
        cout << endl; 
        return 0; 
}

 

5.产生一定范围随机数的通用表示公式
要取得[a,b) 的随机整数,使用(rand() % (b-a))+ a;
要取得[a,b] 的随机整数,使用(rand() % (b-a+1 ))+ a;
要取得( a,b] 的随机整数,使用(rand() % (b-a))+ a + 1;
通用公式:a + rand() % n;取得[a,a+n) 的随机整数,其中的a是起始值,n是整数的范围。

要取得[a,b) 的随机整数,另一种表示:a + (int)b * rand() / (RAND_MAX + 1)。
要取得[a,b] 的随机整数 另一种表示:a + (int)b * rand() / (RAND_MAX )。

要取得[0,1] 之间的浮点数 ,可以使用rand() / double(RAND_MAX)。

 

以上内容整理自互联网资料。

本文出自 “子 孑 ” 博客,请务必保留此出处http://zhangjunhd.blog.51cto.com/113473/197020

 

分享到:

·  上一篇:什么是I帧,P帧,B帧

·  下一篇:NS2学习笔记

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

移动开发者大会亮点之二:七大论坛神秘嘉宾闪亮登场!                “IT适合你吗?”智力挑战

快速生产一定数量的不重复的随机数

2010-11-05 23:29 60人阅读 评论(0) 收藏 举报

    在程序中,尤其在游戏程序中我们都会经常性使用到随机数。有时我们只需要生产1个在一定范围内的随机数。如a=int(rnd*100)  生成一个0~99之间的随机数。而有时我们会需要产生一批随机数,比如我们做有关扑克牌的游戏时,就需要将54张牌打乱然后分发出去。这就需要生产54个不重复的随机数。而这时我们就会遇到怎样防止重复的问题,如果用判断程序的话,越到后面就要做越多的判断,而且经常会需要生成很多次才会生成一个不重复的数。当然,如果是54个数的话,即使多花时间了,我们也感觉不出来,但如果是10000个,甚至更多呢?下面介绍一个比较高效的方法。

   主要思想是引入一个辅助数组。比如我们要将0~99这100个数随机的存入res(0)~res(99)这个数组里,那我们就先定义个辅助数组temp(0)~temp(99),并使它依次等于0~99。而我们产生的随机数是指这个数组的下标而不是直接的数字。根据随机产生的下标提取辅助数组中的一个单元,并同时把这个单元用辅助数组的最后一个单元填上。下次取随机数的范围也跟着减少一个。如以下程序:

    Dim res(99) As Integer  '结果存放数组
    Dim temp(99) As Integer  '辅助数组
    Dim lentemp As Integer   '辅助寄存器长度
    Dim i, a As Integer
    For i = 0 To 99         '辅助数组依次存入0~99
        temp(i) = i
    Next i
    lentemp = 100
    Randomize
    For i = 0 To 99
        a = Int(Rnd * lentemp)
        res(i) = temp(a)
        temp(a) = temp(lentemp - 1)
        lentemp = lentemp - 1
    Next i

 

 以上程序是VB6.0的程序,当然方法同样适合于别的语言。。

  

 

 

2011移动开发者大会亮点之二:七大论坛神秘嘉宾闪亮登场!                “IT适合你吗?”智力挑战

用rand()和srand()产生伪随机数的方法总结

2010-05-25 19:57 62人阅读 评论(0) 收藏 举报

标准库<cstdlib>(被包含于<iostream>中)提供两个帮助生成伪随机数的函数:

 

函数一:int rand(void);
从srand (seed)中指定的seed开始,返回一个[seed, RAND_MAX(0x7fff))间的随机整数。

函数二:void srand(unsigned seed);
参数seed是rand()的种子,用来初始化rand()的起始值。

可以认为rand()在每次被调用的时候,它会查看:
1) 如果用户在此之前调用过srand(seed),给seed指定了一个值,那么它会自动调用
srand(seed)一次来初始化它的起始值。
2) 如果用户在此之前没有调用过srand(seed),它会自动调用srand(1)一次。

根据上面的第一点我们可以得出:
1) 如果希望rand()在每次程序运行时产生的值都不一样,必须给srand(seed)中的seed一个变值,这个变值必须在每次程序运行时都不一样(比如到目前为止流逝的时间)。
2) 否则,如果给seed指定的是一个定值,那么每次程序运行时rand()产生的值都会一样,虽然这个值会是[seed, RAND_MAX(0x7fff))之间的一个随机取得的值。
3) 如果在调用rand()之前没有调用过srand(seed),效果将和调用了srand(1)再调用rand()一样(1也是一个定值)。

举几个例子,假设我们要取得0~6之间的随机整数(不含6本身):

例一,不指定seed:
for(int i=0;i<10;i++){
ran_num=rand() % 6;
cout<<ran_num<<" ";
}
每次运行都将输出:5 5 4 4 5 4 0 0 4 2

例二,指定seed为定值1:
srand(1);
for(int i=0;i<10;i++){
ran_num=rand() % 6;
cout<<ran_num<<" ";
}
每次运行都将输出:5 5 4 4 5 4 0 0 4 2
跟例子一的结果完全一样。

例三,指定seed为定值6:
srand(6);
for(int i=0;i<10;i++){
ran_num=rand() % 6;
cout<<ran_num<<" ";
}
每次运行都将输出:4 1 5 1 4 3 4 4 2 2
随机值也是在[0,6)之间,随得的值跟srand(1)不同,但是每次运行的结果都相同。

例四,指定seed为当前系统流逝了的时间(单位为秒):time_t time(0):
#include <ctime>
//…
srand((unsigned)time(0));
for(int i=0;i<10;i++){
ran_num=rand() % 6;
cout<<ran_num<<" ";
}
第一次运行时输出:0 1 5 4 5 0 2 3 4 2
第二次:3 2 3 0 3 5 5 2 2 3
总之,每次运行结果将不一样,因为每次启动程序的时刻都不同(间隔须大于1秒?见下)。

关于time_t time(0):

time_t被定义为长整型,它返回从1970年1月1日零时零分零秒到目前为止所经过的时间,单位为秒。比如假设输出:
cout<<time(0);
值约为1169174701,约等于37(年)乘365(天)乘24(小时)乘3600(秒)(月日没算)。

另外,关于ran_num = rand() % 6,

将rand()的返回值与6求模是必须的,这样才能确保目的随机数落在[0,6)之间,否则rand()的返回值本身可能是很巨大的。
一个通用的公式是:
要取得[a,b)之间的随机整数,使用(rand() % (b-a))+ a (结果值将含a不含b)。
在a为0的情况下,简写为rand() % b。

最后,关于伪随机浮点数:

用rand() / double(RAND_MAX)可以取得0~1之间的浮点数(注意,不同于整型时候的公式,是除以,不是求模),举例:
double ran_numf=0.0;
srand((unsigned)time(0));
for(int i=0;i<10;i++){
ran_numf = rand() / (double)(RAND_MAX);
cout<<ran_numf<<" ";
}
运行结果为:0.716636,0.457725,…等10个0~1之间的浮点数,每次结果都不同。

如果想取更大范围的随机浮点数,比如1~10,可以将
rand() /(double)(RAND_MAX) 改为 rand() /(double)(RAND_MAX/10)
运行结果为:7.19362,6.45775,…等10个1~10之间的浮点数,每次结果都不同。
至于100,1000的情况,如此类推。

以上不是伪随机浮点数最好的实现方法,不过可以将就着用用…

分享到:

·  上一篇:一起进步,一起加油!

·  下一篇:模版函数指针,C++委托的实现

 

 

 

 

 

 

 

 

 

 

 

移动开发者大会亮点之二:七大论坛神秘嘉宾闪亮登场!                “IT适合你吗?”智力挑战

关于rand()和srand()的理解

分类: C/C++ 2010-05-07 14:05 6人阅读 评论(0) 收藏 举报

函数一:int rand(void);
从srand (seed)中指定的seed开始,返回一个[seed, RAND_MAX(0x7fff))间的随机整数。

函数二:void srand(unsigned seed); 
参数seed是rand()的种子,用来初始化rand()的起始值。

 

如果在rand()之前没有调用srand (),它会自动调用srand(1)一次。

可以把随机数列看做是一个长为RAND_MAX的随机数组,而srand(seed)就是取数组的下标,从这个下标开始往后去数组中的数。

因此如果给seed指定的是一个定值,那么每次程序运行时rand()产生的值都会一样,虽然这个值会是[seed, rand_max(0x7fff))之间的一个随机取得的值。 

所以利用时间作为seed,那么每次取到的值随机性很强的。

srand((unsigned)time(0));

 

例如网游的服务器,每次启动的时候都设置种子srand((unsigned)time(0)),然后所有的随机数都无须再设置种子,相当于每次都依次往后取随机数组中的数,只要rand()就可以取到比较满意的随机数了。

分享到:

·  上一篇:关于时间的操作

·  下一篇:c++ 之类的前置声明

 

 

 

 

 

 

 

2011移动开发者大会亮点之二:七大论坛神秘嘉宾闪亮登场!                “IT适合你吗?”智力挑战

生成无重复的随机数

分类: C++ 2008-12-12 21:47 256人阅读 评论(0) 收藏 举报

  摘自:http://www.cppblog.com/pengkuny/archive/2006/11/12/15057.html

生成无重复的随机数,注意,是不重复的序列.
   通常的生成随机数的做法是不考虑重复的,因为即使重复也属于概率意义上的正常情况.但某些情况下需要不重复的随机数据,怎么办呢?
   我想从大方向上来说,应该只有两个方法.要么牺牲时间要么牺牲空间.讲得不对或不完整,大家一定要指出来啊,谢谢.

   注意,下面均以在101~200的范围内(设为b[100],它实际上是附加空间),从中产生10个不重复的随机数(设为a[10]).
  
一.牺牲时间为代价
   这种方法不需要附加空间b数组.
   要产生一定范围内不可重复的随机数,把曾经生成的随机数保存起来作为历史数据。产生一个新的随机数后在历史数据搜索,若找到就重新产生一个新的再重复数据搜索;否则就认为已经找到了一个新的不同随机数。
   可以预见,每个新产生的随机数都要与前面所有的数比较.若重复,舍弃,再产生;否则,产生下一个.平均耗时n的平方量级.
   粗看起来,上面的程序似乎没有什么问题,在执行过程中程序也能够通过。但,仔细分析我们就会发现问题出在一个新产生的随机数是否已经存在的判定上。既然是随机数,那么从数学的角度来说在概率上,每次产生的随机数 r就有可能相同,尽管这种可能性很小,但确是一个逻辑性与正确性的问题。因此,每次产生的新的随机数r都有可能是数组random的前i-1个数中的某一个,也就是说程序在运行过程中由此可能会导致死循环!
    有人可能会争辩说,这种概率很小嘛,几乎为零.的确,但我要问,算法的五大特性是什么,其中两大特性就是:确定性和有穷性.
    所以,怎么解决?牺牲空间.(稍后介绍)

二.牺牲空间为代价
   以下方法需要附加空间b数组.
   (1)将范围数组b[100](b[i]=100+i,不妨设数组下标从1开始)的每个元素设置一个标志位flag.初始均为flag=0;若某元素被选入到a数组中,则flag=1;显然,以后再选到重复元素可以立刻判定是否已选.这不正是以空间换时间吗?
   但是仍然有一个很严重的问题,在小规模输入下,无疑它的表现是不错的.但现在举一个失败的例子.
   在1~65536之间,选择65500个不重复的随机数.看看后面的随机数,比如第65500个数(最后一个),它要在剩下的36个数中选择才会有flag=0(根本不知道这36个数是什么);哼哼,概率36/65536.越到后面,随机数越难产生,空间也换不了时间.
   改进:先在1~65536之间随机选取36个数,删除.将剩下的65500个数依次赋值给a[65500],然后打乱顺序即可,如下伪码:

1 for  i ←  1  to length[a]
2     do  j ← random()  // 随机产生一个a数组的下标
3       exchange a[i]←→a[j] // 交换a[i]与a[j]
4

  当范围数组与目标数组的大小非常接近时,上述算法非常有效,建议采用.

  (2)问题的最终解决.
   仍以最开始的那个例子来说,初始数组b[i]=100+i,a数组空.
   每次随机生成数组b的一个下标subscript,然后取出它所对应的数据a[subscript],记下来.然后将数组b的最后一个数b[length]放到下标subscript的位置,同时将数组a长度减1。尽管前若干次生成的下标subscript随机数有可能相同,但,因为每一次都把最后一个数填到取出的位置,因此,相同下标subscript对应的数却绝不会相同,每一次取出的数都不会一样,这样,就保证了算法的确定性、有效性、有穷性.
  伪码算法如下:

 1 lower ←  101
 2 upper ←  200
 3 for  i ←  1  to upper - lower + 1
 4      do  b[i] = lower + i - 1
 5 for  i← 1  to length[a]
 6      do  subscript  =  ( int )(length[b] * Rnd  +  lower) // 随机产生b数组的一个下标,Rnd产生0~1随机数
 7        temp ← b[subscript]
 8        b[subscript] ← b[length[b]]
 9        length[b] -- ;
10        a[i] = temp;
11

  这个算法我认为是很不错的.
  如果大家有更好的想法解决不重复的随机数,欢迎探讨!

posted on 2006-11-12 12:05 pengkuny 阅读(1250) 评论(11)  编辑 收藏 引用 所属分类: 算法与数据结构


评论:

# re: 生成无重复的随机数 2006-12-05 18:23 | 沐枫

你的方法1)因为需要保存随机数历史数据,因此仍然是需要空间消耗的。而且空间消耗与方法2)比起来,没区别。

--
至于方法2)的交换方法,VS2005中的std::random_shuffle函数就是这么做的。

  回复  更多评论
  

# re: 生成无重复的随机数 2006-12-05 22:27 | pengkuny

@沐枫
方法1)中,历史数据不算附加空间吧
比如从0~10000000000中随机选6个数,
a[6]不算附加空间,b[10000000000]才是

至于VS2005中的std::random_shuffle函数,非常谢谢,原来有这样的函数,那太好了.  回复  更多评论
  

# re: 生成无重复的随机数 2007-01-19 15:13 | null

二(1)处有误,“若某元素被选入到a数组中,则flag=1;显然,以后再选到重复元素可以立刻判定是否已选.这不正是以空间换时间吗?”,在概率下有可能存在一直生成树组b的且flag为1的下标而导致死循环,与一同。
二(2)中有笔误,“同时将数组a长度减1。尽管”该处a应为b。  回复  更多评论
  

# re: 生成无重复的随机数 2007-01-19 16:38 | Dain

我知道c/cpp中可以产生随机种子,在用rand函数,就避免了重复
srand((unsigned)time(NULL));
rand();  回复  更多评论
  

# re: 生成无重复的随机数 2007-01-19 20:20 | pengkuny

@null
null说得不错
二(1)确实没有达到有穷性,只是使得"判定是否重复"的时间为常数
二(2)中笔误已改正.谢谢@Dain
  回复  更多评论
  

# re: 生成无重复的随机数 2007-01-19 20:22 | pengkuny

@Dain
撒种srand可以避免程序每次运行时数据一样(毕竟系统采用伪随机方法)
只不过和本文讨论的不是一回事  回复  更多评论
  

# re: 生成无重复的随机数 2007-05-13 11:32 | Stupidmxx

m序列可能可以做到生成不重复随机序列  回复  更多评论
  

# re: 生成无重复的随机数 2007-05-13 12:02 | pengkuny

@Stupidmxx
请问什么是m序列?它是怎么生成不重复随机序列的  回复  更多评论
  

# re: 生成无重复的随机数 2007-05-24 23:45 | Stupidmxx

小m序列,没记错的话是先找到个本原多项式,然后得到相应的线性移位寄存器,再不断的异或+移位生成的。呵呵,老师讲的时候我就只记得它的性质,具体细节没搞清楚。博主有兴趣不妨baidu之。  回复  更多评论
  

# re: 生成无重复的随机数 2007-05-25 01:50 | pengkuny

@Stupidmxx
查过了,就是线性同余法.模为m.
如Xi = 65539Xi (mod 2^31),65539=2^16+3,左移16位并相加3次.

最终,它还是伪随机,电脑也正是这么实现的.

  回复  更多评论
  

分享到:

·  上一篇:使用random_shuffle()算法随机化序列元素

·  下一篇:用rand()和srand()产生伪随机数的方法总结

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值