有没有办法在golang math / rand包中保存随机状态?
我想将它序列化并存储以供以后使用,但随机状态是一个接口,接口下面的具体结构是未导出的(因此显然不能使用json.Marshall)。
作为保存rand.Source对象的替代方法,我想过只保存底层的int64种子值。您可以使用rand.Seed进行设置,但我没有找到获取种子值的方法,以便可以保留以供以后使用。
答案 0 :(得分:1)
您可以制作自己的随机数源,可以编组。
一种方法是简单地从http://golang.org/src/math/rand/rng.go复制代码并通过添加可以以任何方式编组状态的代码来对其进行调整。这将为您提供自己的rand.Source
,您可以在rand.New(myRandSource)
中使用它来生成随机数。
答案 1 :(得分:1)
正如您已经指出的那样,math/rand
包不会让您深入了解(伪)随机数生成器的当前状态(种子)。如果你需要这个,你必须自己实现它(如匿名所述)。
如果你愿意:好的,让我们说你知道随机数生成器的内部状态等于种子值1234
的设置。如果种子是任何其他混凝土或随机的"号码?
这里提示如何模拟"访问生成器的种子值:
假设您已经创建了Rand
个对象,您已经设置并使用它(已经生成了一些随机数)。此Rand
对象也可能是math/rand
包的默认/全局,它不必是一个独特的Rand
。
你达到了想要保存" sate"随机数生成器的顺序,以便以后您可以从这一点重复精确的伪随机序列。这将需要获取当前种子,稍后当您想要从此点重复序列时,您只需将存储的种子设置为Rand
对象。问题:您无法访问的种子。
但你可以做的是设置一个新的种子,然后你知道内部种子是你刚设置的种子!所以要模拟一个GetSeed()
(在默认的{{} 1 {} Rand
包裹:
math/rand
要模拟func GetSeed() int64 {
seed := time.Now().UnixNano() // A new random seed (independent from state)
rand.Seed(seed)
return seed
}
或任何GetSeed()
(不是默认值):
Rand
上面提出的func GetSeed2(r rand.Rand) int64 {
seed := time.Now().UnixNano() // A new random seed (independent from state)
r.Seed(seed)
return seed
}
使用当前时间来重新种子" GetSeed()
对象。这将根据调用的时间改变伪随机序列。这可能是也可能不是(在大多数情况下这不是问题)。
但如果是,我们可以避免这种情况,如果我们使用Rand
对象本身来指定这样的新种子(通过这样做,新种子将仅取决于当前状态 - 当前种子):
Rand
备注:强>
func GetSeed() int64 {
seed := rand.Int63() // A new pseudo-random seed: determined by current state/seed
rand.Seed(seed)
return seed
}
func GetSeed2(r rand.Rand) int64 {
seed := r.Int63() // A new pseudo-random seed: determined by current state/seed
r.Seed(seed)
return seed
}
功能旨在偶尔使用 ,例如当你想要保存游戏时。正常使用情况是生成数千个随机数,并仅在时调用GetSeed()
。
正如Anonymous所指出的,使用伪随机数生成器的当前算法,在某些极端情况下(例如,在每个生成的随机数之后调用GetSeed()
),这可能会导致在生成的随机数的循环中,将返回先前生成的随机数序列。序列的长度可能约为几千。以下是序列长度为8034的示例:Repetition Go Playground Example。
但同样:这不是正常用法,在每个随机数生成后故意调用GetSeed()
;这仅适用于使用GetSeed()
本身生成新种子的情况。例如,如果您使用当前时间重新种子Rand
对象,则不会重复。