यादृच्छिक संख्या जनरेटर को ठीक से बीज कैसे करें


160

मैं गो में एक यादृच्छिक स्ट्रिंग उत्पन्न करने की कोशिश कर रहा हूं और यहां वह कोड है जो मैंने अब तक लिखा है:

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एक निश्चित समय के लिए एक ही यादृच्छिक संख्या लाता है, इसलिए लूप बार-बार पुनरावृत्त होता है। मैं अपना कोड कैसे सुधार सकता हूं?


2
"यदि स्ट्रिंग (रैंडआईंट (65,90))! = अस्थायी {" ऐसा लगता है कि आप अतिरिक्त सुरक्षा जोड़ने की कोशिश कर रहे हैं, लेकिन हे, चीजें एक के बाद एक मौका पाती हैं। ऐसा करने से आप वास्तव में एन्ट्रापी को कम कर सकते हैं।
याकूब

3
साइड नोट के रूप में, UTC को "time.Now ()। UTC () (UnixNano ()" में परिवर्तित करने की आवश्यकता नहीं है। यूनिक्स समय की गणना युग के बाद से की जाती है, जो वैसे भी यूटीसी है।
ग्रेजेर्गज़ लुसीवो

2
आपको एक बार बीज सेट करना चाहिए, केवल एक बार, और एक बार से अधिक कभी नहीं। ठीक है, यदि आपका आवेदन दिनों के लिए चलता है तो आप इसे दिन में एक बार सेट कर सकते हैं।
कैस्पर

आपको एक बार बीज देना चाहिए। और मुझे लगता है कि "Z" कभी प्रकट नहीं हो सकता है, मुझे लगता है? इसलिए मैं आरंभिक समावेशी और अंत सूचकांक अनन्य का उपयोग करना पसंद करता हूं।
जेहुँ येओम

जवाबों:


232

हर बार जब आप एक ही बीज सेट करते हैं, तो आपको एक ही क्रम मिलता है। तो बेशक अगर आप बीज को एक तेज लूप में समय पर सेट कर रहे हैं, तो आप शायद इसे एक ही बीज के साथ कई बार कहेंगे।

आपके मामले में, जैसा कि आप अपने randIntफ़ंक्शन को कॉल कर रहे हैं जब तक कि आपके पास एक अलग मूल्य नहीं है, तब तक आप समय (नैनो द्वारा लौटाए गए) को बदलने के लिए इंतजार कर रहे हैं।

सभी छद्म यादृच्छिक पुस्तकालयों के लिए , आपको केवल एक बार बीज सेट करना होगा, उदाहरण के लिए जब आप अपने प्रोग्राम को प्रारंभ करते हैं जब तक कि आपको विशेष रूप से किसी दिए गए अनुक्रम को पुन: पेश करने की आवश्यकता न हो (जो आमतौर पर केवल डिबगिंग और यूनिट परीक्षण के लिए किया जाता है)।

उसके बाद आप बस Intnअगले यादृच्छिक पूर्णांक प्राप्त करने के लिए कॉल करते हैं।

rand.Seed(time.Now().UTC().UnixNano())रैंडआई फ़ंक्शन से लाइन को मुख्य की शुरुआत तक ले जाएं और सब कुछ तेज हो जाएगा।

ध्यान दें कि मुझे लगता है कि आप अपनी स्ट्रिंग बिल्डिंग को सरल बना सकते हैं:

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)
}

यह समझाने के लिए धन्यवाद, मैंने सोचा कि इसे हर बार वरीयता देने की आवश्यकता है।
ताम्र

13
आप rand.Seed(...)फ़ंक्शन में भी जोड़ सकते हैं init()init()पहले स्वचालित रूप से कहा जाता है main()। ध्यान दें कि आपको कॉल करने की आवश्यकता नहीं init()है main()!
Jabba

2
@ जब्बा सही। मैं अपने उत्तर को यथासंभव सरल और प्रश्न से बहुत दूर रख रहा था, लेकिन आपका अवलोकन सही है।
डेनसिटी सेग्रुट

7
कृपया ध्यान दें कि अब तक पोस्ट किए गए किसी भी एवर ने क्रिप्टोग्राफिक रूप से सुरक्षित तरीके से बीज को इनिशियलाइज़ नहीं किया है। आपके आवेदन के आधार पर, यह बिल्कुल भी मायने नहीं रखता है या इसके परिणामस्वरूप भयावह विफलता हो सकती है।
इंगो ब्लेस्च्मिड्ट

