কিভাবে এলোমেলো নম্বর জেনারেটর সঠিকভাবে বীজ


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))! = টেম্পের looks" দেখে মনে হচ্ছে আপনি অতিরিক্ত সুরক্ষা যোগ করার চেষ্টা করছেন তবে আরে, সুযোগগুলি একের পর এক জিনিস পেয়ে যায়। এটি করে আপনি প্রকৃতপক্ষে এনট্রপি কমিয়ে আনতে পারেন।
ইয়্যাকজ

2
পার্শ্ব নোট হিসাবে, "সময়.নাউ ()। ইউটিসি ()। ইউনিক্সনানো ()" তে ইউটিসি তে রূপান্তর করার দরকার নেই। ইউনিক্স সময় গণনা করা হয় Epoch থেকে যা কোনওভাবেই ইউটিসি।
গ্রজেগোর্স লুসজিও

2
আপনার একবারে, একবারে বীজ সেট করা উচিত এবং একবারের বেশি কখনও হবে না। ভাল, যদি আপনার অ্যাপ্লিকেশনটি দিনের জন্য চালিত হয় তবে আপনি দিনে একবার এটি সেট করতে পারেন।
ক্যাস্পেরাহ

আপনার একবার বীজ করা উচিত এবং আমার মনে হয় "জেড" কখনই হাজির হতে পারে না, আমার ধারণা? তাই আমি শুরু সূচকটি অন্তর্ভুক্তি এবং শেষ সূচকটি একচেটিয়া ব্যবহার করতে পছন্দ করি।
জাহেয়ুন ইওম

উত্তর:


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()!
জাববা

2
@ যাবা ঠিক আছে। আমি আমার উত্তরটি যথাসম্ভব সহজ করে রাখছিলাম এবং প্রশ্ন থেকে খুব দূরে নয়, তবে আপনার পর্যবেক্ষণটি সঠিক।
অস্বীকার করেন সাগুরেট

7
দয়া করে নোট করুন যে এ পর্যন্ত পোস্ট করা কোনও আঞ্জর বীজটিকে ক্রিপ্টোগ্রাফিকভাবে নিরাপদ উপায়ে আরম্ভ করবেন না। আপনার অ্যাপ্লিকেশন উপর নির্ভর করে, এটি মোটেও গুরুত্বপূর্ণ নয় বা এটি বিপর্যয়কর ব্যর্থতার কারণ হতে পারে।
ইনগো ব্লিচস্মিড্ট

3
@ ইঙ্গোব্লেশ্মমিডট math/randকোনওভাবেই ক্রিপ্টোগ্রাফিকভাবে সুরক্ষিত নয়। যদি এটি প্রয়োজন হয় তবে এটি crypto/randব্যবহার করা উচিত।
ডানকান জোন্স

39

আমি বুঝতে পারি না কেন লোকেরা সময় মূল্য দিয়ে বীজ বপন করছে। এটি আমার অভিজ্ঞতাতে কখনও ভাল ধারণা ছিল না। উদাহরণস্বরূপ, সিস্টেমের ঘড়িটি ন্যানোসেকেন্ডে সম্ভবত উপস্থাপন করা হলেও, সিস্টেমের ঘড়ির যথার্থতা ন্যানোসেকেন্ড নয় onds

এই প্রোগ্রামটি গো খেলার মাঠে চালানো উচিত নয় তবে আপনি যদি এটি আপনার মেশিনে চালান তবে আপনি কী ধরণের নির্ভুলতা আশা করতে পারেন তার একটি মোটামুটি অনুমান পাবেন। আমি প্রায় 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
এই উত্তরটি খুব অনাকাঙ্ক্ষিত। বিশেষত কমান্ড লাইন সরঞ্জামগুলির জন্য যা এক সেকেন্ডে একাধিকবার চলতে পারে, এটি অবশ্যই করা উচিত। আপনাকে ধন্যবাদ
সাইদগ্নু

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সমেত)।
স্ন্যাপ করুন

2
@ স্নাপ সঠিক; আসলে সহ -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())
}

এটি ডিসট্রয়ের কোডের ভিত্তিতে তৈরি তবে আমার প্রয়োজনের জন্য উপযুক্ত।

এটি মারা যায় ছয় (রেন্ডস ইনটস 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
@ থমাস মডিনিয়াস: এটি কারণ তারা খেলার মাঠে সময় নকল
ofavre

1
ধন্যবাদ @ ফ্যাভরে, সেই নকল-সময় আমাকে প্রথমে ছুড়ে ফেলেছিল।
জেসি চিশলম

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

আমি স্প্রিন্টফ ব্যবহার করার কারণ এটি সহজ স্ট্রিং ফর্ম্যাটিংয়ের অনুমতি দেয় allows

এছাড়াও, 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 () বাদ দিন:

সময় এখন(). ইউটিসি () .উনিক্স ন্যানো () -> সময়.নাউ ()। ইউনিক্সনো ()

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)
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.