रैंडम संख्या जनरेटर केवल एक यादृच्छिक संख्या उत्पन्न करता है


765

मेरा निम्नलिखित कार्य है:

//Function to get random number
public static int RandomNumber(int min, int max)
{
    Random random = new Random();
    return random.Next(min, max);
}

मैं इसे कैसे कहता हूं:

byte[] mac = new byte[6];
for (int x = 0; x < 6; ++x)
    mac[x] = (byte)(Misc.RandomNumber((int)0xFFFF, (int)0xFFFFFF) % 256);

यदि मैं रनवे के दौरान डिबगर के साथ उस लूप को चरणबद्ध करता हूं तो मुझे अलग-अलग मान मिलते हैं (जो कि मुझे चाहिए)। हालाँकि, अगर मैं उस कोड के नीचे दो बिंदुओं पर एक ब्रेकपॉइंट लगाता हूं, तो macसरणी के सभी सदस्यों का समान मूल्य है।

ऐसा क्यों होता है?


20
का उपयोग कर new Random().Next((int)0xFFFF, (int)0xFFFFFF) % 256);किसी भी बेहतर "यादृच्छिक" संख्या की तुलना में नहीं है.Next(0, 256)
bohdan_trotsenko

आपको यह NuGet पैकेज मददगार लग सकता है। यह एक स्थैतिक Rand.Next(int, int)विधि प्रदान करता है जो बिना लॉक किए या बिना बीज के पुन: उपयोग की समस्या में यादृच्छिक मूल्यों तक स्थैतिक पहुंच प्रदान करता है
चेसमैडेलियन

जवाबों:


1040

हर बार जब आप new Random()यह करते हैं तो घड़ी का उपयोग करके इसे आरंभ किया जाता है। इसका मतलब है कि एक तंग लूप में आपको कई बार समान मूल्य मिलता है। आपको एक ही रैंडम इंस्टेंस रखना चाहिए और उसी इंस्टेंस पर नेक्स्ट का इस्तेमाल करते रहना चाहिए ।

//Function to get a random number 
private static readonly Random random = new Random(); 
private static readonly object syncLock = new object(); 
public static int RandomNumber(int min, int max)
{
    lock(syncLock) { // synchronize
        return random.Next(min, max);
    }
}

संपादित करें (टिप्पणियां देखें): हमें lockयहां की आवश्यकता क्यों है ?

मूल रूप से, उदाहरण Nextकी आंतरिक स्थिति को बदलने जा रहा है Random। यदि हम एक ही समय में कई थ्रेड से करते हैं, तो आप तर्क दे सकते हैं कि "हमने अभी परिणाम को और अधिक यादृच्छिक बना दिया है", लेकिन हम वास्तव में जो कर रहे हैं वह आंतरिक कार्यान्वयन को संभवतः तोड़ रहा है, और हम भी एक ही नंबर प्राप्त करना शुरू कर सकते हैं। विभिन्न धागों से, जो एक समस्या हो सकती है - और नहीं हो सकती है। आंतरिक रूप से क्या होता है इसकी गारंटी हालांकि बड़ा मुद्दा है; के बाद से Randomकरता नहीं धागे की सुरक्षा के किसी भी गारंटी। इस प्रकार दो मान्य दृष्टिकोण हैं:

  • सिंक्रनाइज़ करें ताकि हम इसे अलग-अलग थ्रेड्स से एक ही समय में एक्सेस न करें
  • Randomप्रति थ्रेड विभिन्न उदाहरणों का उपयोग करें

या तो ठीक हो सकता है; लेकिन एक ही समय में कई कॉल करने वालों से किसी भी उदाहरण को म्यूट करना केवल परेशानी के लिए पूछ रहा है।

lockइन तरीकों की पहली (और सरल) को प्राप्त होता है; हालाँकि, एक और तरीका हो सकता है:

private static readonly ThreadLocal<Random> appRandom
     = new ThreadLocal<Random>(() => new Random());

यह तब प्रति-सूत्र है, इसलिए आपको सिंक्रनाइज़ करने की आवश्यकता नहीं है।


19
एक सामान्य नियम के रूप में, सभी स्थिर तरीकों को थ्रेड-सुरक्षित बनाया जाना चाहिए, क्योंकि यह गारंटी देना कठिन है कि एक ही समय में कई थ्रेड इसे कॉल नहीं करेंगे। यह है नहीं बनाने के लिए आम तौर पर आवश्यक उदाहरण (यानी गैर स्थिर) तरीके धागा सुरक्षित।
मार्क Gravell

