关于golang的兰德包的问题

wmomyfyw  于 2023-04-09  发布在  Go
关注(0)|答案(2)|浏览(188)

我一直在使用和阅读有关Golang兰德包的内容,但我找不到一个资源,可以用我能理解的方式解释它的功能。
首先,当你“播种”时,到底发生了什么?如果你要求一个范围内的随机数(例如使用rand.Intn(7)),这似乎应该足以告诉Go你在寻找什么,但事实并非如此。rand.Seed()贡献了什么?
这里有一个例子,你可以在这里玩:

func main() {
  rand.Seed(time.Now().UnixNano())
  fmt.Println(rand.Intn(7))
}

我在想,也许“源”是你可以从中提取的所有可能的数字,然后类似于兰德.Intn()从Source的一个子集中给你一个随机数。所以播种只是定义Source。但是如果我尝试从初始种子之外的范围中获取随机数,它仍然有效,所以这似乎不正确,除非它只是排除了范围中不存在的部分。请参见以下示例:

func main() {
  rand.Seed(6)
  fmt.Println(rand.Intn(7))
}

那么文档中的这一行怎么说呢:
如果未调用“种子”,则生成器将在程序启动时随机设定种子。
这似乎不会发生,因为如果你不调用兰德.Seed(),而试图使用rand.Intn(),你只会得到同样的东西一遍又一遍,类似于如果你在rand.Seed()中使用常量。
第二,兰德.Intn()的文档说它“panics if n〈= 0”。我已经使用上面的链接测试过了,它不是真的,它会返回0而不会panics。我实际上想包含0,所以这很好,但它与文档所说的不一致。在指定范围时,是否有其他合适的方法来包含0?我找不到一个。
第三,文档在这里谈到了一个“默认源代码”。这是不是只是一个不需要我们做任何事情就存在的东西?然后如果我想要一个特定的源代码,我会使用兰德.New()来创建一个?为什么我想要一个特定的源代码?
Go的文档被认为是非常好的,经过深思熟虑的,所以我想我一定是错过了一些东西,感谢任何人的洞察力!

2cmtqfgy

2cmtqfgy1#

math/rand随机数生成器是一个“伪”随机数生成器。从概念上讲,它看起来像这样:

var last int

func nextRandom() int { 
   last:= computeRandom(last)
   return last
}

因此,它是一个确定性函数,它根据前一个值生成一个值序列。给定last的初始值,连续调用nextRandom将生成相同的值序列。
Seed设置last的值,因此通过将最后一个值设置为某个数字,例如当前时间,您将获得不同的数字序列。
在编写本文时(v1.19),随机数生成器在程序启动时 * 不 * 以随机数作为种子。这似乎在v1.20中有所改变。
Intnn<=0以下情况下死机:https://cs.opensource.google/go/go/+/refs/tags/go1.20.2:src/math/rand/rand.go;l=178
默认源是所有导出函数使用的包级Source示例:

var globalRand = New(new(lockedSource))

func Int63() int64 { return globalRand.Int63() }
...
soat7uwm

soat7uwm2#

兰德.Seed()贡献了什么?
播种伪随机数生成器意味着提供设置其状态的输入。伪随机数生成器然后从该状态创建随机性。如果您多次播种PRNG,则后面的种子值会混合在一起。
我在想,也许“源”是你可以从中提取的所有可能的数字,然后像兰德.Intn()这样的东西会从源的子集中给你一个随机数。
Source实际上是一个有限的RNG,因为它只产生位(或者,在本例中,只产生[0,2^63]范围内的整数值),当然,它只对应于63位。然后可以用来执行其他任务,例如生成其他范围内的数字,或者可能是 Shuffle 列表等。
这似乎不会发生,因为如果你不调用兰德(),而试图使用rand.Intn(),你只会得到同样的东西一遍又一遍,类似于如果你在rand.Seed()中使用常量。
这个seems to be a recent change。所以我猜你的运行时和文档不是同一个API版本。
第二,兰德()的文档说它“panics if n〈= 0”。我已经用上面的链接测试过了,这不是真的,它会返回0而不会panics。
听起来像一个bug。如果n确实是0或小于0,那么它应该会死机。
我实际上想包括0,所以这是好的,但它不符合什么文档说。有没有其他的,适当的方式来包括0时,指定一个范围?我找不到一个。
不知道你在这里的意思。如果你指定0,那么你得到的范围[0,0)没有任何意义,因为0首先作为起始值被包含,然后作为结束值被排除。你会期望[0,1)也有问题,因为仅仅返回0不是很随机(我仍然允许作为API设计者的函数,但是的,这是一个退化的情况)。
兰德.Intn()生成一个range [0,n)。无论n是什么,0都会包含在可能的输出中。
第三,文档在这里谈到了一个“默认源代码”。这是不是只是一个不需要我们做任何事情就存在的东西?然后如果我想要一个特定的源代码,我会使用兰德.New()来创建一个?为什么我想要一个特定的源代码?
好吧,也许你想创建一个非常具体的测试值运行,例如用于测试目的。

相关问题