解决Go中使用seed得到相同随机数的问题_Golang

来源:脚本之家  责任编辑:小易  

其实这个MC把染料归为一大类,中间再分小类,墨囊你可以直接用351,然后青金石可以用351:4来实现。虽然它们的代码英文名都是一样的,但是也有一个区分的方法,那就是后面的指数代码。青金石的代码是4,而墨囊的代码是0,所以你如果不输入这个指令代码的话,默认是0,就会给你墨囊了,而如果你输入4,那么就会给你青金石了。青金石(Lapis Lazuli)是一种基本染料和附魔用品www.zgxue.com防采集请勿采集本网。

1. 重复的随机数

设该数为x,余数r 300=ax+r 262=bx+r 205=cx+r 上三个式子两两做减法,得 38=(a-b)x 95=(a-c)x 57=(b-c)x 而a,b,c和x都为自然数,另一方面 38=2 x 19,95=5 x 19,57=3 x 19 所以不难知道

废话不多说,首先我们来看使用seed的一个很神奇的现象。

1、go v.去;离开;变得;进行 n.去;尝试;精力;一举 例句:(1)We' ll go for a walk if you feel like it. 你愿意的话,咱们就去散散步。(2)I must be going. 我该走了。(3)The boat rolled gently

func main() { for i := 0; i < 5; i++ { rand.Seed(time.Now().Unix()) fmt.Println(rand.Intn(100)) }}// 结果如下// 90// 90// 90// 90// 90

一个成熟的人使用有效的归因来解释事件,从而获得可改变的可能性;一个不成熟的人会使用无效的归因来解释事件,放过自己或推给他人。我们都喜欢逃避。任务难度增加,会导致人逃避的几率。逃避责任,可以让

可能不熟悉seed用法的看到这里会很疑惑,我不是都用了seed吗?为何我随机出来的数字都是一样的?不应该每次都不一样吗?

同一网段的意思就是多个IP如果具有相同的网络地址就认为他们在同一网段。举例子说明:192.168.1.60和192.168.1.70两个IP如果使用掩码都是255.255.255.0的话,网络地址相同为192.168.1.0那么两个

可能会有人说是你数据的样本空间太小了,OK,我们加大样本空间到10w再试试。

300-262=38 300-205=95 262-205=57 38,95,57的公约数有:1和19, 因为这个整数不小于:2, 所以这个整数是:19,

func main() { for i := 0; i < 5; i++ { rand.Seed(time.Now().Unix()) fmt.Println(rand.Intn(100000)) }}// 结果如下// 84077// 84077// 84077// 84077// 84077

你会发现结果仍然是一样的。简单的推理一下我们就能知道,在上面那种情况,每次都取到相同的随机数跟我们所取的样本空间大小是无关的。那么唯一有关的就是seed。我们首先得明确seed的用途。

2. seed的用途

在这里就不卖关子了,先给出结论。

上面每次得到相同随机数是因为在上面的循环中,每次操作的间隔都在毫秒级下,所以每次通过time.Now().Unix()取出来的时间戳都是同一个值,换句话说就是使用了同一个seed。

这个其实很好验证。只需要在每次循环的时候将生成的时间戳打印出来,你就会发现每次打印出来的时间戳都是一样的。

每次rand都会使用相同的seed来生成随机队列,这样一来在循环中使用相同seed得到的随机队列都是相同的,而生成随机数时每次都会去取同一个位置的数,所以每次取到的随机数都是相同的。

seed 只用于决定一个确定的随机序列。不管seed多大多小,只要随机序列一确定,本身就不会再重复。除非是样本空间太小。解决方案有两种:

在全局初始化调用一次seed即可

每次使用纳秒级别的种子(强烈不推荐这种)

3. 不用每次调用

上面的解决方案建议各位不要使用第二种,给出是因为在某种情况下的确可以解决问题。比如在你的服务中使用这个seed的地方是串行的,那么每次得到的随机序列的确会不一样。