3
@IngoBlechschmidt math/randवैसे भी क्रिप्टोग्राफिक रूप से सुरक्षित नहीं है। यदि वह आवश्यकता है, crypto/randतो इसका उपयोग किया जाना चाहिए।
डंकन जोन्स

39

मुझे समझ में नहीं आता कि लोग समय के मूल्य के साथ क्यों बो रहे हैं। यह मेरे अनुभव में कभी भी अच्छा विचार नहीं रहा है। उदाहरण के लिए, जबकि सिस्टम घड़ी को शायद नैनोसेकंड में दर्शाया गया है, सिस्टम की घड़ी की सटीकता नैनोसेकंड नहीं है।

इस कार्यक्रम को गो खेल के मैदान पर नहीं चलाया जाना चाहिए लेकिन अगर आप इसे अपनी मशीन पर चलाते हैं तो आपको इस बात का अंदाजा हो जाता है कि आप किस प्रकार की सटीकता की उम्मीद कर सकते हैं। मुझे लगभग 1000000 एनएस की वेतन वृद्धि दिखाई देती है, इसलिए 1 एमएस वेतन वृद्धि। यह एंट्रॉपी के 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और इसका उपयोग गैर-समवर्ती तरीके से कर सकते हैं। भले ही, आपको पुनरावृत्तियों के बीच अपने यादृच्छिक संख्या जनरेटर को फिर से स्थापित नहीं करना चाहिए, यह कभी भी उस तरह से उपयोग करने के लिए डिज़ाइन नहीं किया गया था।


5
यह जवाब बहुत ही कम है। विशेष रूप से कमांड लाइन टूल के लिए जो एक सेकंड में कई बार चल सकता है, यह एक करना होगा। धन्यवाद
saeedgnu

1
यदि आवश्यक हो तो आप पीआईडी ​​और होस्टनाम / मैक में मिश्रण कर सकते हैं, लेकिन सावधान रहें कि क्रिप्टोग्राफिक रूप से सुरक्षित स्रोत के साथ आरएनजी को सीडिंग करें यह क्रिप्टोग्राफिक रूप से सुरक्षित नहीं है क्योंकि कोई व्यक्ति पीआरएनजी आंतरिक स्थिति को फिर से बना सकता है।
निक टी

पीआईडी ​​वास्तव में यादृच्छिक नहीं हैं। एमएसीएस क्लोन किया जा सकता है। आप उन्हें किस तरह से मिलाएंगे जो अवांछित तिरछा / पूर्वाग्रह का परिचय नहीं देता है।
जॉन लेदरग्रेन

16

पोस्टरिटी के लिए इसे टॉस करें: प्रारंभिक चरित्र सेट स्ट्रिंग का उपयोग करके कभी-कभी यादृच्छिक स्ट्रिंग उत्पन्न करना बेहतर हो सकता है। यह उपयोगी है यदि स्ट्रिंग को मानव द्वारा मैन्युअल रूप से दर्ज किया जाना है; 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)
}

और मैं आमतौर पर एक init()ब्लॉक के अंदर बीज सेट करता हूं । वे यहाँ प्रलेखित हैं: http://golang.org/doc/effective_go.html#init


9
जहां तक ​​मैं सही ढंग से समझता हूं, अंदर जाने की कोई जरूरत नहीं -1है rand.Intn(len(alpha)-1)। ऐसा इसलिए है क्योंकि rand.Intn(n)हमेशा एक संख्या देता है जो n(दूसरे शब्दों में: शून्य से n-1समावेशी तक) से कम है।
17

2
@snap सही है; वास्तव में, सहित -1में len(alpha)-1गारंटी है कि नंबर 9 अनुक्रम में कभी इस्तेमाल नहीं हुआ होगा।
कार्बोनेशन

2
यह भी ध्यान दिया जाना चाहिए कि 0 (शून्य) को छोड़कर एक अच्छा विचार है क्योंकि आप एक स्ट्रिंग को बाइट स्लाइस कास्टिंग कर रहे हैं, और यह 0 को एक शून्य बाइट बनने का कारण बनता है। जैसे, '0' बाइट के साथ बीच में एक फाइल बनाने की कोशिश करें और देखें कि क्या होता है।
एरिक लैगरग्रेन ने

14

ठीक है क्यों इतना जटिल!

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())
}

यह dystroy कोड बंद है, लेकिन मेरी जरूरतों के लिए फिट है।

