C++中操作随机数与概率

作者:张维,引用请注明出处


这里整理出两个实用小函数,用来处理随机数与概率问题。

1,int et_rand_between(int iBegin, int iEnd)

获取从iBegin到iEnd当中的一个随机数,含iBegin,iEnd.

比如,从0到100,任意取一个数。


2,bool et_rand_is_hit_rate(int iTotal, int iRate)

此函数适用于计算 有或者没有 的情况

设有10000张奖票,只有30张是有奖的,

你想知道你这次会不会中奖,就是调用et_rand_with_rate(1000, 30)

你调用1000次,可能30次返回true(也就是中奖)


也许这个例子不是很恰当,那换一种说法吧,

假设你在玩游戏,进入一个关卡后,你有可能会遇到某个怪,它出现的概率是60%

现在你已经进入关卡了,我要马上选择让怪出现或者不出现,则调用一次et_rand_with_rate(100,60)

如果结果是true,怪物就出来。



接下来上代码和实例

代码在vc中通过测试


如果运行代码你会发现,在我设置为50%概率的时候,运行结果确实也差不多是50%命中,建议运行多次此代码以查看效果

注意点:

1,C中的随机数是伪随机,某种情况下是可预测的

2,在多线程的时候会有一些问题,如果你要做多线程处理,需要在代码上做一些修改,在性能越高的机器上越明显


#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <time.h>

int et_rand_between(int iBegin, int iEnd)
{
	static bool bSeedInited = false;//标记种子是否已经生成过

	int iResult = 0;
	int iDiff = 0;
	int iTimeSeed = 0;
	int iSec = 0;
	int iSeed = 0;

<span style="white-space:pre">	</span><pre code_snippet_id="627556" snippet_file_name="blog_20150325_1_6748329" name="code" class="cpp">//参数判断,如果begin小于end那返回-1表示错误,所以要小心-1的结果
if (iBegin > iEnd){return -1;}
 
//初始化种子,在这里我们简单的用时间做种子

if (!bSeedInited){iTimeSeed = time((time_t*)NULL);iSec = iTimeSeed % 10;iSeed = (iTimeSeed / 10) * iSec;srand(iSeed);//系统利用这个函数初始化种子srand名字也就是代表Seed initialized in RANDrand();//在初始化后我们预先rand一次,增加混淆度bSeedInited = true;}iDiff = iEnd - iBegin + 1;//这里的+1很重要,如果不加的话,随机结果不会包含最大值iResult = rand() % iDiff + iBegin;return iResult;}


bool et_rand_is_hit_rate(int iTotal, int iRate){

int iRand = 0;bool bResult = false;

iRand = et_rand_between(0, iTotal - 1);

 
//如果概率值大于随机值,那这次中了
	if (iRate > iRand){
		bResult = true;
	}

	return bResult;
}

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

	int iRate = 50;
	int iTotal = 100;
	int iFrom = 1;
	int iTo = 100;
	int i = 0;

	bool bHit = false;
	int iHitCount = 0;
	for (i = iFrom - 1; i < iTo; i++){

		bHit = et_rand_with_rate(iTotal, iRate);
		printf("%d,",bHit);
		if (bHit){
			iHitCount++;
		}
	}

	printf("\n%d\n",iHitCount);

	system("pause");
	return 0;
}


接下来分析一下第一个函数,

里面有三个标准C的API

time(),srand(),rand()

其实我们最终只需要用一个rand,他会计算出从0到1的一个小数,

那为何要srand?

因为rand在计算的时候需要一个种子。

随机数的产生依赖于两个条件,1是规律,2是种子,

同一种算法,规律当然是一样的,如果种子一样,,,那不好意思,结果就是一样的了,还何谈随机?

举个例子,要取0-100之间的随机数,

如果srand的时候,种子是5,

那rand调用的结果序列可能是,3,99,78,23,。。。

这个序列是确定的

一个有足够经验的黑客可以根据这样的序列来分析你每一次随机的结果

建议大家写代码调用rand看它的结果序列


所以,要让自己的随机数无法预测,就必须要给一个不容易预测的种子

在这里,我们没有做特别复杂的算法产生种子,只给一个时间种子

如果你做得更好,还可以根据当前硬件环境,如CPU串号,硬盘串号,等乖,

还可以根据当前业务特定情况来计算

种子只有一个,生成之后,不再生成,

所以,有一个这样的static变量定义

static bool bSeedInited = false;

接下来的事情就简单了

在种子初始化之后,我们每次做的事情只有两行代码

iDiff = iEnd - iBegin + 1;
iResult = rand() % iDiff + iBegin;

那就是rand给一个0到1之间的概率,我们从Begin到End间取一个数而已


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值