首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C rand()函数和ISAAC随机数生成器

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

Stack Overflow用户
提问于 2016-01-03 07:14:12
回答 1查看 501关注 0票数 0

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

您能否提供一些想法,让我既能保留标准的rand()函数,又能使用ISAAC?

EN

回答 1

Stack Overflow用户

发布于 2016-01-03 07:39:45

假设标头rand.h包含:

代码语言:javascript
复制
#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 */

您需要对代码做一些工作,以便能够将其与<stdlib.h>中的rand()一起使用。到ISAAC rand()的接口也不同于从<stdlib.h>rand()的接口。

创建一个新的头文件"isaac.h",它定义了封面函数来处理ISAAC系统的特性。

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

代码语言:javascript
复制
#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.h调用rand()宏(从某个地方提供上下文,这就是非线程部分的用武之地)。您可以决定如何处理seed,或者是否更改种子设定机制。

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

我还会升级rand.h中的代码,以便为包中的函数提供完整的原型。注释原型是在90年代中期第一次编写它时留下的,当时标准C编译器并不是所有人都可以访问的。标题中最早的日期是1996年;这正是标准C编译器几乎普遍可用的时候。

我注意到(上面删除的)头中的注释表明代码是在公共领域中;这意味着它是100%合法的,可以进行任何您需要的修改。

isaac.c

代码语言:javascript
复制
#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);
}

这个实现忽略了您给出的种子,主要是因为这个结构需要8个32位的数字来给context结构(我称之为control)的randrsl成员提供种子。你可以这样做,比如在一行中使用种子值8次,而不是完全忽略它,或者每次都添加一些数字,或者其他任何更复杂的种子技术。您应该认真考虑使用/dev/urandom作为种子的来源:

代码语言:javascript
复制
#define DEV_URANDOM "/dev/urandom"

int ur = open(DEV_URANDOM, O_RDONLY);
if (ur >= 0)
{
    read(ur, control.randrsl, sizeof(control.randrsl));
    close(ur);
}

在调用randinit()之前,将此代码放入isaac_init(),并将FALSE更改为TRUE。您可能还会丢失isaac_init()函数的seed参数。

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

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/34571718

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档