c rand()函数和ISAAC随机数生成器

时间:2016-01-02 23:14:12

标签: c random

我在C中编写了一个程序,它使用了许多不同的随机数生成器,其中一个是ISAAC(可在http://burtleburtle.net/bob/rand/isaacafa.html获得)。它运行良好,但问题是在rand.h中rand()被重新定义为宏。在我的程序中,我也想使用标准的C rand()函数。我尝试将宏的名称更改为rand12()但我在ISAAC中看不到调用宏的任何其他位置,因此这不起作用。

你能提供一些关于如何保持标准rand()函数并使用ISAAC的想法吗?

1 个答案:

答案 0 :(得分:2)

鉴于标题rand.h包含:

#ifndef STANDARD
#include "standard.h"
#endif

#ifndef RAND
#define RAND
#define RANDSIZL   (8)
#define RANDSIZ    (1<<RANDSIZL)

/* context of random number generator */
struct randctx
{
  ub4 randcnt;
  ub4 randrsl[RANDSIZ];
  ub4 randmem[RANDSIZ];
  ub4 randa;
  ub4 randb;
  ub4 randc;
};
typedef  struct randctx  randctx;

/* If (flag==TRUE), then use the contents of randrsl[0..RANDSIZ-1] as the seed. */
void randinit(/*_ randctx *r, word flag _*/);

void isaac(/*_ randctx *r _*/);

/* Call rand(/o_ randctx *r _o/) to retrieve a single 32-bit random value */
#define rand(r) \
   (!(r)->randcnt-- ? \
     (isaac(r), (r)->randcnt=RANDSIZ-1, (r)->randrsl[(r)->randcnt]) : \
     (r)->randrsl[(r)->randcnt])

#endif  /* RAND */

您需要对代码进行一些工作才能在rand() <stdlib.h>旁边使用它。 ISAAC rand()的界面与rand()的{​​{1}}界面不同。

创建一个新的标题<stdlib.h>,它定义了覆盖函数以处理ISAAC系统的特性。

也许,如果你不打算在线程化的上下文中工作

"isaac.h"

然后,您在#ifndef ISAAC_H_INCLUDED #define ISAAC_H_INCLUDED extern void isaac_init(unsigned long seed); extern int isaac_rand(void); #endif 中实现这些功能,以便它们调用isaac.c中定义的函数,rand.h包含isaac_rand()宏的调用rand() 1}}(从某处提供上下文,这是非线程部分的来源)。您可以决定如何处理rand.h,或者是否更改播种机制。

然后,您可以在代码中使用seedisaac_init()函数,以及普通isaac_rand()rand()

我还要升级srand()中的代码,以便为包中的函数提供完整的原型。评论的原型是从90年代中期开始编写时的遗产,当时标准C编译器不是普遍可访问的。标题中最早的日期是1996年;当标准C编译器几乎普遍可用时,这正处于尖端。

我注意到标题中的注释(上面删除)表示代码在公共域中;这意味着您可以100%合法地进行所需的任何修改。

rand.h

isaac.c

此实现忽略了您提供的种子,主要是因为该结构需要8个32位数来为上下文结构的#include "isaac.h" #include "rand.h" static randctx control; void isaac_init(unsigned long seed) { assert(seed != 0); randinit(&control, FALSE); } int isaac_rand(void) { return rand(&control); } 成员(我称之为randrsl)成员。您可以执行类似连续8次使用种子值而不是完全忽略它,或者每次添加一些数字,或者其他更复杂的种子技术。您应该认真考虑使用control作为种子来源:

/dev/urandom

在调用#define DEV_URANDOM "/dev/urandom" int ur = open(DEV_URANDOM, O_RDONLY); if (ur >= 0) { read(ur, control.randrsl, sizeof(control.randrsl)); close(ur); } 之前,您已将此代码放入isaac_init(),并且您将randinit()更改为FALSE。您可能还会失去TRUE函数的seed参数。

这使您无法跟踪随机种子以获得可重复性(在调试时这很重要)。这是你要解决的问题 - 有多种方法可以解决这个问题。您可能有两个初始化函数:isaac_init()void isaac_init(void),其中包含8个void isaac_rsl(unsigned int *rsl)(或unsigned int)值的数组,并将其用作种子而不是{的输出{1}}。或者你可以传递一个空指针来表示“使用来自ub4的输出”和一个非空指针来表示“使用我提供的值”。等