免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
论坛 操作系统 BSD rand(3)
最近访问板块 发新帖
查看: 3539 | 回复: 6
打印 上一主题 下一主题

[NetBSD] rand(3) [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2006-08-12 10:03 |只看该作者 |倒序浏览
昨天写了个小程序,用rand(3)模拟随机过程,结果概率不对。
后来换random(3),结果才正确。

今天一看man 3 rand,
These interfaces are obsoleted by random(3).


系统是BSD的同学可以试一下下面的程序(我看了FreeBSd的rand.c,和NetBSD的算法一样),用rand和random分别看一下结果:

  1. #include <stdio.h>
  2. #include <time.h>

  3. #define SEAT_COUNT 100

  4. int seats[SEAT_COUNT];

  5. void clear_seats() {
  6.         int i;
  7.         for(i = 0; i < SEAT_COUNT; i++) seats[i] = -1;
  8. }

  9. int get_rand_seat() {
  10.         int i;
  11.         int ss[SEAT_COUNT];
  12.         int count = 0;
  13.         for(i = 0; i < SEAT_COUNT; i++) {
  14.                 if(seats[i] == -1) ss[count++] = i;
  15.         }
  16.         return ss[rand() % count];
  17. }

  18. int main() {
  19.         int i;
  20.         int j;
  21.         int right = 0, wrong = 0;

  22.         srand(time(NULL));

  23.         for(j = 0; j < 100000; j++) {
  24.                 clear_seats();
  25.                 seats[rand() % SEAT_COUNT] = 0; //被第一位抢占
  26.                 for(i = 1; i < SEAT_COUNT; i++) {
  27.                         if(seats[i] == -1) { //为空
  28.                                 seats[i] = i;
  29.                         }
  30.                         else { //被抢
  31.                                 seats[get_rand_seat()] = i;
  32.                         }
  33.                 }
  34.                 if(seats[SEAT_COUNT - 1] == SEAT_COUNT - 1) right++;
  35.                 else wrong++;
  36.         }
  37.         printf("正确的次数: %d\n", right);
  38.         printf("错误的次数: %d\n", wrong);
  39.         printf("概率: %f\n", (float) right / 100000.0);
  40.         return 0;
  41. }
复制代码

论坛徽章:
2
亥猪
日期:2014-03-19 16:36:35午马
日期:2014-11-23 23:48:46
2 [报告]
发表于 2006-08-12 10:17 |只看该作者
光换rand -> random就可以吗?
还没仔细看代码,不过和你的感觉相反,换成random之后,概率就固定为某个值了。

论坛徽章:
0
3 [报告]
发表于 2006-08-12 10:21 |只看该作者
原帖由 gvim 于 2006-8-12 10:17 发表
光换rand -> random就可以吗?
还没仔细看代码,不过和你的感觉相反,换成random之后,概率就固定为某个值了。

当然对应的srand(3)要换成srandom(3),呵呵。

论坛徽章:
0
4 [报告]
发表于 2006-08-12 10:23 |只看该作者

  1. /*
  2. /usr/src/lib/libc/stdlib/rand.c
  3. */

  4. #include <sys/types.h>
  5. #include <stdlib.h>

  6. static u_long next = 1;

  7. int
  8. rand()
  9. {
  10.         /* LINTED integer overflow */
  11.         return (int)((next = next * 1103515245 + 12345) % ((u_long)RAND_MAX + 1));
  12. /*
  13. 错误似乎出在这里,如果不+1,结果就正确。
  14. 另外很奇怪为什么要用%,这造成rand速度极慢。
  15. */
  16. }

  17. void
  18. srand(seed)
  19.         u_int seed;
  20. {
  21.         next = seed;
  22. }
复制代码

论坛徽章:
2
亥猪
日期:2014-03-19 16:36:35午马
日期:2014-11-23 23:48:46
5 [报告]
发表于 2006-08-12 10:23 |只看该作者
原帖由 assiss 于 2006-8-12 10:21 发表

当然对应的srand(3)要换成srandom(3),呵呵。



再看看

论坛徽章:
2
亥猪
日期:2014-03-19 16:36:35午马
日期:2014-11-23 23:48:46
6 [报告]
发表于 2006-08-12 10:40 |只看该作者
sys/lib/libkern/arch/i386/random.S

/* Here is a very good random number generator.  This implementation is
* based on ``Two Fast Implementations of the "Minimal Standard" Random
* Number Generator'', David G. Carta, Communications of the ACM, Jan 1990,
* Vol 33 No 1.  Do NOT modify this code unless you have a very thorough
* understanding of the algorithm.  It's trickier than you think.  If
* you do change it, make sure that its 10,000'th invocation returns
* 1043618065.
*
* Here is easier-to-decipher pseudocode:
*
* p = (16807*seed)<30:0>       # e.g., the low 31 bits of the product
* q = (16807*seed)<62:31>      # e.g., the high 31 bits starting at bit 32
* if (p + q < 2^31)
*      seed = p + q
* else
*      seed = ((p + q) & (2^31 - 1)) + 1
* return (seed);
*
* The result is in (0,2^31), e.g., it's always positive.
*/
#include <machine/asm.h>

        .data
randseed:
        .long   1
        .text
ENTRY(random)
        movl    $16807,%eax
        imull   randseed
        shld    $1,%eax,%edx
        andl    $0x7fffffff,%eax
        addl    %edx,%eax
        js      1f
        movl    %eax,randseed
        ret
1:
        subl    $0x7fffffff,%eax
        movl    %eax,randseed
        ret

数学不够,看不懂......
>>>It's trickier than you think

论坛徽章:
0
7 [报告]
发表于 2006-08-12 10:47 |只看该作者
原帖由 gvim 于 2006-8-12 10:40 发表
sys/lib/libkern/arch/i386/random.S

数学不够,看不懂......
>>>It's trickier than you think

我昨天为这个问题,写了大约10个程序,分别用数组、链表、Hash等数据结构,用C/C++/PYTHON等语言,用LIBC/GLIB等库,

结果表明:
PYTHON的几个程序都正确。
用GLIB中的rand函数的程序都正确。
用libc中的rand函数的程序结果都错。

这也可能是NetBSD手册里建议使用random(3)代替rand(3)的原因吧。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP