Random 如何使用标准库在Go中生成*唯一*随机数
问题:如何在Go中生成唯一的随机数流 也就是说,我想使用Random 如何使用标准库在Go中生成*唯一*随机数,random,go,Random,Go,问题:如何在Go中生成唯一的随机数流 也就是说,我想使用math/rand和/或标准Go库实用程序保证数组a中没有重复 func RandomNumberGenerator() *rand.Rand { s1 := rand.NewSource(time.Now().UnixNano()) r1 := rand.New(s1) return r1 } rng := RandomNumberGenerator() N := 10000 for i
math/rand
和/或标准Go库实用程序保证数组a
中没有重复
func RandomNumberGenerator() *rand.Rand {
s1 := rand.NewSource(time.Now().UnixNano())
r1 := rand.New(s1)
return r1
}
rng := RandomNumberGenerator()
N := 10000
for i := 0; i < N; i++ {
a[i] = rng.Int()
}
func RandomNumberGenerator()*rand.rand{
s1:=rand.NewSource(time.Now().UnixNano())
r1:=新兰特(s1)
返回r1
}
rng:=RandomNumberGenerator()
N:=10000
对于i:=0;i
例如,关于如何在Go中生成一系列随机数,存在一些问题和解决方案 但现在我想生成一系列随机数,这些随机数不会与前面的值重复。在围棋中有没有标准/推荐的方法 我的猜测是(1)使用置换或(2)跟踪以前生成的数字,如果以前生成过,则重新生成一个值 但解决方案(1)如果我只想要几个数字,听起来像是一个杀伤力过大的解决方案(2)如果我因为碰撞而生成了一长串随机数,听起来非常耗时,我想这也非常消耗内存
用例:用10K、100K、1M无重复的伪随机数对Go程序进行基准测试。您绝对应该使用方法2。假设您在64位机器上运行,因此生成63位整数(64位,但
rand.Int
从不返回负数)。即使你生成了40亿个数字,任何给定数字复制的可能性仍然只有40亿分之一。因此,你几乎不需要再生,也几乎不需要再生两次
试试看,例如:
type UniqueRand struct {
generated map[int]bool
}
func (u *UniqueRand) Int() int {
for {
i := rand.Int()
if !u.generated[i] {
u.generated[i] = true
return i
}
}
}
1-:
2-只需填写
映射[int32]结构{}
:
for i := int32(0); i < n; i++ {
m[i] = zero
}
对于1000000个唯一的数字,这只需要183ms,没有重复():
主程序包
进口(
“fmt”
“时间”
)
func main(){
常数n=1000000
m:=make(映射[int32]结构{},n)
t:=时间。现在()
对于i:=int32(0);i
3-这是一个简单但缓慢的过程(200000个唯一数字需要22秒),因此您可以生成并将其保存到一个文件中一次:
package main
import "time"
import "fmt"
import "math/rand"
func main() {
dup := 0
t := time.Now()
const n = 200000
rand.Seed(time.Now().UTC().UnixNano())
var a [n]int32
var exist bool
for i := 0; i < n; {
r := rand.Int31()
exist = false
for j := 0; j < i; j++ {
if a[j] == r {
dup++
fmt.Println(dup)
exist = true
break
}
}
if !exist {
a[i] = r
i++
}
}
fmt.Println(time.Since(t))
}
主程序包
导入“时间”
输入“fmt”
导入“数学/兰德”
func main(){
dup:=0
t:=时间。现在()
常数n=200000
rand.Seed(time.Now().UTC().UnixNano())
变量a[n]int32
变量存在布尔
对于i:=0;i
基于@joshlf答案的临时解决方案
type UniqueRand struct {
generated map[int]bool //keeps track of
rng *rand.Rand //underlying random number generator
scope int //scope of number to be generated
}
//Generating unique rand less than N
//If N is less or equal to 0, the scope will be unlimited
//If N is greater than 0, it will generate (-scope, +scope)
//If no more unique number can be generated, it will return -1 forwards
func NewUniqueRand(N int) *UniqueRand{
s1 := rand.NewSource(time.Now().UnixNano())
r1 := rand.New(s1)
return &UniqueRand{
generated: map[int]bool{},
rng: r1,
scope: N,
}
}
func (u *UniqueRand) Int() int {
if u.scope > 0 && len(u.generated) >= u.scope {
return -1
}
for {
var i int
if u.scope > 0 {
i = u.rng.Int() % u.scope
}else{
i = u.rng.Int()
}
if !u.generated[i] {
u.generated[i] = true
return i
}
}
}
客户端代码
func TestSetGet2(t *testing.T) {
const N = 10000
for _, mask := range []int{0, -1, 0x555555, 0xaaaaaa, 0x333333, 0xcccccc, 0x314159} {
rng := NewUniqueRand(2*N)
a := make([]int, N)
for i := 0; i < N; i++ {
a[i] = (rng.Int() ^ mask) << 1
}
//Benchmark Code
}
}
func TestSetGet2(t*testing.t){
常数N=10000
对于33;,掩码:=范围[]int{0,-1,0x555555,0xAAAAA,0x333333,0xCCCC,0x314159}{
rng:=NewUniqueRand(2*N)
a:=make([]整数,N)
对于i:=0;i a[i]=(rng.Int()^mask)我认为有两个原因需要这样做。您想要测试随机数生成器,或者想要唯一的随机数
你在测试一个随机数发生器
我的第一个问题是为什么?有很多可靠的随机数生成器可用。不要自己写,它基本上只是涉猎密码学,这从来不是一个好主意。也许你正在测试一个使用随机数生成器生成随机输出的系统
有一个问题:无法保证随机数是唯一的。它们是随机的。总是有冲突的可能性。测试随机输出是唯一的是不正确的
相反,您要测试的结果是均匀分布的
你想要唯一的随机数
从实际的角度来看,您不需要保证唯一性,但要使冲突不太可能发生,这不是一个问题。这就是原因。它们是128位通用唯一标识符。有许多方法可以为特定场景生成它们
UUIDv4基本上只是一个122位的随机数,它发生冲突的可能性非常小
解决n
n = sqrt(2MP)
将p设为1e-12(万亿分之一)之类的荒谬值,我们发现可以生成约3.2万亿个UUIDV4,碰撞概率为万亿分之一。您中彩票的概率是3.2万亿个UUIDV4碰撞概率的1000倍。我认为这是可以接受的
下面是生成100万个唯一随机128位值的示例
package main
import (
"fmt"
"github.com/frankenbeanies/uuid4"
)
func main() {
for i := 0; i <= 1000000; i++ {
uuid := uuid4.New().Bytes()
// use the uuid
}
}
主程序包
进口(
“fmt”
“github.com/frankenbeanies/uuid4”
)
func main(){
对于i:=0;i我正在电话上键入此内容,因此请原谅代码缺失或格式错误
我会这样做:
生成有序唯一编号的列表
选择任意两个随机索引并交换其元素
继续交换一定数量的迭代
剩下的部分是您的随机唯一列表
注:
它很简单,内存使用与大小成正比
该列表可以随时生成和随机化,甚至可以使用go generate进行预编译
当你想要一个数字时,你会得到列表中的下一个元素
您可以完全控制它的属性。我有类似的任务,通过随机uniq索引从初始切片中拾取元素。因此,从包含10k元素的切片中可以得到1k个随机uniq元素
以下是简单的正面解决方案:
import (
"time"
"math/rand"
)
func getRandomElements(array []string) []string {
result := make([]string, 0)
existingIndexes := make(map[int]struct{}, 0)
randomElementsCount := 1000
for i := 0; i < randomElementsCount; i++ {
randomIndex := randomIndex(len(array), existingIndexes)
result = append(result, array[randomIndex])
}
return result
}
func randomIndex(size int, existingIndexes map[int]struct{}) int {
rand.Seed(time.Now().UnixNano())
for {
randomIndex := rand.Intn(size)
_, exists := existingIndexes[randomIndex]
if !exists {
existingIndexes[randomIndex] = struct{}{}
return randomIndex
}
}
}
导入(
“时间”
“数学/兰德”
)
func getRandomElements(数组[]字符串)[]字符串{
结果:
func TestSetGet2(t *testing.T) {
const N = 10000
for _, mask := range []int{0, -1, 0x555555, 0xaaaaaa, 0x333333, 0xcccccc, 0x314159} {
rng := NewUniqueRand(2*N)
a := make([]int, N)
for i := 0; i < N; i++ {
a[i] = (rng.Int() ^ mask) << 1
}
//Benchmark Code
}
}
n = how many random numbers you'll generate
M = size of the keyspace (2^122 for a 122 bit random number)
P = probability of collision
P = n^2/2M
n = sqrt(2MP)
package main
import (
"fmt"
"github.com/frankenbeanies/uuid4"
)
func main() {
for i := 0; i <= 1000000; i++ {
uuid := uuid4.New().Bytes()
// use the uuid
}
}
import (
"time"
"math/rand"
)
func getRandomElements(array []string) []string {
result := make([]string, 0)
existingIndexes := make(map[int]struct{}, 0)
randomElementsCount := 1000
for i := 0; i < randomElementsCount; i++ {
randomIndex := randomIndex(len(array), existingIndexes)
result = append(result, array[randomIndex])
}
return result
}
func randomIndex(size int, existingIndexes map[int]struct{}) int {
rand.Seed(time.Now().UnixNano())
for {
randomIndex := rand.Intn(size)
_, exists := existingIndexes[randomIndex]
if !exists {
existingIndexes[randomIndex] = struct{}{}
return randomIndex
}
}
}
uniqueNumber:=time.Now().UnixNano()/(1<<22)
println(uniqueNumber)