我在C中编写了一个程序,它使用了许多不同的随机数生成器,其中一个是ISAAC(可在http://burtleburtle.net/bob/rand/isaacafa.html获得)。它运行良好,但问题是在rand.h中rand()被重新定义为宏。在我的程序中,我也想使用标准的C rand()函数。我尝试将宏的名称更改为rand12()但我在ISAAC中看不到调用宏的任何其他位置,因此这不起作用。
你能提供一些关于如何保持标准rand()函数并使用ISAAC的想法吗?
答案 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
,或者是否更改播种机制。
然后,您可以在代码中使用seed
和isaac_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
的输出”和一个非空指针来表示“使用我提供的值”。等