我正在尝试创建一个类,为多个分布生成随机数,同时保持它们的可重复性(通过设置初始种子)。
该代码似乎有效,直到我开始使用正态分布和奇怪的错误表面。这些主要是:
- 如果我取消注释
double a = rnd.rnorm(0.0, 1.0);
-line(第40行)(也就是说,如果我打电话rnorm
在设置种子之前),正态分布的第一个随机数不再匹配,之后的随机数再次匹配
- 如果我从正态分布中检索奇数个随机数,则正态随机数将移位 1(例如,将第 39 行设置为
int n = 3;
)
- 如果我同时做这两件事,随机数就会向另一个方向移动一个(引导)
现在我的问题是,是什么导致了这种奇怪的行为?我实施了吗RNG
以错误的方式?最重要的是,我该如何解决它?
Code
如果您想自己测试结果,可以使用这个http://cpp.sh/9phre http://cpp.sh/9phre
or this
#include <stdio.h>
#include <random>
// Class to create random numbers
// Main functions to set the seed: setseed()
// create uniformly distributed values: runif()
// and normally distributed values: rnorm()
class RNG {
public:
RNG(int seed = (int) time(0)) {
setseed(seed);
};
~RNG() {};
void setseed(int newSeed) {
re.seed(newSeed);
};
double runif(double minNum, double maxNum) {
return dud(re, distUnifDbl::param_type{minNum, maxNum});
};
double rnorm(double mu, double sd) {
return dnd(re, distNormDbl::param_type{mu, sd});
};
private:
// take the Mersenne-Twister Engine
std::mt19937 re {};
// create the uniform distribution
using distUnifDbl = std::uniform_real_distribution<double>;
distUnifDbl dud {};
// create the normal distribution
using distNormDbl = std::normal_distribution<double>;
distNormDbl dnd {};
};
int main(int argc, char const *argv[]) {
RNG rnd;
int n = 4; // setting n to an odd number, makes _all_ normal numbers non-reproducible
//double a = rnd.rnorm(0.0, 1.0); // uncommenting this, makes the _first_ normal number non-reproducible
printf("Testing some Uniform Numbers\n");
rnd.setseed(123);
for (int i = 0; i < n; ++i) {
printf("% 13.10f ", rnd.runif(0.0, 1.0));
}
rnd.setseed(123);
printf("\n");
for (int i = 0; i < n; ++i) {
printf("% 13.10f ", rnd.runif(0.0, 1.0));
}
printf("\n");
printf("\nTesting some Normal Numbers\n");
rnd.setseed(123);
for (int i = 0; i < n; ++i) {
printf("% 13.10f ", rnd.rnorm(0.0, 1.0));
}
rnd.setseed(123);
printf("\n");
for (int i = 0; i < n; ++i) {
printf("% 13.10f ", rnd.rnorm(0.0, 1.0));
}
printf("\n");
return 0;
}
Results
基本情况
设置时n = 4
并离开a
评论后,我收到以下内容(这正是我想要/需要的;可重复的“随机”数字):
Testing some Uniform Numbers
0.7129553216 0.4284709250 0.6908848514 0.7191503089
0.7129553216 0.4284709250 0.6908848514 0.7191503089
Testing some Normal Numbers
-0.5696096995 1.6958337120 1.1108714913 0.9675940713
-0.5696096995 1.6958337120 1.1108714913 0.9675940713
Error 1
现在来说说错误。环境n = 5
(或任何奇数),我收到:
Testing some Uniform Numbers
0.7129553216 0.4284709250 0.6908848514 0.7191503089 0.4911189328
0.7129553216 0.4284709250 0.6908848514 0.7191503089 0.4911189328
Testing some Normal Numbers
-0.5696096995 1.6958337120 1.1108714913 0.9675940713 1.5213608069
-0.0482498863 -0.5696096995 1.6958337120 1.1108714913 0.9675940713
这显然是shifts所有正常数字都减 1。统一数字保持不变(我想这很好)。
Error 2
取消注释一行(即调用rnd.rnorm(0.0, 1.0)
once before设置种子),会产生以下输出(n = 4
或任何其他偶数)
Testing some Uniform Numbers
0.7129553216 0.4284709250 0.6908848514 0.7191503089
0.7129553216 0.4284709250 0.6908848514 0.7191503089
Testing some Normal Numbers
0.9761557076 -0.5696096995 1.6958337120 1.1108714913
0.9675940713 -0.5696096995 1.6958337120 1.1108714913
这显然打破了只有第一个正常随机数,再次保留统一数字即可。
Error 3
一起使用这两个点(保留该行未注释并将 n 设置为奇数),我得到这个
Testing some Uniform Numbers
0.7129553216 0.4284709250 0.6908848514 0.7191503089 0.4911189328
0.7129553216 0.4284709250 0.6908848514 0.7191503089 0.4911189328
Testing some Normal Numbers
-0.4553400276 -0.5696096995 1.6958337120 1.1108714913 0.9675940713
-0.5696096995 1.6958337120 1.1108714913 0.9675940713 1.5213608069
现在,第二个正态随机数被移至另一个方向(前导)。
系统规格
我在 Ubuntu 16.04 上使用这个g++ --version
g++(Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609
Updates
它似乎没有连接到特定的发电机,即更换std::mt19937 re {};
with std:: linear_congruential_engine<std::uint_fast32_t, 48271, 0, 2147483647> re {};
,或与std::subtract_with_carry_engine<std::uint_fast64_t, 48, 5, 12> re{};
导致相同的行为(但显然数字不同)。