英文:
Golang Strange random problems
问题
几年前,我写了一个简单的“模块”(https://github.com/parasit/rpgforge),用于模拟掷骰子并将可读的骰子投掷定义转换为循环投掷。比如,“3d6”表示投掷六面骰子三次,等等。
我在我的工具中使用它来支持我的爱好(纸笔角色扮演游戏)。代码很简单,但非常有用,以至于在过去的4年里我几乎没有碰过它。然而最近我需要另一个工具,导入了我的库后发现结果非常奇怪。似乎存在随机性,但结果返回的是一系列相同的数字。我不知道发生了什么,而且自上次以来唯一改变的是golang从1.18升级到1.19。
附注:1.19是在win11上,1.18是在第二台装有ubuntu的机器上。
示例代码:
package main
import (
"fmt"
"math/rand"
"time"
forge "github.com/parasit/rpgforge"
)
func main() {
rand.Seed(time.Now().UTC().UnixNano())
for x := 0; x < 10; x++ {
fmt.Println(forge.ThrowDices("10d10"))
}
}
预期结果(在旧的1.18版本上):
❯ go run ./main.go
{[6 6 2 6 7 7 10 3 4 3] 0}
{[1 7 7 8 6 1 3 3 6 3] 0}
{[7 4 5 1 3 9 6 7 1 1] 0}
{[1 1 7 2 10 4 5 6 10 7] 0}
{[2 10 10 1 10 3 9 10 3 6] 0}
{[2 8 1 3 1 3 5 4 6 2] 0}
{[3 9 4 5 9 2 4 7 6 6] 0}
{[3 5 7 1 6 4 8 10 9 2] 0}
{[3 6 4 8 1 7 8 10 4 1] 0}
{[2 9 2 8 9 8 5 6 7 2] 0}
但在1.19版本上,我得到了类似这样的结果:
{[1 1 1 1 1 1 1 1 1 1] 0}
{[1 1 1 1 1 1 1 1 1 1] 0}
{[1 1 1 1 1 1 1 1 1 1] 0}
{[1 1 1 1 1 1 1 1 1 1] 0}
{[8 8 8 8 8 8 8 8 8 8] 0}
{[8 8 8 8 8 8 8 8 8 8] 0}
{[8 8 8 8 8 8 8 8 8 8] 0}
{[8 8 8 8 8 8 8 8 8 8] 0}
{[8 8 8 8 8 8 8 8 8 3] 0}
{[3 3 3 3 3 3 3 3 3 3] 0}
1.19发生了什么?
编辑:
Mike是对的,从所有投掷中删除“初始化”可以解决问题。但需要在代码开头手动添加它。
英文:
A few years ago I wrote a simple "module" (https://github.com/parasit/rpgforge) to simulate dice rolls and "translate" human readable dice throw definiton to throws loops. Like "3d6" as 3 times roll six sides dice, etc.
I used it in my tools to support my hobby (pen & paper RPG). The code is simple, but so useful that I haven't really touched it for the last 4 years. However recently I needed another tool, imported my library and found the results very strange. Randomness seems to occur, but the results are returned as series of the same digits. I have no idea what's going on, and the only thing that has changed since the last time is golang from 1.18 to 1.19.
P.S. 1.19 is on win11, 1.18 is on second machine with ubuntu
Sample code:
package main
import (
"fmt"
"math/rand"
"time"
forge "github.com/parasit/rpgforge"
)
func main() {
rand.Seed(time.Now().UTC().UnixNano())
for x := 0; x < 10; x++ {
fmt.Println(forge.ThrowDices("10d10"))
}
}
Expected result (on old 1.18):
❯ go run ./main.go
{[6 6 2 6 7 7 10 3 4 3] 0}
{[1 7 7 8 6 1 3 3 6 3] 0}
{[7 4 5 1 3 9 6 7 1 1] 0}
{[1 1 7 2 10 4 5 6 10 7] 0}
{[2 10 10 1 10 3 9 10 3 6] 0}
{[2 8 1 3 1 3 5 4 6 2] 0}
{[3 9 4 5 9 2 4 7 6 6] 0}
{[3 5 7 1 6 4 8 10 9 2] 0}
{[3 6 4 8 1 7 8 10 4 1] 0}
{[2 9 2 8 9 8 5 6 7 2] 0}
But on 1.19 i got something like this:
{[1 1 1 1 1 1 1 1 1 1] 0}
{[1 1 1 1 1 1 1 1 1 1] 0}
{[1 1 1 1 1 1 1 1 1 1] 0}
{[1 1 1 1 1 1 1 1 1 1] 0}
{[8 8 8 8 8 8 8 8 8 8] 0}
{[8 8 8 8 8 8 8 8 8 8] 0}
{[8 8 8 8 8 8 8 8 8 8] 0}
{[8 8 8 8 8 8 8 8 8 8] 0}
{[8 8 8 8 8 8 8 8 8 3] 0}
{[3 3 3 3 3 3 3 3 3 3] 0}
What happened in 1.19 ???
EDIT:
Mike had right, removing "initialize" from all rolls solve the problem. But requires add it "manually" to beginning of code.
答案1
得分: 2
你似乎不需要过高的速度,所以我建议使用一个加密安全的随机数生成器来规避这个问题。crypto/rand库使用系统的随机数生成器,其种子熵比仅使用日期更好。
更好的随机性和较低的速度似乎是一个非常合理的权衡。
英文:
You don't seem to need excessive speed, so I'd sidestep the issue by using a cryptographically secure random number generator. The crypto/rand library uses the systems' random number generator, which is seeded by a lot better entropy than just a date.
Better randoms, less speed seems like a very reasonable tradeoff.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论