如何从 C++ rand() 获取当前种子
How to get current seed from C++ rand()?
我基于C++ rand()函数在我的程序中生成了几千个对象。将它们保存在内存中将是详尽无遗的。有没有办法在任何给定时间复制 rand() 的当前种子?这将使我有机会仅存储当前种子而不是完整对象。(因此,我可以通过再生完全相同的随机数子序列来再生这些对象)
一个详尽的解决方案是存储 rand() 给出的完整随机数序列 - 不值得。另一个解决方案是为随机数实现我自己的类。
谷歌没有给我任何积极的线索。有数百篇文章教授兰德和斯兰德的基础知识,但我找不到具体的。
有谁知道其他带有已实现种子窃取器的随机数生成器?
感谢您的快速回答!这个问题有更多可能的答案/解决方案,所以我在这里列出了你的答案。
解决 方案:
-
简短的回答是:没有标准的方法可以获得种子
-
最接近的解决方法是在开始时保存 INITIAL 种子,并计算您调用 rand() 函数的次数。我将其标记为解决方案,因为它适用于每个编译器的当前 std::rand() 函数(这是主要问题)。我对我的 2.0 GHz CPU 进行了基准测试,发现我可以在 35 秒内调用和计数 rand() 1,000,000,000 次。这听起来不错,但我有 80,000 次调用来生成一个对象。这会将代数限制为 50,000,因为大小为无符号长。无论如何,这是我的代码:
class rand2 { unsigned long n; public: rand2 () : n(0) {} unsigned long rnd() { n++; return rand(); } // get number of rand() calls inside this object unsigned long getno () { return n; } // fast forward to a saved position called rec void fast_forward (unsigned long rec) { while (n < rec) rnd(); } };
-
另一种方法是实现自己的伪随机数生成器,就像Matteo Italia建议的那样。这是最快的,也可能是最好的解决方案。您不限于 4,294,967,295 次 rand() 调用,也不需要使用其他库。值得一提的是,不同的编译器有不同的生成器。我已经将Matteo的LCG与Mingw/GCC 3.4.2和G ++ 4.3.2中的rand()进行了比较。所有 3 个都不同(种子 = 0)。
-
使用来自C++11或其他图书馆的生成器,如Cubbi,Jerry Coffin和Mike Seymour建议的那样。如果您已经在与他们合作,这是最好的主意。C++11 发电机的链接:http://en.cppreference.com/w/cpp/numeric/random(这里也有一些算法说明)
有谁知道其他带有已实现种子窃取器的随机数生成器
所有标准 C++11 随机数生成器(在 TR1 和 Boost 中也可用)都提供此功能。您可以简单地复制生成器对象或序列化/反序列化它们。
标准方法来获取当前种子(您只能通过 srand
设置它),但您可以在几行代码中自己重新实现rand()
(通常是线性全余生成器):
class LCG
{
private:
unsigned long next = 1;
public:
LCG(unsigned long seed) : next(seed) {}
const unsigned long rand_max = 32767
int rand()
{
next = next * 1103515245 + 12345;
return (unsigned int)(next/65536) % 32768;
}
void reseed(unsigned long seed)
{
next = seed;
}
unsigned long getseed()
{
return next;
}
};
使用 srand() 设置种子。 保存用作种子的值。
http://cplusplus.com/reference/clibrary/cstdlib/srand/
C++11 中的随机数生成类支持operator<<
存储其状态(主要是种子),并operator>>
将其读回。所以,基本上,在创建对象之前,保存状态,然后当你需要重新生成相同的序列时,重新读取状态,然后就可以了。
rand()
不提供任何提取或复制种子的方法。你能做的最好的事情就是在用srand()
设置种子时存储种子的初始值,然后从中重建整个序列。
Posix 函数rand_r()
可让您控制种子。
C++11 库包括一个基于序列生成"引擎"的随机数库;这些引擎是可复制的,并允许使用 <<
和 >>
运算符提取和恢复其状态,以便您可以随时捕获序列的状态。TR1 和 Boost 中提供了非常相似的库,如果你还不能使用 C++11。
有没有办法在任何给定时间复制 rand() 的当前种子?
以下是保存和恢复伪随机数生成器 (PRNG) 状态的特定于实现的方法,该状态适用于 Ubuntu Linux 上的 C 库(在 14.04 和 16.04 上测试)。
#include <array>
#include <cstdlib>
#include <iostream>
using namespace std;
constexpr size_t StateSize = 128;
using RandState = array<char, StateSize>;
void save(RandState& state) {
RandState tmpState;
char* oldState = initstate(1, tmpState.data(), StateSize);
copy(oldState, oldState + StateSize, state.data());
setstate(oldState);
}
void restore(RandState& state) {
setstate(state.data());
}
int main() {
cout << "srand(1)n";
srand(1);
cout << " rand(): " << rand() << 'n';
cout << " rand(): " << rand() << 'n';
cout << " rand(): " << rand() << 'n';
cout << " rand(): " << rand() << 'n';
cout << " rand(): " << rand() << 'n';
cout << " rand(): " << rand() << 'n';
cout << " rand(): " << rand() << 'n';
cout << " rand(): " << rand() << 'n';
cout << "srand(1)n";
srand(1);
cout << " rand(): " << rand() << 'n';
cout << " rand(): " << rand() << 'n';
cout << " rand(): " << rand() << 'n';
cout << " rand(): " << rand() << 'n';
cout << "save()n";
RandState state;
save(state);
cout << " rand(): " << rand() << 'n';
cout << " rand(): " << rand() << 'n';
cout << " rand(): " << rand() << 'n';
cout << " rand(): " << rand() << 'n';
cout << "restore()n";
restore(state);
cout << " rand(): " << rand() << 'n';
cout << " rand(): " << rand() << 'n';
cout << " rand(): " << rand() << 'n';
cout << " rand(): " << rand() << 'n';
}
这依赖于:
- C 库用于公开
rand()
和random()
接口的相同 PRNG,以及 - 有关 C 库中此 PRNG 的默认初始化的一些知识(128 字节状态)。
如果运行,这应该输出:
srand(1)
rand(): 1804289383
rand(): 846930886
rand(): 1681692777
rand(): 1714636915
rand(): 1957747793
rand(): 424238335
rand(): 719885386
rand(): 1649760492
srand(1)
rand(): 1804289383
rand(): 846930886
rand(): 1681692777
rand(): 1714636915
save()
rand(): 1957747793
rand(): 424238335
rand(): 719885386
rand(): 1649760492
restore()
rand(): 1957747793
rand(): 424238335
rand(): 719885386
rand(): 1649760492
此解决方案在某些情况下会有所帮助(无法更改的代码、出于调试目的重现执行等),但显然不建议将其作为通用解决方案(例如,使用 C++11 PRNG 来正确支持此功能)。
您可以尝试在 srand 之前(或之后)保存用于播种的值。
因此,例如:
int seed = time(NULL);
srand(time(NULL));
cout << seed << endl;
cout << time(NULL);
这两个值应相同。
我建议您使用Mersenne Twister伪随机数生成器。它速度很快,并提供非常好的随机数。您可以非常简单地在类的构造函数中播种生成器:
unsigned long rSeed = 10;
MTRand myRandGen(rSeed);
然后你只需要把你用来生成序列的种子存储在某个地方......
- C++为构建时间获取QDateTime的可靠方法
- lambda参数转换为constexpr技巧,然后获取带链接的数组
- 如何使用 < 和 > 命令获取 c++ 中的输入和输出?
- 使用指针从C++中的数组中获取最大值
- 如何获取std::result_of函数的返回类型
- 如何在openssl-ecc中获取十六进制格式的私钥
- 使用Unreal C++获取VR耳机的世界位置/方向
- 获取日期异步信号安全吗?如果在信号处理程序中使用,它会导致死锁吗
- 从C字符串中获取奇怪的字符串长度
- 为什么我的for循环不能正确获取argv
- 从python中调用C++函数并获取返回值
- 如何获取一个数字的前3位
- 获取字符串的长度并将其分配给数组
- 无法获取菜单选择以运行函数.C++
- 数组长度,为什么从命令行获取时不能使用它?
- Boost Spirit,获取迭代器内部语义动作
- 尝试通过OCI例程从Oracle获取blob数据,但出现错误:ORA-01008:并非所有变量都绑定
- 具有默认值的引用获取函数
- 如何从 C++ rand() 获取当前种子
- 获取外部来源的种子