5
@ फ़्लोरिन - दोनों के बीच कोई अंतर नहीं है "स्टैक आधारित"। स्थैतिक क्षेत्र बस "बाहरी राज्य" के रूप में हैं, और बिल्कुल कॉलर्स के बीच साझा किए जाएंगे। उदाहरणों के साथ, एक अच्छा मौका है कि विभिन्न थ्रेड्स के अलग-अलग उदाहरण (एक सामान्य पैटर्न) हैं। स्टैटिक्स के साथ, यह गारंटी है कि वे सभी साझा करते हैं ([थ्रेडस्टैटिक सहित नहीं))।
मार्क Gravell

2
@gdoron क्या आपको कोई त्रुटि हो रही है? "लॉक" ... यहाँ प्रत्येक-दूसरे पर ट्रिपिंग से धागे रोकने चाहिए
मार्क Gravell

6
@ यदि वस्तु सार्वजनिक रूप से कभी उजागर नहीं होती है: आप कर सकते हैं। (बहुत सैद्धांतिक) जोखिम यह है कि कुछ अन्य धागे उन तरीकों से लॉक हो रहे हैं जिनकी आपको उम्मीद नहीं थी।
मार्क ग्रेवेल

3
@smiron यह बहुत संभावना है कि आप बस एक ताला के बाहर यादृच्छिक का उपयोग कर रहे हैं। लॉकिंग आपके द्वारा लॉक किए जा रहे सभी एक्सेस को रोकता नहीं है - यह सिर्फ यह सुनिश्चित करता है कि एक ही उदाहरण पर दो लॉक स्टेटमेंट समवर्ती नहीं चलेंगे। तो lock (syncObject)केवल तभी मदद मिलेगी जब सभी random.Next() कॉल भीतर भी हों lock (syncObject)। परिदृश्य आप का वर्णन भी सही के साथ आती है तो lockउपयोग, यह भी अत्यंत संभावना एक एकल थ्रेड परिदृश्य में क्या होता है (उदाहरण के लिए Randomआसानी से टूट गया है)।
लुआं

118

आपके एप्लिकेशन में पुन: उपयोग में आसानी के लिए एक स्थिर वर्ग मदद कर सकता है।

public static class StaticRandom
{
    private static int seed;

    private static ThreadLocal<Random> threadLocal = new ThreadLocal<Random>
        (() => new Random(Interlocked.Increment(ref seed)));

    static StaticRandom()
    {
        seed = Environment.TickCount;
    }

    public static Random Instance { get { return threadLocal.Value; } }
}

आप तब कोड के साथ स्थिर यादृच्छिक उदाहरण का उपयोग कर सकते हैं जैसे

StaticRandom.Instance.Next(1, 100);

62

मार्क का समाधान काफी महंगा हो सकता है क्योंकि इसे हर बार सिंक्रनाइज़ करने की आवश्यकता होती है।

हम थ्रेड-विशिष्ट भंडारण पैटर्न का उपयोग करके सिंक्रनाइज़ेशन की आवश्यकता के आसपास प्राप्त कर सकते हैं:


public class RandomNumber : IRandomNumber
{
    private static readonly Random Global = new Random();
    [ThreadStatic] private static Random _local;

    public int Next(int max)
    {
        var localBuffer = _local;
        if (localBuffer == null) 
        {
            int seed;
            lock(Global) seed = Global.Next();
            localBuffer = new Random(seed);
            _local = localBuffer;
        }
        return localBuffer.Next(max);
    }
}

दो कार्यान्वयन को मापें और आपको एक महत्वपूर्ण अंतर देखना चाहिए।


12
जब वे चुनाव नहीं लड़ते हैं तो ताले बहुत सस्ते होते हैं ... और अगर मैं चुनाव लड़ता हूं तो मुझे सबसे दिलचस्प परिदृश्यों में लॉक की लागत को कम करने के लिए "अब नंबर के साथ कुछ करना" कोड की उम्मीद होगी।
मार्क Gravell

4
सहमत, यह लॉकिंग समस्या को हल करता है, लेकिन यह अभी भी एक तुच्छ समस्या का अत्यधिक जटिल समाधान नहीं है: कि आपको एक के बजाय एक यादृच्छिक संख्या उत्पन्न करने के लिए कोड की '' दो '' लाइनें लिखनी होंगी। क्या कोड की एक सरल रेखा को पढ़ने से बचाने के लिए यह वास्तव में इसके लायक है?
ईएमपी