यह छह मर गया (रैंड इन्ट्स 1 =< i =< 6)

func randomInt (min int , max int  ) int {
    var bytes int
    bytes = min + rand.Intn(max)
    return int(bytes)
}

ऊपर का कार्य बिल्कुल वही है।

मुझे उम्मीद है कि यह जानकारी उपयोग की थी।


यह एक ही क्रम में हर समय लौटेगा, एक ही क्रम में अगर कई बार कहा जाता है, तो यह मेरे लिए बहुत यादृच्छिक नहीं लगता है। लाइव उदाहरण की जाँच करें: play.golang.org/p/fHHENtaPv5 3 5 2 5 4 2 5 6 3 1
थॉमस मॉडेनिस

8
@ThomasModeneis: ऐसा इसलिए है क्योंकि वे खेल के मैदान में नकली हैं
इवारे का

1
धन्यवाद @ofavre, कि नकली समय वास्तव में मुझे पहली बार में फेंक दिया।
जेसी चिशोल्म

1
आपको कॉल करने से पहले अभी भी बीज बोने की आवश्यकता है rand.Intn(), अन्यथा आप अपना कार्यक्रम चलाने के बाद कभी भी एक ही नंबर प्राप्त करेंगे।
फ्लेवियो कॉप्स

का कोई कारण var bytes int? उपरोक्त bytes = rand.Intn(6)+1को बदलने के लिए क्या अंतर है bytes := rand.Intn(6)+1? वे दोनों मेरे लिए काम करने लगते हैं, क्या उनमें से किसी कारण के लिए उप-इष्टतम है?
pzkpfw

0

यह नैनो सेकंड है, एक ही बीज को दो बार प्राप्त करने की संभावना क्या है।
वैसे भी, मदद के लिए धन्यवाद, यहाँ सभी इनपुट के आधार पर मेरा अंत समाधान है।

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))
}

1
पुन: what are the chances of getting the exact the exact same [nanosecond] twice?बहुत बढ़िया। यह सब गोलंग रनटाइम्स के कार्यान्वयन की आंतरिक शुद्धता पर निर्भर करता है । भले ही इकाइयां नैनो-सेकंड हैं, लेकिन सबसे छोटा वेतन वृद्धि एक-सेकंड या एक सेकंड भी हो सकती है।
जेसी चिशोल्म

0

यदि आपका उद्देश्य सिर्फ रैंडम नंबर का स्टिंग जनरेट करना है तो मुझे लगता है कि इसे हर बार कई फंक्शन कॉल्स या रीसेटिंग सीड के साथ जटिल करना अनावश्यक है।

सबसे महत्वपूर्ण कदम वास्तव में चलने से पहले एक बार बीज फ़ंक्शन को कॉल करना है rand.Init(x)बीज डिफ़ॉल्ट स्रोत को निर्धारित करने के लिए निर्धारित बीज मूल्य का उपयोग करता है एक निर्धारक राज्य में। इसलिए, छद्म यादृच्छिक संख्या जनरेटर को वास्तविक फ़ंक्शन कॉल करने से पहले इसे एक बार कॉल करने का सुझाव दिया जाएगा।

यहाँ एक नमूना कोड है जो यादृच्छिक संख्याओं की एक स्ट्रिंग बनाता है

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)
}

स्प्रिंटफ का उपयोग करने का कारण यह है कि यह सरल स्ट्रिंग प्रारूपण की अनुमति देता है।

इसके अलावा, rand.Intn(7) इन्ट रिटर्न में, एक इंट, एक गैर-नकारात्मक छद्म यादृच्छिक संख्या [0,7] में है।


0

@ [डेनिस सेगुरेट] ने सही पोस्ट किया है। लेकिन मेरे मामले में मुझे हर बार कोड के नीचे नए बीज की आवश्यकता होती है;

आप त्वरित कार्यों की जरूरत है। मैं इस तरह का उपयोग करता हूं।


func RandInt(min, max int) int {
    r := rand.New(rand.NewSource(time.Now().UnixNano()))
    return r.Intn(max-min) + min
}

func RandFloat(min, max float64) float64 {
    r := rand.New(rand.NewSource(time.Now().UnixNano()))
    return min + r.Float64()*(max-min)
}

स्रोत


-2

गोलंग आपी परिवर्तन के कारण छोटा अद्यतन, कृपया .UTC () छोड़ें:

अब समय()। UTC () .UnixNano () -> समय।अब ()। 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)
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.