但是如果在高并发下呢?你能够保证每次取到的还是不一样的吗?事实证明,在高并发下,即使使用UnixNano作为解决方案,同样会得到相同的时间戳,Go官方也不建议在服务中同时调用。

Seed should not be called concurrently with any other Rand method.

接下来会带大家了解一下代码的细节。想了解源码的可以继续读下去。

4. 源码解析-seed

4.1 seed

首先来看一下seed做了什么。

func (rng *rngSource) Seed(seed int64) { rng.tap = 0 rng.feed = rngLen - rngTap seed = seed % int32max if seed < 0 { // 如果是负数,则强行转换为一个int32的整数 seed += int32max } if seed == 0 { // 如果seed没有被赋值,则默认给一个值 seed = 89482311 } x := int32(seed) for i := -20; i < rngLen; i++ { x = seedrand(x) if i >= 0 { var u int64 u = int64(x) << 40 x = seedrand(x) u ^= int64(x) << 20 x = seedrand(x) u ^= int64(x) u ^= rngCooked[i] rng.vec[i] = u } }}

首先,seed赋值了两个定义好的变量,rng.tap和rng.feed。rngLen和rngTap是两个常量。我们来看一下相关的常量定义。

const ( rngLen = 607 rngTap = 273 rngMax = 1 << 63 rngMask = rngMax - 1 int32max = (1 << 31) - 1)

由此可见,无论seed是否相同,这两个变量的值都不会受seed的影响。同时,seed的值会最终决定x的值,只要seed相同,则得到的x就相同。而且无论seed是否被赋值,只要检测到是零值,都会默认的赋值为89482311。

接下来我们再看seedrand。

4.2 seedrand

// seed rng x[n+1] = 48271 * x[n] mod (2**31 - 1)func seedrand(x int32) int32 { const ( A = 48271 Q = 44488 R = 3399 ) hi := x / Q // 取除数 lo := x % Q // 取余数 x = A*lo - R*hi // 通过公式重新给x赋值 if x < 0 { x += int32max // 如果x是负数,则强行转换为一个int32的正整数 } return x}

可以看出,只要传入的x相同,则最后输出的x一定相同。进而最后得到的随机序列rng.vec就相同。

到此我们验证我们最开始给出的结论,即只要每次传入的seed相同,则生成的随机序列就相同。验证了这个之后我们再继续验证为什么每次取到的随机序列的值都是相同的。

5. 源码解析-Intn

首先举个例子,来直观的描述上面提到的问题。

func printRandom() { for i := 0; i < 2; i++ { fmt.Println(rand.Intn(100)) }}// 结果// 81// 87// 81// 87

假设printRandom是一个单独的Go文件,那么你无论run多少次,每次打印出来的随机序列都是一样的。通过阅读seed的源码我们知道,这是因为生成了相同的随机序列。那么为什么会每次都取到同样的值呢?不说废话,我们一层一层来看。

5.1 Intn

func (r *Rand) Intn(n int) int { if n <= 0 { panic("invalid argument to Intn") } if n <= 1<<31-1 { return int(r.Int31n(int32(n))) } return int(r.Int63n(int64(n)))}

可以看到,如果n小于等于0,就会直接panic。其次,会根据传入的数据类型,返回对应的类型。

虽然说这里调用分成了Int31n和Int63n,但是往下看的你会发现,其实都是调用的r.Int63(),只不过在返回64位的时候做了一个右移的操作。

// r.Int31n的调用func (r *Rand) Int31() int32 { return int32(r.Int63() >> 32) }// r.Int63n的调用func (r *Rand) Int63() int64 { return r.src.Int63() }

5.2 Int63

先给出这个函数的相关代码。

// 返回一个非负的int64伪随机数.func (rng *rngSource) Int63() int64 { return int64(rng.Uint64() & rngMask)}func (rng *rngSource) Uint64() uint64 { rng.tap-- if rng.tap < 0 { rng.tap += rngLen } rng.feed-- if rng.feed < 0 { rng.feed += rngLen } x := rng.vec[rng.feed] + rng.vec[rng.tap] rng.vec[rng.feed] = x return uint64(x)}

可以看到,无论是int31还是int63,最终都会进入Uint64这个函数中。而在这两个函数中,这两个变量的值显得尤为关键。因为直接决定了最后得到的随机数,这两个变量的赋值如下。

rng.tap = 0rng.feed = rngLen - rngTap

tap的值是常量0,而feed的值决定于rngLen和rngTap,而这两个变量的值也是一个常量。如此,每次从随机队列中取到的值都是确定的两个值的和。

到这,我们也验证了只要传入的seed相同,并且每次都调用seed方法,那么每次随机出来的值一定是相同的。

6. 结论

首先评估是否需要使用seed,其次,使用seed只需要在全局调用一次即可,如果多次调用则有可能取到相同随机数。

总结

以上所述是小编给大家介绍的解决Go中使用seed得到相同随机数的问题,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对真格学网网站的支持!

如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

1、go after 追求,设法获得2、go on 继续3、go on with 继续4、go against 反对,违背5、go ahead 向前,干吧,说吧,用吧6、go by 从旁经过7、go down下降,倒下8、go up上涨9、go in for 酷爱10、go over 走过去,温习11、go through仔细查看,浏览,翻阅,通过12、go wrong出毛病13、go out出去,熄灭14、go around到处去,传开15、go swimming去游泳16、goes on继续;持续17、go to school去上学18、go to bed上床睡觉19、goes home回家20、go out for a walk出去散步21、go away走开22、goes down降落23、go back回去24、go on with继续做某事25、go a little way 不大有作用,走一点点路26、go a long way 大有帮助,走了一大段路,采取主动27、go about 着手做,从事,走动,传开28、go across 走过29、go against the stream 逆流而行,反潮流30、go all lengths 竭尽全力扩展资料go 用法1、用作动词go用作不及物动词时,常可接带to的动词不定式,这动词不定式并不是用作状语表示目的,而是与go构成一个动词短语,意思是“去做某事”,在非正式英语中,这种结构常可变为go and do sth,而在美式英语中and常被省去。go常用于“be going to+动词原形”结构,可以用于表示时间,即“将要做某事”;也可以用于表示意志,即“打算做某事”、“准备做某事”。表示“将要做某事”的用法在美式英语中使用得很广泛,大有取代英式英语中的shall〔will〕之势。表示“打算做某事”、“准备做某事”时多用于人称结构,用于被动语态时则可用于非人称结构,表示情况的必然或或然等。用于一般过去时态,be going to所表示的意图往往是未达到的。也可为非人称代词it,用于自然现象。例:I was going to see you yesterday,but it rained.我本本打算昨天去看你,可是下雨了。“be going to”后有时也可接名词(多表示地点),这时to是介词。现代英语中也可用“be going to go to”,两者意思相同,都表示“去某地”,但后者使用不太广泛。“not going to”的含义因主语不同而有异。当主语是第一人称时意为“(主语)不愿做某事”;当主语是第二或第三人称时则意为“(说话人)不许(主语)做某事”或“(说话人)认为(主语)无权做某事”。go to后常接不带冠词的名词,表示去进行一种活动,而不表示去什么地方。例如:go to school 上学(习惯用法)go在用作不及物动词时,其主动结构有时含有被动意义,这主要用于:(1)以废弃、去掉、放弃的东西作主语。常与must,have to,can等连用;(2)以花费的金钱〔时间〕作主语,常以in引出花钱〔时间〕的项目,以on引出花钱〔时间〕的目标;(3)以售卖的东西作主语,接to引出买主,接at引出单价,接for引出卖得的钱;(4)以授予的奖品、称号或财产作主语,以to引出承受人;(5)以装入物为主语,以in引出容纳物。也可用作系动词,其后多接形容词或常用作形容词的过去分词作表语,多表示不好的意思。go用作系动词时,还可以现在分词作补足语,这种用法源自“go+动名词“,一般用来表示:带有经常性的一般活动,如goshopping;带有一定程度的职业性活动,如go soldiering;体育运动或娱乐消遣,如go swimming〔fishing〕等。2、用作名词go可指在游戏中轮到某人做游戏;在口语中,也可指人精力充沛或具有活力和生气;还可指疾病等的侵袭或发作。have a go的意思是“尝试”、“抱怨”。make a go of的意思是“成功”。on the go的意思是“忙碌”内容来自www.zgxue.com请勿采集。


  • 本文相关:
  • golang 中的随机数的示例代码
  • go语言排序算法之插入排序与生成随机数详解
  • 利用golang生成整数随机数方法示例
  • golang编程实现生成n个从a到b不重复随机数的方法
  • go语言返回1-99之间随机数的方法
  • go语言生成随机数的方法
  • go 字符串格式化的实例代码详解
  • mac下golang安装了windows编译环境后编译变慢
  • go语言waitgroup使用时需要注意的坑
  • go 并发实现协程同步的多种解决方法
  • go语言中使用timer的常用方式
  • go语言make()分配用法实例
  • golang中数据结构queue的实现方法详解
  • go语言telnet回音服务器的实现
  • go时间/时间戳操作大全(小结)
  • go实现整型的二进制转化的方法
  • 关于go开头的 词组动词30个
  • minecraft中想用give指令得到青金石,但是它和墨囊的代码相同,怎么办?
  • 此网络中的另一台计算机与该计算机的ip地址相同,怎么解决啊,我路由
  • 求数学高手解决:设随机变量x i(i=1,2)具有相同的分布列,且满足P(x1,x2=0)=1则P(x1=x2)=答案为什么为0?
  • 有一个自然数,用它去除300,262,205得到相同的非零余数,求这个自然数
  • go、do、qlay、have的不同用法和短语
  • 长期按照相同的思维方式去解决问题这叫什么
  • 同一网段什么意思,百科上讲IP地址与子网掩码相与得到相同的网络地址。
  • 有一个整数,除300,262,205得到相同的余数,这个整数是多少
  • wrest from和go on意思相同吗
  • 网站首页网页制作脚本下载服务器操作系统网站运营平面设计媒体动画电脑基础硬件教程网络安全vbsdos/bathtahtcpythonperl游戏相关vba远程脚本coldfusionruby专题autoitseraphzonepowershelllinux shellluagolangerlang其它首页golanggolang 中的随机数的示例代码go语言排序算法之插入排序与生成随机数详解利用golang生成整数随机数方法示例golang编程实现生成n个从a到b不重复随机数的方法go语言返回1-99之间随机数的方法go语言生成随机数的方法go 字符串格式化的实例代码详解mac下golang安装了windows编译环境后编译变慢go语言waitgroup使用时需要注意的坑go 并发实现协程同步的多种解决方法go语言中使用timer的常用方式go语言make()分配用法实例golang中数据结构queue的实现方法详解go语言telnet回音服务器的实现go时间/时间戳操作大全(小结)go实现整型的二进制转化的方法go语言中的array、slice、map和sgo语言的gopath与工作目录详解go语言string,int,int64 ,floago语言interface详解五步让你成为go 语言高手go语言命令行操作命令详细介绍go语言编程中字符串切割方法小结我放弃python转go语言的9大理由(go语言创建、初始化数组的常见方go语言数组和切片实例详解使用golang获取linux上文件的访问/创建/修go语言服务器开发之简易tcp客户端与服务端golang中defer的使用规则详解go语言的sql包原理与用法分析golang json性能分析详解golang复用http.request.body的方法示例go语言同步教程之条件变量go语言学习技巧之如何合理使用poolgolang的httpserver优雅重启方法详解使用golang写一个redis-cli的方法示例
    免责声明 - 关于我们 - 联系我们 - 广告联系 - 友情链接 - 帮助中心 - 频道导航
    Copyright © 2017 www.zgxue.com All Rights Reserved