• rand * () 之间相互生成总结


    先举一个之前看过的例子:(引自http://gaofen100.iteye.com/blog/1294993

    给一个方法,比如 rand5(), 它能够等概率生成 1-5 之间的整数。 所谓等概率就是1,2,3,4,5 生产的概率均为 0.2 。现在利用rand5(), 构造一个能够等概率生成 1- 7 的方法?


    思路:很多人的第一反应是return rand5()+rand5()%3; 这个实现确实能产生1-7之间的随机数,但是问题在于分布是不均匀的。rand5()%3产生0的概率是1/5,而产生1和2的概率都是2/5。所以这个实现产生6和7的概率要大于产生5的概率。 

      这里有两个特别重要的点,一是 如同上面思路,如果 rand5() + rand5(), 我们能够产生一个均匀分布的1 - 10 吗? 答案是否定的。比如对于 6来讲(4+2, 2+4, 3+3),它被生成的生成的概率比1 (1+0,0+1)要大.

      第二个点就是我们不可能用rand5()直接产生 1- 7 的数,不管你用加减乘除都不行。

    所以,我们要构造一个更大的范围,使得范围里每一个值被生成的概率是一样的,而且这个范围是7的倍数,我们从下面的代码中来分析如何解决上面两个问题:

    1. int rand7() {  
    2.         while (1) {  
    3.                 int rand = 5 * (rand5() -1) ;  
    4.                 rand = rand + rand5() -1;  
    5.                 if (rand < 22 && ran > 0) {  
    6.                              return rand%7 + 1 ;  
    7.                 }  
    8.          }  
    9. }  

    第三行代码产生一个均匀分布的 0, 5, 10, 15, 20的数。

    第四行代码产生一个均匀分布的 0, 1, 2, 3, 4 的数。

    相加以后,会产生一个 0到24的数,而且每个数(除0外)生成的概率是一样的。我们只取 1 - 21 这一段,和7 取余以后+1就能得到完全均匀分布的1-7的随机数了。

    后来看到博客园另外一篇文章介绍的极其详细,果断学习之http://www.cppblog.com/hardtry/archive/2011/10/08/157556.html


    学习之余,顺便探讨下rand()函数本身

    函数rand()是真正的随机数生成器,而srand()会设置供rand()使用的随机数种子。函数rand()会返回一个处于0和你所指定的数值(缺省为1)之间的分数。如果你在第一次调用rand()之前没有调用srand(),那么系统会为你自动调用srand()。而使用同种子相同的数调用 srand()会导致相同的随机数序列被生成。

    srand((unsigned)time(NULL))则使用系统定时/计数器的值做为随机种子,所以,在相同的平台环境下,显示的随机数会是伪随机数,即每次运行显示的结果会有不同

    要注意的是所谓的“伪随机数”指的并不是假的随机数。其实绝对的随机数只是一种理想状态的随机数,计算机只能生成相对的随机数即伪随机数。计算机生 成的伪随机数既是随机的又是有规律的 —— 一部份遵守一定的规律,一部份则不遵守任何规律。比如“世上没有两片形状完全相同的树叶”,这正点到了事物的特性 —— 规律性;但是每种树的叶子都有近似的形状,这正是事物的共性 —— 规律性。从这个角度讲,我们就可以接受这样的事实了:计算机只能产生伪随机数而不是绝对的随机数。

    下面是C库函数里面的rand()代码

     1 【C语言库函数rand()源代码】
     2 【本程序在Dev C 4.9.9.2 下编译通过】
     3 /*
     4    这两个函数是C库中产生随机数的程序。你需要先使用srand()函数赋随机数种子值。然后再使用 rand()函数来产生随机数。但是产生随机数的算法较简单,srandom()和random()函数是对这两个函数的改良,用法也很类似。
     5 */
     6 #define RANDOM_MAX 0x7FFFFFFF
     7  
     8 static long my_do_rand(unsigned long *value)
     9 {
    10    /*
    11       这个算法保证所产生的值不会超过(2^31 - 1)这里(2^31 - 1)就是 0x7FFFFFFF。而 0x7FFFFFFF等于127773 * (7^5) 2836,7^5 = 16807。整个算法是通过:t = (7^5 * t) mod (2^31 - 1)这个公式来计算随机值,并且把这次得到的值得到并且计算,作为下次计算的随机种子值。
    12    */
    13    long quotient, remainder, t;
    14  
    15    quotient = *value / 127773L;
    16    remainder = *value % 127773L;
    17    t = 16807L * remainder - 2836L * quotient;
    18    if (t <= 0)
    19       t = 0x7FFFFFFFL;
    20    return ((*value = t) % ((unsigned long)RANDOM_MAX 1));
    21 }
    22 static unsigned long next = 1;
    23 int my_rand(void)
    24 {
    25    return my_do_rand(&next);
    26 }
    27  
    28 void my_srand(unsigned int seed)
    29 {
    30    next = seed;
    31 }
    32  
    33 #include <time.h>
    34 int main()
    35 {
    36    int i;  
    37    my_srand((unsigned)(time(NULL)));
    38    for(i=0;i<100;i )
    39    {
    40       if(i % 10 == 0)
    41          printf("\n");
    42       printf("%d\t",my_rand()%99 1);
    43    }
    44    system("pause");
    45    return 0;
    46 }
    47  

    rand()和random()的区别:

    int rand(void):返回 0 ------RAND_MAX 之间的一个 int 类型整数,该函数为非线程安全函数。并且生成随机数的性能不是很好,已经不推荐使用

    long int random(void):返回 0 ------- RAND_MAX 之间的一个 long 类型整数,该函数会产生一个非常大的随机值,最大为 16*((2**31)-1)。random 函数使用非线性反馈随机数发生器生成默认大小为31个长整数表所返回的连续伪随机数。

     

    如果你使用 srandom 种植种子, 则你应该使用 random 返回随机数, 如果你使用 srand 种植种子, 则你应该使用rand返回随机数。

    不过srand和rand官方已经不推荐使用。原因是产生随机数的性能不是很好, 另外是随机数的随机性没有random好, 再者就是不是线程安全。

     

  • 相关阅读:
    【转】大型高性能ASP.NET系统架构设计
    【原创】构建高性能ASP.NET站点 第五章—性能调优综述(后篇)
    表关联键上创建索引的重要性
    NorthScale Memcached Server尝试总结
    转:80后的80条幽默有哲理的语录
    利用AOP重构代码
    Sandcastle Help File Builder
    酒店项目OO设计
    泛型委托在项目中的应用
    SQL CTE能帮助我做什么
  • 原文地址:https://www.cnblogs.com/zhaoxiaolei/p/2468218.html
Copyright © 2020-2023  润新知