rand和srand的实现机制



rand和srand是用于产生伪随机数的两个函数,根据参考手册rand的返回值是在[0, RAND_MAX]之间的数据,RAND_MAX在不同的系统中数值有所不同。

以下是rand和srand实现方式的一个示例(假定RAND_MAX为32767)

  1. static unsigned long next = 1;  
  2.   
  3. /* RAND_MAX assumed to be 32767 */  
  4. int rand(void) {  
  5.     next = next * 1103515245 + 12345;  
  6.     return((unsigned)(next/65536) % 32768);  
  7. }  
  8.   
  9. void srand(unsigned seed) {  
  10.     next = seed;  
  11. }  
static unsigned long next = 1;

/* RAND_MAX assumed to be 32767 */
int rand(void) {
    next = next * 1103515245 + 12345;
    return((unsigned)(next/65536) % 32768);
}

void srand(unsigned seed) {
    next = seed;
}
事实上现在多数系统上的rand和srand就是使用的这种机制,只是上面取的数字或略有不同。

  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3.   
  4. int main()  
  5. {  
  6.     int i;  
  7.     for (i = 0; i < 10; i++)  
  8.     {  
  9.         printf("%d ", rand());  
  10.     }  
  11.     getchar();  
  12.     return 0;  
  13. }  
#include <stdio.h>
#include <stdlib.h>

int main()
{
    int i;
    for (i = 0; i < 10; i++)
    {
        printf("%d ", rand());
    }
    getchar();
    return 0;
}

在Windows下编译上面这个程序并运行,它产生的随机序列是:

41 18467 6334 26500 19169 15724 11478 29358 26962 24464

但是,当我们再运行一次时,我们会发现产生的序列是相同的。在当我们需要每次运行都产生不同的序列时,上面这样的函数显然是不行的。这是要注意的第一个陷阱。

在Linux下编译上面的程序,两次运行也会得出相同的结果,这与我们程序代码的预期是相同的。如果我们在程序的循环之前添加srand(1),我们会得到相同的序列(与不调用srand效果相同)

根据实现机制给出的代码,如果我们写的程序是如下:

  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3.   
  4. int main()  
  5. {  
  6.     int i;  
  7.     for (i = 0; i < 10; i++)  
  8.     {  
  9.         srand(1);  
  10.         printf("%d ", rand());  
  11.     }  
  12.     getchar();  
  13.     return 0;  
  14. }  
#include <stdio.h>
#include <stdlib.h>

int main()
{
    int i;
    for (i = 0; i < 10; i++)
    {
        srand(1);
        printf("%d ", rand());
    }
    getchar();
    return 0;
}
那它输出的序列将是相同的数,经过实际测试,确实如此:

41 41 41 41 41 41 41 41 41 41


如何写出每次运行结果都不同的随机序列呢?我们来看下例:

  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <time.h>  
  4.   
  5. int main()  
  6. {  
  7.     int i;  
  8.     srand(time(NULL));  
  9.     for (i = 0; i < 10; i++)  
  10.     {  
  11.         printf("%d ", rand());  
  12.     }  
  13.     getchar();  
  14.     return 0;  
  15. }  
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main()
{
    int i;
    srand(time(NULL));
    for (i = 0; i < 10; i++)
    {
        printf("%d ", rand());
    }
    getchar();
    return 0;
}

上面的代码,取了当前时间作为随机数种子,所以每隔一秒钟重新运行程序产生的序列都是不同的,但在同一秒钟会产生相同的序列,这不太理想。而且虽然每一秒的序列有所不同,但每个序列第一个数的数值往往相差不大,这不适用于一些要求比较严格的场合。

所以在这种情况下,最好用能取到毫秒和微秒级系统时间的函数去改写上面程序,并且在取到数时,先取一次模,再将数字拿去做种子会比较可靠一些。

如下面在Linux下的一个实现方法:

  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <time.h>  
  4. #include <sys/time.h>  
  5.   
  6. int main()  
  7. {  
  8.     int i, seed;  
  9.     struct timeval tv;  
  10.     struct timezone tz = {0, 0};  
  11.     gettimeofday(&tv, &tz);  
  12.   
  13.     /* tv.tv_usec 是一个微秒级的时间 */  
  14.     seed = tv.tv_usec % 65536;  
  15.     srand(seed);  
  16.     for (i = 0; i < 10; i++)  
  17.     {  
  18.         printf("%d ", rand());  
  19.     }  
  20.     getchar();  
  21.     return 0;  
  22. }  
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>

int main()
{
    int i, seed;
    struct timeval tv;
    struct timezone tz = {0, 0};
    gettimeofday(&tv, &tz);

    /* tv.tv_usec 是一个微秒级的时间 */
    seed = tv.tv_usec % 65536;
    srand(seed);
    for (i = 0; i < 10; i++)
    {
        printf("%d ", rand());
    }
    getchar();
    return 0;
}
这个版本的运行结果基本可以满足预期,都是不相同的序列,即使在fork多个进程运行时,也可以使每个进程所得到的序列是不相同的。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SMAC(Simple Medium Access Control)是一种简单的媒体访问控制协议,下面是用C++实现SMAC协议的MAC访问机制的代码示例: ```c++ #include <iostream> #include <cstdlib> #include <ctime> using namespace std; // 定义SMAC协议的MAC访问机制 class SMAC { private: int backoffLimit; // 最大重传次数 int backoffCounter; // 当前重传次数 int backoffPeriod; // 退避时间 bool channelBusy; // 信道是否忙碌 public: SMAC() { backoffLimit = 10; // 设置最大重传次数为10 backoffCounter = 0; // 当前重传次数为0 backoffPeriod = 0; // 退避时间为0 channelBusy = false; // 信道开始空闲 } // 访问信道 void accessChannel() { // 如果信道忙碌,进行退避 if (channelBusy) { if (backoffCounter < backoffLimit) { // 生成0到2^backoffCounter-1之间的随机数 int randNum = rand() % (1 << backoffCounter); backoffPeriod = randNum; backoffCounter++; cout << "Channel is busy, backoff period is " << backoffPeriod << endl; // 进行退避 for (int i = 0; i < backoffPeriod; i++) { // 等待1个时间单位 } // 重新访问信道 accessChannel(); } else { cout << "Backoff limit exceeded!" << endl; } } else { // 信道空闲,进行访问 cout << "Channel is idle, start transmission!" << endl; // 发送数据 // ... // 数据发送完毕后,释放信道 channelBusy = false; backoffCounter = 0; backoffPeriod = 0; } } // 设置信道状态 void setChannelStatus(bool busy) { channelBusy = busy; } }; int main() { srand((unsigned)time(NULL)); // 初始化随机数发生器 SMAC smac; // 设置信道状态为忙碌 smac.setChannelStatus(true); // 访问信道 smac.accessChannel(); // 设置信道状态为空闲 smac.setChannelStatus(false); // 访问信道 smac.accessChannel(); return 0; } ``` 上面的代码实现了SMAC协议的MAC访问机制,当信道忙碌时,会进行退避操作,等待一段时间后再次访问信道,直到达到最大重传次数。当信道空闲时,可以进行数据发送,并释放信道。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值