Step to UEFI (31) ----- CLIB:Rand 随机数生成

很多时候我们期望使用随机数来测试我们的结果,在C99中有给出2个随机函数

int rand(void);

void srand(unsigned int seed);

CLIB中,在 \StdLib\Include\stdlib.h 有如下定义

/* ################  Pseudo-random sequence generation functions  ######### */

/** The rand function computes a sequence of pseudo-random integers in the
    range 0 to RAND_MAX.

    @return   The rand function returns a pseudo-random integer.
**/
int     rand(void);

/** The srand function uses the argument as a seed for a new sequence of
    pseudo-random numbers to be returned by subsequent calls to rand.

    If srand is then called with the same seed value, the sequence of
    pseudo-random numbers shall be repeated. If rand is called before any calls
    to srand have been made, the same sequence shall be generated as when srand
    is first called with a seed value of 1.
**/
void    srand(unsigned seed);

 

前者rand 是“伪随机”数,因为生成随机数的种子是固定的,所以每次生成的序列都是相同的。比如,我们用下面的程序段测试:

  printf("1st time generated by rand()\n");
  for (i=0;i<5;i++)   
  {
	printf("%d ",rand());
  }
  printf("\n");

  printf("2nd time generated by rand()\n");
  for (i=0;i<5;i++)   
  {
	printf("%d ",rand());
  }
  printf("\n");

 

得到的结果如下,可以看出来:生成的数值之间是随机的,但是每次运行生成的序列是一样的。这也就是“伪随机”的由来。

rand

此外,在程序的开始处,运行 srand 指定一个种子,就可以让 rand生成“随机数”。运行 srand的结果如下:

srand

进一步分析随机函数,可以在 \StdLib\LibC\StdLib\Rand.c 看到

static UINT32 next = 1;

/** Compute a pseudo-random number.
  *
  * Compute x = (7^5 * x) mod (2^31 - 1)
  * without overflowing 31 bits:
  *      (2^31 - 1) = 127773 * (7^5) + 2836
  * From "Random number generators: good ones are hard to find",
  * Park and Miller, Communications of the ACM, vol. 31, no. 10,
  * October 1988, p. 1195.
**/
int
rand()
{
  INT32 hi, lo, x;

  /* Can't be initialized with 0, so use another value. */
  if (next == 0)
    next = 123459876;
  hi = next / 127773;
  lo = next % 127773;
  x = 16807 * lo - 2836 * hi;
  if (x < 0)
    x += 0x7fffffff;
  return ((next = x) % ((UINT32)RAND_MAX + 1));
}

void
srand(unsigned int seed)
{
  next = (UINT32)seed;
}

 

就是说当我们使用 rand 函数的时候,种子 static UINT32 next = 1; 默认为 1.而当我们首先给定一个种子的时候,next会被替换为我们指定的值。从而达到随机的目的。(话说感觉这样做出来的随机似乎也不是很可靠。如果我们有足够多的序列,完全也能推测出随机种子,也能预测出下面将要出现的数值)

一般随机种子都是直接取当前的时间,于是写一个是程序验证:

#include  <Uefi.h>
#include  <Library/UefiLib.h>
#include  <Library/ShellCEntryLib.h>

#include  <stdio.h>
#include  <stdlib.h>
#include  <wchar.h>
#include  <time.h>
#include <Protocol/EfiShell.h>
#include <Library/ShellLib.h>

extern EFI_BOOT_SERVICES        *gBS;
extern EFI_SYSTEM_TABLE		*gST;
extern EFI_RUNTIME_SERVICES 	*gRT;

int
EFIAPI
main (
  IN int Argc,
  IN char **Argv
  )
{
  INTN i;
  time_t t;

  printf("1st time generated by rand()\n");
  for (i=0;i<5;i++)   
  {
	printf("%d ",rand());
  }
  printf("\n");

  printf("2nd time generated by rand()\n");
  for (i=0;i<5;i++)   
  {
	printf("%d ",rand());
  }
  printf("\n");

  printf("Generated by srand()\n");
  time(&t);
  srand(t);
  for (i=0;i<5;i++)   
  {
	printf("%d ",rand());
  }
  printf("\n");
  
  return EFI_SUCCESS;
}

 

这个程序工作正常,不过有一个“奇怪”的现象:当你连续运行这个程序的时候,2nd time generated by rand() 生成的序列有时候会相同,您说这是为什么呢?

randfail

完整程序代码下载
rand

参考:

1.http://blog.csdn.net/zhenyongyuan123/article/details/5810253 C99标准库函数

发表评论

电子邮件地址不会被公开。 必填项已用*标注