4
+1 Randomबीज प्राप्त करने के लिए एक अतिरिक्त वैश्विक उदाहरण का उपयोग करना एक अच्छा विचार है। यह भी नोट करें कि ThreadLocal<T>.NET 4 में शुरू की गई कक्षा का उपयोग करके कोड को और सरल बनाया जा सकता है (जैसा कि फिल में नीचे भी लिखा गया है )।
ग्रू

40

मेरा जवाब यहाँ से :

बस सही समाधान दोहरा रहे हैं :

namespace mySpace
{
    public static class Util
    {
        private static rnd = new Random();
        public static int GetRandom()
        {
            return rnd.Next();
        }
    }
}

तो आप कॉल कर सकते हैं:

var i = Util.GetRandom();

पूरे कार्यकाल में।

यदि आपको यादृच्छिक संख्याओं को उत्पन्न करने के लिए एक सच्चे स्टेटलेस स्टेटिक विधि की सख्त आवश्यकता है , तो आप एक पर भरोसा कर सकते हैं Guid

public static class Util
{
    public static int GetRandom()
    {
        return Guid.NewGuid().GetHashCode();
    }
}

यह एक सुबह थोड़ा धीमा होने जा रहा है, लेकिन और अधिक यादृच्छिक हो सकता है की तुलना में Random.Nextकम से कम मेरे अनुभव से,।

लेकिन नहीं :

new Random(Guid.NewGuid().GetHashCode()).Next();

अनावश्यक वस्तु निर्माण इसे विशेष रूप से एक लूप के तहत धीमा बनाने जा रहा है।

और कभी नहीं :

new Random().Next();

न केवल यह धीमी (एक लूप के अंदर) है, इसकी यादृच्छिकता है ... मेरे अनुसार वास्तव में अच्छा नहीं है।


10
मैं गाइड केस से सहमत नहीं हूं। रैंडम वर्ग एक समान वितरण लागू करता है। जो कि गाइडेंस में नहीं है। गाइड का उद्देश्य विशिष्ट रूप से समान रूप से वितरित नहीं किया जाना है (और इसका कार्यान्वयन अधिकांश समय कुछ हार्डवेयर / मशीन संपत्ति के आधार पर होता है जो कि ... यादृच्छिकता) के विपरीत होता है।
Askolein

4
यदि आप मार्गदर्शक पीढ़ी की एकरूपता को साबित नहीं कर सकते हैं, तो इसे यादृच्छिक के रूप में उपयोग करना गलत है (और हैश एकरूपता से एक और कदम दूर होगा)। इसी तरह, टकराव एक मुद्दा नहीं है: टक्कर की एकरूपता है। गाइड पीढ़ी के संबंध में हार्डवेयर पर नहीं होने के बारे में अब मैं RTFM, मेरा बुरा (कोई संदर्भ?) जा रहा हूं
Askolein

5
"यादृच्छिक" की दो समझ है: 1. पैटर्न की कमी या 2. एक संभावना वितरण द्वारा वर्णित एक विकास के बाद पैटर्न की कमी (2 में शामिल 1)। आपका गाइड उदाहरण केस 1 में सही है, केस 2 में नहीं। इसके विपरीत: Randomक्लास मैच केस 2 (इस प्रकार, केस 1 भी)। यदि आप मामले में नहीं हैं तो आप केवल Randomअपने द्वारा उपयोग की जगह ले सकते Guid+Hashहैं । केस 1 शायद सवाल का जवाब देने के लिए पर्याप्त है, और फिर, आपके काम ठीक हैं। लेकिन यह स्पष्ट रूप से नहीं कहा गया है (ps: यह वर्दी )Guid+Hash
Askolein

2
@ एस्कॉलिन बस कुछ परीक्षण डेटा के लिए, मैं दोनों के कई बैचों को चलाता हूं Randomऔर Guid.NewGuid().GetHashCode()एंट ( फोरमिलब.च / रैंडम ) के माध्यम से और दोनों समान रूप से यादृच्छिक हैं। new Random(Guid.NewGuid().GetHashCode())बस के रूप में अच्छी तरह से काम करता है, के रूप में Random"बच्चे" के लिए बीज उत्पन्न करने के लिए एक सिंक्रनाइज़ "मास्टर" का उपयोग करता है Random.. बेशक, यह इस बात पर निर्भर करता है कि आपका सिस्टम कैसे गाइड उत्पन्न करता है - मेरे सिस्टम के लिए, वे काफी यादृच्छिक हैं, और दूसरों पर यह हो सकता है यहां तक ​​कि क्रिप्टो-यादृच्छिक हो। इसलिए आजकल विंडोज या एमएस एसक्यूएल ठीक लगता है। मोनो और / या मोबाइल अलग हो सकता है, यद्यपि।
लुआण

