我有一个函数从一组字母表中生成随机字符。这个函数将被多次调用,因此我试图让它使用相同的变量集,即具有相同的种子,这样字符串就不会重复尽可能长的时间。
#include <iostream>
#include <random>
#include <string>
std::string generateRandomChar(const unsigned int _len)
{
std::string result;
result.reserve(_len);
static constexpr char alphanum[] = "0123456789"
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> dis(0, 61);
for (int i = 0; i < _len;
result += (alphanum[dis(gen)]);
}
return result;
}
int main(){
for(int i = 0; i < 10; ++i){
std::cout << generateRandomChar(10) << std::endl;
}
}
不幸的是,我对C++11 <random>
函数没有任何专门知识,而且我之前只使用了srand
和朋友,所以我在这里可能会犯很多错误。目前,它不重复地工作并生成大量字符串,但我确信我可以做到以下两种:
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> dis(0, 61);
静态变量也是如此,所以每次调用函数时都不会计算它,因为这会浪费时间,对吗?
那么哪一个应该是静态的呢?你在这里看到了什么错误/改进吗?
艾德龙
发布于 2018-10-26 20:18:03
无论您放在哪里,static
都会极大地改变您的程序的行为。最后,我们有了2^3 = 8组合,所以让我们检查其中的一些。
如果没有用于随机数的硬件设备,random_device
可能会退回到伪随机引擎。如果在本例中不对static
使用random_device
,则所有字符串都可能以相同的方式结束,因为伪随机引擎可能会使用定义的固定种子来初始化。
std::random_device a;
std::random_device b;
assert(a() == b()); // worst case if no hardware-device or a low-effort implementation is used
在这种情况下,mt19937
将始终以相同的值作为种子,我们在每次调用中都会得到相同的字符串。如果mt19937
或random_device
是静态的,这种情况就会改变,如果dist
是静态的,则可能会改变,因为uniform_int_distribution
可以使用几次对生成器的内部状态调用。
当然,如果mt19937
是静态的,那么您也可以将random_device
更改为static
变体,因为它只需要计算一次。这是您在程序开始时最接近单个srand()
调用的地方。但是,您的uniform_int_distribution
仍然失去了它的内部状态。
最后,这取决于我们是否希望两个generateRandomChar
调用相互关联。如果它们根本不相关,我们需要用一个新的非确定数重新分配我们的PRNG,并且根本不能使用static
。
或者,换一种说法:如果我们对所有三个值都使用static
,那么
generateRandomChar(10) + generateRandomChar(10)
与generateRandomChar(20)相同--如果我们在mt19937
上使用static
,那么两者可能是相同的,这取决于_len
和dist
。
无论哪种方式,如果您希望对生成有更多的控制,您只需在您的函数中提供一个生成器:
template <typename Generator>
std::string generateRandomChar(Generator & gen, const unsigned int _len)
{
...
}
分配的情况也是一样。
除此之外,我将使用sizeof
而不是61
来确保在不更改dist
's构造函数中的数字界的情况下,不会意外地更改可能的字符池:
static constexpr char alphanum[] = "0123456789"
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> dis(0, sizeof(alphanum) - 1);
发布于 2016-09-21 18:35:37
我认为您应该为此创建一个单独的包装类。我使用了以下方法:
#include <random>
class randomStreamUniformInt {
public:
explicit randomStreamUniformInt(int lower_bound, int upper_bound)
: mt(rand()), uniform_dist(lower_bound, upper_bound) {}
explicit randomStreamUniformInt(int lower_bound, int upper_bound, double seed)
: mt(seed), uniform_dist(lower_bound, upper_bound) {}
int operator ()(void) { return uniform_dist(mt); }
private:
std::mt19937_64 mt;
std::uniform_int_distribution<> uniform_dist;
};
显然,您可以将其扩展到使用首选生成器。然后,您应该将这个引用传递给您的函数,或者用generateRandomChar作为方法创建一个类。
https://codereview.stackexchange.com/questions/141989
复制相似问题