/**************************************************************************
Author: Rita
Descrption: 写此程序源于某公司的一个面试题。
已知条件:假设已经得到一个rand5()函数:可以随机产生0 ~ 4 这5个数
问题:要求利用两个rand5(),得到一个rand7(),即可随机产生0 ~ 6 这7个数。
算法思路:
随机函数的一个最重要的特点就是均匀分布,即产生每一个数的概率相等。
显然,rand5()是以等概率生成0 ~ 4 这5个数的。因此,rand7()函数也
必须以等概率生成0 ~ 6 这7个数。
算法1:rand7_ref1()
将第一次rand5()生成的数num1和第二次rand5()生成的数num2组合相加,
可以等概率得到0 ~ 24 这25个数。具体可用如下方式表示:
0 5 10 15 20
0 0 5 10 15 20
1 1 6 11 16 21
2 2 7 12 17 22
3 3 8 13 18 23
4 4 9 14 19 24
为了等概率得到0 ~ 6 这7个数,可以从上面生成的25个数中取出个数为
7的最大倍数(21)个数,即将21,22,23,24这4个数舍弃。然后将0~20
这21个数 %7(取模)即可。
算法2:rand7_ref2()
利用计算机中数字的二进制表示法,可以用三位二进制数来表示0 ~ 6 这7个数。
step1: 先用rand5()生成rand2(),思路与算法1类似。
rand5()生成0 ~ 4 这5个数,从中取出个数为2的最大公倍数(4)个数,舍弃4,
然后将0 ~ 3 这4个数 % 2即可得到rand2()。
step2: 再用rand2()生成rand7()
rand7() = rand2() << 2 + rand2() << 1 + rand2();
Date: 2012.09.29
****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define TEST_TIMES 10000
/*************************************
算法1:
从两次rand5()产生的25个组合数
0 ~ 24 中取出前面的21个模7
*************************************/
int rand7_ref1()
{
int num1 = 0, num2 = 0;
int val = 0;
int result=0;
do
{
num1 = rand()%5;
num2 = rand()%5;
val = 5*num1 + num2;
if ( val < 21)
{
result = val % 7;
}
}while( val >= 21 );
return result;
}
/*************************************
测试算法1是否满足均匀分布
*************************************/
int test_rand7_ref1()
{
int i;
int num = 0;
int count[7];
for ( i = 0; i < 7; i++)
{
count[i] = 0;
}
for ( i = 0 ; i < TEST_TIMES ; i++ )
{
num = rand7_ref1();
count[num]++;
}
printf("判断算法1是否均匀生成 0 ~ 6:\n");
for ( i = 0 ;i < 7; i++ )
{
printf("count[%d]=%.3f\n",i,(float)count[i]/TEST_TIMES);
}
return 1;
}
/**************************************
rand5()生成rand2():等概率得到0和1
***************************************/
int rand5_to_rand2()
{
int num1=0 , num2=0;
do
{
num1 = rand()%5;
if ( num1 < 4 )
{
num2 = num1 % 2;
}
}while( num1 == 4);
return num2;
}
/**************************************
测试是否等概率得到0和1
***************************************/
void test_rand5_to_rand2()
{
int i, result = 0;
int count[2];
for ( i = 0; i < 2; i++)
{
count[i] = 0;
}
for( i = 0 ; i < TEST_TIMES; i++ )
{
result = rand5_to_rand2();
count[result]++;
}
printf("判断是否均匀生成 0 ~ 1:\n");
for ( i = 0; i< 2; i++ )
{
printf("count[%d]=%.3f\n",i,(float)count[i]/TEST_TIMES);
}
}
/**************************************
由三位二进制数生成rand7()
***************************************/
int rand7_ref2()
{
int bit[3],result=0;
bit[0] = rand5_to_rand2();
bit[1] = rand5_to_rand2()<<1;
bit[2] = rand5_to_rand2()<<2;
result = bit[2] + bit[1] + bit[0];
return result;
}
/**************************************
测试是否等概率得到0 ~ 6
***************************************/
void test_rand7_ref2()
{
int i,result;
int count[7];
for ( i = 0; i < 7; i++ )
{
count[i] = 0;
}
for ( i = 0 ; i < TEST_TIMES; i++ )
{
result = rand7_ref2();
count[result]++;
}
printf("判断算法2是否均匀生成 0 ~ 6:\n");
for ( i = 0 ;i < 7; i++ )
{
printf("count[%d]=%.3f\n",i,(float)count[i]/TEST_TIMES);
}
}
int main()
{
srand(time(NULL));
test_rand5_to_rand2();
test_rand7_ref1();
test_rand7_ref2();
return 1;
}
运行结果:
判断是否均匀生成 0 ~ 1:
count[0]=0.496
count[1]=0.504
判断算法1是否均匀生成 0 ~ 6:
count[0]=0.150
count[1]=0.149
count[2]=0.145
count[3]=0.141
count[4]=0.136
count[5]=0.139
count[6]=0.141
判断算法2是否均匀生成 0 ~ 6:
count[0]=0.126
count[1]=0.125
count[2]=0.123
count[3]=0.119
count[4]=0.126
count[5]=0.125
count[6]=0.125