我正在尝试编写一个程序,如果完全执行或者从某个检查点停止并重新启动,则会产生相同的结果。为此,我需要能够在任何场景中重复完全相同的随机数序列。所以,这里是我试图做的一段代码,但当然,我没有成功。你能帮我修一下这段代码吗?
int main(){
int i;
long int seed;
// Initial seed
srand48(3);
// Print 5 random numbers
for(i=0;i<5;i++) printf("%d %f\n",i,drand48());
// CHECKPOINT: HOW TO PROPERLY SET seed?
seed=mrand48(); // <--- FIXME
// 5 numbers more
for(i=5;i<10;i++) printf("%d %f\n",i,drand48());
// Restart from the CHECKPOINT.
srand48(seed);
// Last 5 numbers again
for(i=5;i<10;i++) printf("%d %f\n",i,drand48());
}
答案 0 :(得分:3)
如果您需要能够恢复随机数序列,则不能让drand48()
包隐藏您的种子值,因此您需要使用包中的不同功能。具体来说,你应该打电话:
double erand48(unsigned short xsubi[3]);
而不是:
double drand48(void);
并且您将保留3个unsigned short
值的数组,并且在每个检查点,您将其值记录为状态的一部分。如果你需要恢复停止的地方,你可以将保存状态的值恢复到你的阵列中,然后继续你的快乐方式。
这也是你编写库代码的方式,它既不会干扰使用随机数生成器的其他代码,也不会被使用随机数生成器的其他代码干扰。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
unsigned short seed[3] = { 0, 0, 3 };
// Print 5 random numbers
for (int i = 0; i < 5; i++)
printf("%d %f\n", i, erand48(seed));
// CHECKPOINT
unsigned short saved[3];
memmove(saved, seed, sizeof(seed));
// 5 numbers more
for (int i = 5; i < 10; i++)
printf("%d %f\n", i, erand48(seed));
// Restart from the CHECKPOINT.
memmove(seed, saved, sizeof(seed));
// Last 5 numbers again
for (int i = 5; i < 10; i++)
printf("%d %f\n", i, erand48(seed));
return 0;
}
示例运行:
0 0.700302
1 0.122979
2 0.346792
3 0.290702
4 0.617395
5 0.059760
6 0.783933
7 0.352009
8 0.734377
9 0.124767
5 0.059760
6 0.783933
7 0.352009
8 0.734377
9 0.124767
显然,您最初如何设置种子数组完全取决于您。您可以轻松地允许用户指定种子值,并报告您正在使用的种子,以便他们可以这样做。例如,您可以使用PID或一天中的某些元素以及子秒组件作为默认种子。或者您可以访问随机数设备,例如/dev/urandom
,并从中获取6个字节的随机值,以用作种子。
如何让用户仅使用
long int
指定种子值?在这种方法中,似乎用户需要定义3个数字,但我想在输入文件中只询问1个数字(如安全素数)。
您可以采用单个数字并以您选择的任何方式将其拆分。我有一个程序,它使用选项-s
来打印随机种子,-S
来设置long
的种子,有时会将long
拆分为3 {{1}使用随机高斯分布生成器时的值。我主要在64位系统上工作,所以我只是将unsigned short
分成三个16位组件;代码也在32位系统下安全编译,但将种子中的第三个数字保留为0.像这样:
long
就我的目的而言,32位的播种值更受限制是可以的(不理想,但可以)。是的,我可以使用 case 'q':
qflag = true;
break;
case 'r':
check_range(optarg, &min, &max);
perturber = ptb_uniform;
break;
case 's':
sflag = true;
break;
case 't':
delim = optarg;
break;
case 'S':
seed = strtol(optarg, 0, 0);
break;
case 'V':
err_version("PERTURB", &"@(#)$Revision: 1.6 $ ($Date: 2015/08/06 05:05:21 $)"[4]);
/*NOTREACHED*/
default:
err_usage(usestr);
/*NOTREACHED*/
}
}
if (sflag)
printf("Seed: %ld\n", seed);
if (gflag)
{
unsigned short g_seed[3] = { 0, 0, 0 };
g_seed[0] = (unsigned short)(seed & 0xFFFF);
g_seed[2] = (unsigned short)((seed >> 16) & 0xFFFF);
if (sizeof(seed) > 4)
{
/* Avoid 32-bit right shift on 32-bit platform */
g_seed[1] = (unsigned short)(((seed >> 31) >> 1) & 0xFFFF);
}
gaussian_init(&g_control, g_seed);
}
else
srand48(seed);
filter_anon(argc, argv, optind, perturb);
return 0;
}
和unsigned long long
等来获取64位数字甚至在32位平台上(尽管我必须将其转换为strtoull()
无论如何要满足long
。我考虑的另一种方法是接受一个参数srand48()
,其中三个种子组件分别设置。然后我必须修改种子打印代码以及解析我使用一个单独的程序-S xxxx:yyyy:zzzz
来读取randseed
中的数字并格式化结果,以便将其传递给需要随机种子的程序:
/dev/urandom