在golang中保存随机状态

问题描述 投票:0回答:3

有没有办法在golang math/rand包中保存随机状态?

我想将其序列化并存储以供以后使用,但随机状态是一个接口,并且接口下的具体结构未导出(因此 json.Marshall 显然无法使用)。

作为保存 rand.Source 对象的替代方法,我考虑只保存底层的 int64 种子值。您可以使用 rand.Seed 设置它,但我没有找到一种方法来获取种子值,以便可以保留它以供以后使用。

go
3个回答
2
投票

正如您已经指出的,

math/rand
包无法让您深入了解(伪)随机数生成器的当前状态(种子)。如果您需要这个,您必须自己实现它(如匿名者所述)。

如果您愿意:好的,假设您知道随机数生成器的内部状态相当于设置种子值

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()
once

正如 Anonymous 所指出的,使用当前的伪随机数生成器算法,在某些“极端情况”下(例如,在每个生成的随机数之后调用 GetSeed())这可能会导致生成的随机数出现循环,并且将返回先前生成的随机数序列。序列的长度可能约为几千。下面是一个示例,其中序列的长度为 8034:

Repetition Go Playground 示例
但是再次强调:这不是正常用法,

GetSeed()

是在每次随机数生成后有意调用的;这仅适用于您使用

Rand
本身生成新种子的情况。例如,如果您使用当前时间重新播种
Rand
对象,则不会发生重复。
    


1
投票

一种方法是简单地从

http://golang.org/src/math/rand/rng.go

复制代码,并通过添加可以以您想要的方式编组状态的代码来对其进行调整。这将为您提供您自己的 rand.Source,您可以在

rand.New(myRandSource)
中使用它来生成随机数。
    


0
投票
添加

rand/v2支持保存和恢复状态。 您首先创建一个源并从该源创建一个生成器。然后,您可以编组源以捕获其当前状态,并解组到其中以恢复状态。

// create a source ( with better seed values than these ) src := rand.NewPCG(1, 2) // create a generator // and use r.Int(), etc. to generate numbers r := rand.New(src) // when you need, save the state: b, err := src.MarshalBinary() val := r.Int() // and later... restore the state: err = src.UnmarshalBinary(b) newVal:= r.Int()

val

newVal
是相同的。
完整示例:

https://play.golang.com/p/lV46qHX5WeL

© www.soinside.com 2019 - 2024. All rights reserved.