2
@ ईडीबी जैसा कि मैंने पहले टिप्पणियों में कहा है, जबकि गाइड (एक बड़ी संख्या) अद्वितीय होने के लिए है GetHashCode। .NET में मार्गदर्शिका का अर्थ इसके स्ट्रिंग प्रतिनिधित्व से लिया गया है। मेरी पसंद के लिए आउटपुट काफी यादृच्छिक है।
नवाफाल

27

मैं यादृच्छिक संख्या उत्पन्न करने के लिए निम्न वर्ग का उपयोग करूंगा:

byte[] random;
System.Security.Cryptography.RNGCryptoServiceProvider prov = new System.Security.Cryptography.RNGCryptoServiceProvider();
prov.GetBytes(random);

30
मैं नीचे के मतदाताओं में से एक नहीं हूं, लेकिन ध्यान दें कि मानक PNRG एक वास्तविक आवश्यकता की सेवा करता है - अर्थात किसी ज्ञात बीज से अनुक्रम को पुन: दोहराने में सक्षम होना। कभी-कभी एक सच्चे क्रिप्टोग्राफिक RNG की सरासर लागत बहुत अधिक होती है। और कभी-कभी एक क्रिप्टो आरएनजी आवश्यक है। पाठ्यक्रमों के लिए घोड़े, इसलिए बोलने के लिए।
मार्क Gravell

4
प्रलेखन के अनुसार यह वर्ग थ्रेड-सुरक्षित है, इसलिए यह इसके पक्ष में कुछ है।
रॉब चर्च

क्या संभावना है कि एक का उपयोग करने के लिए दो यादृच्छिक तार एक और एक ही हो? यदि स्ट्रिंग सिर्फ 3 वर्ण है तो मुझे लगता है कि यह उच्च संभावना के साथ होगा लेकिन क्या होगा यदि 255 वर्णों की लंबाई समान यादृच्छिक स्ट्रिंग होना संभव है या गारंटी है कि यह एल्गोरिथम से नहीं हो सकता है?
हुसोमिर वेलचेव

16

1) जैसा कि मार्क ग्रेवेल ने कहा, वन रैंडम-जनरेटर का उपयोग करने का प्रयास करें। इसे हमेशा कंस्ट्रक्टर में जोड़ने के लिए अच्छा है: System.Environment.TickCount।

2) एक टिप। मान लें कि आप 100 ऑब्जेक्ट बनाना चाहते हैं और मान लें कि उनमें से प्रत्येक के पास अपना रैंडम-जनरेटर होना चाहिए (यदि आप बहुत कम समय में यादृच्छिक संख्याओं के लोड की गणना करते हैं)। यदि आप इसे एक लूप (100 वस्तुओं की पीढ़ी) में करते हैं, तो आप ऐसा कर सकते हैं (पूरी तरह से यादृच्छिकता को आश्वस्त करने के लिए):

int inMyRandSeed;

for(int i=0;i<100;i++)
{
   inMyRandSeed = System.Environment.TickCount + i;
   .
   .
   .
   myNewObject = new MyNewObject(inMyRandSeed);  
   .
   .
   .
}

// Usage: Random m_rndGen = new Random(inMyRandSeed);

चीयर्स।


3
मैं System.Environment.TickCount लूप से बाहर ले जाऊंगा। यदि आप इसे पुनरावृत्ति करते हुए देखते हैं, तो आपके पास एक ही बीज से आरंभिक दो आइटम होंगे। एक अन्य विकल्प टिक्काउंट को एक अलग तरीके से संयोजित करना होगा (जैसे System.Environment.TickCount << 8 + i)
डॉल्फिन

अगर मैं सही ढंग से समझता हूं: क्या आपका मतलब है, यह हो सकता है, कि "System.Environment.TickCount + i" एसएएमडी मूल्य का परिणाम हो सकता है?
सबीलैंड

संपादित करें: बेशक, लूप के अंदर टिककाउंट करने की कोई आवश्यकता नहीं है। मेरी गलती :)।
सबीलैंड

2
वैसे भी डिफॉल्ट Random()कंस्ट्रक्टर कॉल करता Random(Environment.TickCount)है
Alsty

5

हर बार जब आप निष्पादित करते हैं

Random random = new Random (15);

इससे कोई फर्क नहीं पड़ता कि यदि आप इसे लाखों बार निष्पादित करते हैं, तो आप हमेशा एक ही बीज का उपयोग करेंगे।

यदि तुम प्रयोग करते हो

Random random = new Random ();

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

