2 回答
TA贡献1936条经验 获得超6个赞
正如您已经注意到的那样,该math/rand包不会让您深入了解(伪)随机数生成器的当前状态(种子)。如果你需要这个,你必须自己实现它(如 Anonymous 所提到的)。
如果您愿意:好的,假设您知道随机数生成器的内部状态等同于1234将设置种子值的位置。这比种子是任何其他具体或“随机”数字有什么好处?
以下是如何“模拟”访问生成器种子值的提示:
假设您已经创建了Rand对象,已经设置并使用了它(已经生成了一些随机数)。这个Rand对象也可能是math/rand包的默认/全局对象,它不必是一个不同的Rand.
您到达了一个点,您希望按顺序保存随机数生成器的“状态”,以便稍后您可以从该点重复精确的伪随机序列。这将需要获取当前种子,稍后当您想从这一点开始重复序列时,您只需将存储的种子设置为Rand对象。问题:您无法访问的种子。
但是您可以做的是设置一个新种子,然后您就会知道内部种子就是您刚刚设置的那个!所以要模拟一个GetSeed()(在包的默认值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()功能旨在偶尔使用,例如当您想保存游戏时。正常用法是生成数千个随机数并且只调用GetSeed() 一次。
正如 Anonymous 所指出的,使用伪随机数生成器的当前算法,在某些极端情况下(例如您GetSeed()在每个生成的随机数之后调用)这可能会导致生成的随机数出现循环并返回之前生成的序列的随机数。序列的长度可能在几千左右。这是一个序列长度为 8034 的示例:Repetition Go Playground Example。
但同样:这不是正常用法,GetSeed()在每次随机数生成后有意调用;这仅适用于您使用Rand自身生成新种子的情况。Rand例如,如果您使用当前时间重新设置对象,则不会发生重复。
- 2 回答
- 0 关注
- 181 浏览
添加回答
举报