我在几个地方使用随机数,并且通常在需要时构建随机数生成器。目前我使用Marsaglia Xorshift算法将其与当前系统时间一起播种。 现在我对这个策略有些怀疑: 如果我使用几个生成器,则生成器之间的数字的独立性(随机性)取决于种子(相同的种子相同的数字)。因为我使用时间(ns)作为种子,并且因为这个时间改变了,但是我想知道仅使用一个奇异发生器并且例如是否更好。使其成为单身人士。这会增加随机数质量吗?
编辑:不幸的是,c ++ 11还不是一个选项
编辑:更具体一点:我并不是说单身人士可以提高随机数质量,而是只使用一个发电机并播种。否则,我必须确保不同发电机的种子是独立的(随机的)。 极端的例子:我种下两个具有完全相同数字的发电机 - >他们之间没有随机性
答案 0 :(得分:2)
假设您有几个变量,每个变量都需要是随机的,独立于其他变量,并且会定期使用来自某个随机生成器的新随机值重新分配。这种情况经常发生在蒙特卡洛分析和游戏中(尽管游戏的严谨程度远低于蒙特卡洛)。如果存在完美的随机数生成器,则可以使用它的单个实例化。将 n th 伪随机数从生成器分配给变量 x 1 ,下一个随机数变为< em> x 2 , x 3 旁边,等等,最终回到变量 x < / em> 1 在下一个周期。周围。这里存在一个问题:当使用这种方式时,太多的PRNG未通过独立性测试而无法通过独立性测试,有些甚至会对单个序列进行随机性测试失败。
我的方法是使用单个PRNG生成器作为一组自包含PRNG的 N 实例的种子生成器。后面这些PRNG的每个实例都提供一个变量。通过自包含,我的意思是PRNG是一个对象,状态在实例成员而不是静态成员或全局变量中维护。种子生成器甚至不需要来自与其他 N PRNG相同的族。在多个线程同时尝试使用种子生成器的情况下,它只需要是可重入的。但是,在我的使用中,我发现最好在线程开始之前设置PRNG,以保证可重复性。这是一次运行,一次执行。蒙特卡罗技术通常需要数千次执行,可能更多,甚至更多。使用蒙特卡罗,重复性至关重要。因此需要另一个随机种子生成器。这个种子生成器用于为变量生成 N 生成器。
重复性很重要,至少在蒙特卡罗世界是这样。假设长蒙特卡罗模拟的运行编号10234导致一些大的故障。很高兴看到世界上发生了什么。这可能是一个统计侥幸,它可能是一个问题。问题在于,在典型的MC设置中,仅记录最少的数据,足以用于计算统计数据。要查看运行编号10234中发生的情况,需要重复该特定情况,但现在记录所有内容。
答案 1 :(得分:1)
每当客户端相互关联且代码需要“独立”随机数时,您应该使用随机生成器类的相同实例。
当客户端不相互依赖时,您可以使用随机生成器类的不同对象,并且它们是否接收相同的数字并不重要。
请注意,对于测试和调试,能够再次创建相同的随机数序列非常有用。因此,你不应该“随机播种”太多。
答案 2 :(得分:0)
我不认为它增加了随机性,但它减少了每次想要使用随机生成器时创建对象所需的内存。如果此生成器没有任何特定于实例的设置,则可以创建一个单例。
答案 3 :(得分:0)
由于我使用时间(ns)作为种子,并且由于这个时间改变了,但是我想知道仅使用一个奇异发生器并且例如是否更好。使它成为一个单身人士。
当单例不是反模式时,这是一个很好的例子。您也可以使用某种inversion of control。
这会增加随机数质量吗?
没有。质量取决于生成随机数的算法。你如何使用它是无关紧要的(假设它被正确使用)。
要编辑:您可以创建某种容器来保存RNG类的对象(或使用现有容器)。像这样:
std::vector< Rng > & RngSingleton()
{
static std::vector< Rng > allRngs( 2 );
return allRngs;
}
struct Rng
{
void SetSeed( const int seen );
int GenerateNumber() const;
//...
};
// ...
RngSingleton().at(0).SetSeed( 55 );
RngSingleton().at(1).SetSeed( 55 );
//...
const auto value1 = RngSingleton().at(0).GenerateNumber;
const auto value2 = RngSingleton().at(1).GenerateNumber;
答案 4 :(得分:-1)
工厂模式的救援。 客户端永远不必担心其依赖项的实例化规则。 它允许交换创建方法。反过来说,如果你决定使用不同的算法,你可以交换生成器类,客户端不需要重构。 http://www.oodesign.com/factory-pattern.html
- 编辑
添加了伪代码(抱歉,这不是c ++,自从我上次工作以来,它已经很久了)
interface PRNG{
function generateRandomNumber():Number;
}
interface Seeder{
function getSeed() : Number;
}
interface PRNGFactory{
function createPRNG():PRNG;
}
class MarsagliaPRNG implements PRNG{
constructor( seed : Number ){
//store seed
}
function generateRandomNumber() : Number{
//do your magic
}
}
class SingletonMarsagliaPRNGFactory implements PRNGFactory{
var seeder : Seeder;
static var prng : PRNG;
function createPRNG() : PRNG{
return prng ||= new MarsagliaPRNG( seeder.getSeed() );
}
}
class TimeSeeder implements Seeder{
function getSeed():Number{
return now();
}
}
//usage:
seeder : Seeder = new TimeSeeder();
prngFactory : PRNGFactory = new SingletonMarsagliaPRNGFactory();
clientA.prng = prngFactory.createPRNG();
clientB.prng = prngFactory.createPRNG();
//both clients got the same instance.
现在最大的优势是,如果您希望/需要更改任何实现细节,则无需在客户端中进行任何更改。您可以更改播种方法,RNG算法和实例化规则,无需在任何地方触摸任何客户端。