골란 난수 생성기
Go에서 임의의 문자열을 생성하려고하는데 여기에 내가 작성한 코드가 있습니다.
package main
import (
"bytes"
"fmt"
"math/rand"
"time"
)
func main() {
fmt.Println(randomString(10))
}
func randomString(l int) string {
var result bytes.Buffer
var temp string
for i := 0; i < l; {
if string(randInt(65, 90)) != temp {
temp = string(randInt(65, 90))
result.WriteString(temp)
i++
}
}
return result.String()
}
func randInt(min int, max int) int {
rand.Seed(time.Now().UTC().UnixNano())
return min + rand.Intn(max-min)
}
구현이 매우 느립니다. 시드를 사용 time하면 특정 시간 동안 동일한 난수가 발생하므로 루프가 계속 반복됩니다. 코드를 어떻게 개선 할 수 있습니까?
동일한 시드를 설정할 때마다 동일한 시퀀스를 얻습니다. 물론 빠른 루프에서 시드를 시간으로 설정하는 경우 동일한 시드로 여러 번 호출 할 수 있습니다.
귀하의 경우, randInt다른 값을 가질 때까지 함수를 호출 할 때 (Nano에서 반환 한) 시간이 변경되기를 기다리고 있습니다.
모든 의사 랜덤 라이브러리의 경우 , 주어진 시퀀스 (일반적으로 디버깅 및 단위 테스트 용으로 만 수행됨)를 구체적으로 재현해야하는 경우를 제외하고 프로그램을 초기화 할 때와 같이 시드를 한 번만 설정해야합니다.
그런 다음 단순히 Intn다음 임의의 정수를 얻기 위해 호출 합니다.
rand.Seed(time.Now().UTC().UnixNano())randInt 함수에서 메인의 시작 부분으로 라인을 이동하면 모든 것이 더 빨라집니다.
또한 문자열 작성을 단순화 할 수 있다고 생각합니다.
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
rand.Seed(time.Now().UTC().UnixNano())
fmt.Println(randomString(10))
}
func randomString(l int) string {
bytes := make([]byte, l)
for i := 0; i < l; i++ {
bytes[i] = byte(randInt(65, 90))
}
return string(bytes)
}
func randInt(min int, max int) int {
return min + rand.Intn(max-min)
}
사람들이 왜 시간 가치를 부여하는 지 이해할 수 없습니다. 이것은 내 경험상 결코 좋은 생각이 아닙니다. 예를 들어, 시스템 클럭이 나노초로 표시 될 수 있지만 시스템의 클럭 정밀도는 나노초가 아닙니다.
이 프로그램 은 Go 놀이터에서 실행해서는 안되지만 컴퓨터에서 실행하면 예상 할 수있는 정밀도 유형에 대한 대략적인 추정치를 얻을 수 있습니다. 약 1000000ns 씩 증가하므로 1ms 씩 증가합니다. 그것은 사용되지 않는 20 비트의 엔트로피입니다. 높은 비트는 항상 일정합니다.
이것이 당신에게 중요한 정도는 다를 것이지만, 단순히 crypto/rand.Read씨앗의 소스로 사용함으로써 시계 기반의 씨앗 값의 함정을 피할 수 있습니다 . 실제 구현 자체가 고유하고 결정 론적 무작위 시퀀스로 제한되어 있어도 난수에서 찾고있는 비 결정적 품질을 제공합니다.
import (
crypto_rand "crypto/rand"
"encoding/binary"
math_rand "math/rand"
)
func init() {
var b [8]byte
_, err := crypto_rand.Read(b[:])
if err != nil {
panic("cannot seed math/rand package with cryptographically secure random number generator")
}
math_rand.Seed(int64(binary.LittleEndian.Uint64(b[:])))
}
부수적으로하지만 귀하의 질문과 관련하여. rand.Source소스를 보호하는 잠금 비용이 들지 않도록이 방법을 사용 하여 직접 작성할 수 있습니다 . rand패키지 유틸리티 기능은 편리하지만 또한 동시에 사용되는 소스를 방지하기 위해 후드 잠금을 사용합니다. 필요하지 않은 경우 직접 작성하여 피할 수 Source있으며 비 동시 방식으로 사용하십시오. 그럼에도 불구하고 반복 사이에 난수 생성기를 다시 시드해서는 안되며 절대 그런 식으로 사용되도록 설계되지 않았습니다.
후손을 위해 그것을 던지기 위해 : 때로는 초기 문자 세트 문자열을 사용하여 임의의 문자열을 생성하는 것이 바람직 할 수 있습니다. 사람이 직접 문자열을 입력해야하는 경우에 유용합니다. 0, O, 1 및 l을 제외하면 사용자 오류를 줄일 수 있습니다.
var alpha = "abcdefghijkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789"
// generates a random string of fixed size
func srand(size int) string {
buf := make([]byte, size)
for i := 0; i < size; i++ {
buf[i] = alpha[rand.Intn(len(alpha))]
}
return string(buf)
}
and I typically set the seed inside of an init() block. They're documented here: http://golang.org/doc/effective_go.html#init
OK why so complex!
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
rand.Seed( time.Now().UnixNano())
var bytes int
for i:= 0 ; i < 10 ; i++{
bytes = rand.Intn(6)+1
fmt.Println(bytes)
}
//fmt.Println(time.Now().UnixNano())
}
This is based off the dystroy's code but fitted for my needs.
It's die six (rands ints 1 =< i =< 6)
func randomInt (min int , max int ) int {
var bytes int
bytes = min + rand.Intn(max)
return int(bytes)
}
The function above is the exactly same thing.
I hope this information was of use.
It's nano seconds, what are the chances of getting the same seed twice.
Anyway, thanks for the help, here is my end solution based on all the input.
package main
import (
"math/rand"
"time"
)
func init() {
rand.Seed(time.Now().UTC().UnixNano())
}
// generates a random string
func srand(min, max int, readable bool) string {
var length int
var char string
if min < max {
length = min + rand.Intn(max-min)
} else {
length = min
}
if readable == false {
char = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
} else {
char = "ABCDEFHJLMNQRTUVWXYZabcefghijkmnopqrtuvwxyz23479"
}
buf := make([]byte, length)
for i := 0; i < length; i++ {
buf[i] = char[rand.Intn(len(char)-1)]
}
return string(buf)
}
// For testing only
func main() {
println(srand(5, 5, true))
println(srand(5, 5, true))
println(srand(5, 5, true))
println(srand(5, 5, false))
println(srand(5, 7, true))
println(srand(5, 10, false))
println(srand(5, 50, true))
println(srand(5, 10, false))
println(srand(5, 50, true))
println(srand(5, 10, false))
println(srand(5, 50, true))
println(srand(5, 10, false))
println(srand(5, 50, true))
println(srand(5, 4, true))
println(srand(5, 400, true))
println(srand(6, 5, true))
println(srand(6, 5, true))
println(srand(6, 5, true))
println(srand(6, 5, true))
println(srand(6, 5, true))
println(srand(6, 5, true))
println(srand(6, 5, true))
println(srand(6, 5, true))
println(srand(6, 5, true))
println(srand(6, 5, true))
println(srand(6, 5, true))
println(srand(6, 5, true))
}
If your aim is just to generate a sting of random number then I think it's unnecessary to complicate it with multiple function calls or resetting seed every time.
The most important step is to call seed function just once before actually running rand.Init(x). Seed uses the provided seed value to initialize the default Source to a deterministic state. So, It would be suggested to call it once before the actual function call to pseudo-random number generator.
Here is a sample code creating a string of random numbers
package main
import (
"fmt"
"math/rand"
"time"
)
func main(){
rand.Seed(time.Now().UnixNano())
var s string
for i:=0;i<10;i++{
s+=fmt.Sprintf("%d ",rand.Intn(7))
}
fmt.Printf(s)
}
The reason I used Sprintf is because it allows simple string formatting.
Also, In rand.Intn(7) Intn returns, as an int, a non-negative pseudo-random number in [0,7).
Small update due to golang api change, please omit .UTC() :
time.Now().UTC().UnixNano() -> time.Now().UnixNano()
import (
"fmt"
"math/rand"
"time"
)
func main() {
rand.Seed(time.Now().UnixNano())
fmt.Println(randomInt(100, 1000))
}
func randInt(min int, max int) int {
return min + rand.Intn(max-min)
}
참고URL : https://stackoverflow.com/questions/12321133/golang-random-number-generator-how-to-seed-properly
'Programming' 카테고리의 다른 글
| bash : n 번째 출력 열을 얻는 가장 짧은 방법 (0) | 2020.06.18 |
|---|---|
| HTML5 캔버스 요소에 텍스트를 작성하려면 어떻게해야합니까? (0) | 2020.06.18 |
| 중첩 된 JSON 객체를 평면화 / 비편 성화하는 가장 빠른 방법 (0) | 2020.06.18 |
| Emacs에서 여러 쉘을 실행하는 방법 (0) | 2020.06.18 |
| Django Admin에서 동일한 모델에 대한 여러 ModelAdmins / views (0) | 2020.06.18 |