यदि आपको सुरक्षित यादृच्छिक संख्याओं की आवश्यकता है तो आपको कक्षा का उपयोग करना चाहिए

System.Security.Cryptography.RNGCryptoServiceProvider

public static int Next(int min, int max)
{
    if(min >= max)
    {
        throw new ArgumentException("Min value is greater or equals than Max value.");
    }
    byte[] intBytes = new byte[4];
    using(RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider())
    {
        rng.GetNonZeroBytes(intBytes);
    }
    return  min +  Math.Abs(BitConverter.ToInt32(intBytes, 0)) % (max - min + 1);
}

उपयोग:

int randomNumber = Next(1,100);

It does not matter if you execute it millions of times, you will always use the same seed. यह सच नहीं है जब तक कि आप स्वयं बीज निर्दिष्ट न करें।
लार्सटेक

ठीक करना। धन्यवाद जैसा कि आप कहते हैं कि लार्सटेक, यदि एक ही बीज हमेशा निर्दिष्ट किया जाता है, तो यादृच्छिक संख्याओं का एक ही क्रम हमेशा उत्पन्न होगा। यदि आप हमेशा एक ही बीज का उपयोग करते हैं, तो मैं अपने जवाब में निर्माणकर्ता को मापदंडों के साथ संदर्भित करता हूं। रैंडम वर्ग केवल छद्म यादृच्छिक संख्या उत्पन्न करता है। यदि किसी को पता चलता है कि आपने अपने एल्गोरिथ्म में किस बीज का उपयोग किया है, तो यह आपके एल्गोरिथ्म की सुरक्षा या यादृच्छिकता से समझौता कर सकता है। RNGCryptoServiceProvider वर्ग के साथ, आप सुरक्षित रूप से यादृच्छिक संख्या रख सकते हैं। मैंने पहले ही सुधार कर लिया, सुधार के लिए बहुत-बहुत धन्यवाद।
जोमा

0

बस इस तरह रैंडम वर्ग चर घोषित:

    Random r = new Random();
    // ... Get three random numbers.
    //     Here you'll get numbers from 5 to 9
    Console.WriteLine(r.Next(5, 10));

यदि आप अपनी सूची से हर बार अलग-अलग यादृच्छिक संख्या प्राप्त करना चाहते हैं तो उपयोग करें

r.Next(StartPoint,EndPoint) //Here end point will not be included

हर बार Random r = new Random()एक बार घोषणा करके ।


जब आप कॉल करते हैं तो new Random()यह सिस्टम क्लॉक का उपयोग करता है, लेकिन यदि आप घड़ी बदलने से पहले एक पंक्ति में उस पूरे कोड को दो बार कॉल करते हैं, तो आपको एक ही रैंडम नंबर मिलेगा। ऊपर दिए गए उत्तरों की पूरी बात यह है।
सेव

-1

बहुत सारे समाधान हैं, यहां एक: यदि आप चाहते हैं कि संख्या केवल अक्षरों को मिटा दें और विधि एक यादृच्छिक और परिणाम लंबाई प्राप्त करती है।

public String GenerateRandom(Random oRandom, int iLongitudPin)
{
    String sCharacters = "123456789ABCDEFGHIJKLMNPQRSTUVWXYZ123456789";
    int iLength = sCharacters.Length;
    char cCharacter;
    int iLongitudNuevaCadena = iLongitudPin; 
    String sRandomResult = "";
    for (int i = 0; i < iLongitudNuevaCadena; i++)
    {
        cCharacter = sCharacters[oRandom.Next(iLength)];
        sRandomResult += cCharacter.ToString();
    }
    return (sRandomResult);
}

मूल समस्या अभी भी वही है - आप एक Randomउदाहरण में गुजर रहे हैं , लेकिन आप अभी भी कॉलर से एक साझा उदाहरण बनाने की उम्मीद कर रहे हैं। यदि कॉलर हर बार एक नया उदाहरण बनाता है और कोड को घड़ी बदलने से पहले दो बार निष्पादित किया जाता है, तो आपको एक ही यादृच्छिक संख्या मिलेगी। तो यह जवाब अभी भी मान्यताओं को गलत बनाता है।
सेव

इसके अलावा, यादृच्छिक संख्याओं को उत्पन्न करने के लिए एक विधि होने का पूरा बिंदु एनकैप्सुलेशन है - कि कॉलिंग पद्धति को कार्यान्वयन के बारे में चिंता करने की आवश्यकता नहीं है, यह केवल एक यादृच्छिक संख्या वापस पाने में रुचि रखता है
Savage
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.