我用C语言写了一个程序,它使用了许多不同的随机数生成器,其中一个是艾萨克(可以在http://burtleburtle.net/bob/rand/isaacafa.html上找到)。它工作得很好,但问题是在rand.h中,rand()被重新定义为宏。在我的程序中,我还想使用标准的C rand()函数。我尝试将宏的名称更改为rand12(),但我在ISAAC中看不到调用该宏的任何其他位置,因此这不起作用。
您能否提供一些想法,让我既能保留标准的rand()函数,又能使用ISAAC?
发布于 2016-01-03 07:39:45
假设标头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 */您需要对代码做一些工作,以便能够将其与<stdlib.h>中的rand()一起使用。到ISAAC rand()的接口也不同于从<stdlib.h>到rand()的接口。
创建一个新的头文件"isaac.h",它定义了封面函数来处理ISAAC系统的特性。
也许,如果您不打算在线程上下文中工作
#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
#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作为种子的来源:
#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的输出”,而传递一个非空指针来表示“使用我提供的值”。等。
https://stackoverflow.com/questions/34571718
复制相似问题