2015-04-06 6 views
6

जब मैं निम्नलिखित कोड चलाने के लिए, कोई बात नहीं क्या रेंज मैं for पाश के लिए उपयोग करते हैं, कोड हमेशा बाहर true दस बार प्रिंट देता है।Random.nextBoolean() हमेशा सच है कोई बात नहीं बीज

public static void main(String[] args) 
{ 
    Random bool = new Random(); 

    for (int i = 0; i < 10; i++) { 
     bool.setSeed(i); 
     System.out.println(bool.nextBoolean()); 
    } 
} 

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

public static void main(String[] args) 
{ 
    Random bool = new Random(); 

    for (int i = 0; i < 10; i++) { 
     bool.setSeed(i); 
     bool.nextBoolean(); //Only change 
     System.out.println(bool.nextBoolean()); 
    } 
} 

मुझे ऐसा लगता है कि nextBoolean() समारोह हमेशा true लौटाता है जब पहली बार मार डाला, वहाँ इस व्यवहार के लिए किसी भी कारण है?

+2

आपको लगता है कि 'setSeed' क्या करता है? –

+0

कोई गारेंटी नहीं है जो बीज को रैंडम ऑब्जेक्ट में बदलता है, पहले बूलियन या दूसरे बूलियन को अगले बूलियन() द्वारा वापस कर देगा। – ControlAltDel

+0

क्या यह हर बार यादृच्छिक जनरेटर के लिए 'सत्य' और 'झूठी' का एक अलग पैटर्न नहीं बनाना चाहिए? – Dan

उत्तर

6

कारण setSeed विधि के लिए एपीआई में पाया जाता है:

वर्ग रैंडम द्वारा setSeed के कार्यान्वयन को देखते हुए बीज का केवल 48 बिट का उपयोग होता है।

वास्तव में long उपलब्ध कराने के रूप में बीज मूल्य एक निश्चित मूल्य (Random कक्षा में निजी तौर पर परिभाषित) से गुणा किया जाता और उसके बाद ही कम से कम महत्वपूर्ण 48 बिट माना जाता है। भले ही यह गुणक बड़ा है, क्योंकि i मानों का आपका अनुक्रम लगातार सभी होते हैं, वे सभी बीज मूल्य उत्पन्न करते हैं जो संख्यात्मक रूप से समान होते हैं। तो पहले कुछ हज़ार मान प्रभावी रूप से nextBoolean विधि के समान मान के रूप में देखे जाते हैं, और आपको सटीक प्रारंभिक बूलियन मान मिलता है। nextBoolean को कॉल करना (setSeed को दोबारा कॉल किए बिना) बीज मूल्य को पुनरुत्थान करेगा, इसलिए आप तुरंत उसी पैटर्न को देखने से दूर चले जाएंगे।

यदि आप setSeed विधि पर कॉल करते हैं तो आपको केवल इसे एक बार कॉल करने की आवश्यकता होगी, और आपको लूप के बाहर ऐसा करना चाहिए। लेकिन Random कक्षा पूरी तरह से अपने बीज मूल्य का चयन करने में सक्षम है, इसलिए मैं अनुशंसा करता हूं कि आप setSeed पर कॉल न करें जबतक कि आप यह नहीं जानते कि आप ऐसा क्यों कर रहे हैं।

+0

तो इनपुट को परिवर्तित करने का सबसे अच्छा तरीका क्या है, इसलिए यह इसे एक अद्वितीय संख्या के रूप में पहचानता है? क्या मुझे बस एक बड़ी संख्या से 'i' गुणा करना चाहिए? – Dan

+0

@SuperNew: 'नई तिथि()। GetTime() + कुछ कस्टम Value' बीज के रूप में उपयोग करें। यह सुनिश्चित करता है कि आपका बीज वास्तविक पुनरावृत्ति से स्वतंत्र है। – dognose

+0

जब तक आपको वास्तव में बीज के मूल्य का चयन करने की आवश्यकता नहीं है, तो बस 'रैंडम' को अपना स्वयं का बीज चुनने दें। दूसरे शब्दों में, 'setSeed' को बिल्कुल कॉल न करें, और' रैंडम 'कन्स्ट्रक्टर के लिए बीज मान प्रदान न करें। – Bobulous

1

तो मूल रूप से nextBoolean विधि केवल true या false लौटा सकती है। और seed मानों की कुल संख्या [Long.MIN_VALUE, Long.MAX_VALUE] हो सकती है। तो, आप मान सकते हैं कि इन बीजों में से आधे के लिए आपको true मिलेगा और अन्य आधे के लिए आपको false मिल जाएगा।

अब जब आप 10 संख्याओं के लिए पुनरावृत्त करते हैं, तो यह संभव हो सकता है कि उन 10 बीजों के लिए, आपको प्राप्त मूल्य true है। जब आप काफी अधिक रेंज पर आज़माते हैं, तो आप दोनों मानों के बराबर वितरण प्राप्त करने की अधिक संभावना रखते हैं।

हर बार जब आप nextBoolean() पर कॉल करते हैं, तो (seed * 0x5DEECE66DL + 0xBL) & ((1L << 48) - 1) का उपयोग कर बीज को किसी अन्य मूल्य पर अपडेट किया जाता है। तो यदि वर्तमान बीज 1 है, तो अगला बीज 25214903916 होगा, जहां आप true या false (जिसे आप नहीं जानते) प्राप्त कर सकते हैं। यही कारण है कि आप false कभी-कभी प्राप्त करते हैं जब आप लूप में nextBoolean() दो बार कॉल करते हैं। आखिरकार, यह छद्म-यादृच्छिक संख्या जनरेटर है।

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

public Random() { 
    this(seedUniquifier()^System.nanoTime()); 
} 

private static long seedUniquifier() { 
    // L'Ecuyer, "Tables of Linear Congruential Generators of 
    // Different Sizes and Good Lattice Structure", 1999 
    for (;;) { 
     long current = seedUniquifier.get(); 
     long next = current * 181783497276652981L; 
     if (seedUniquifier.compareAndSet(current, next)) 
      return next; 
    } 
} 

तो, आपको लगता है कि केवल करने के लिए कार्य छोड़ देना चाहिए:

आप Random वर्ग के कोड देखते हैं, तो यह है कि वे कैसे बीज पहली बार सौंपते हैं।

0

यह कारण है कि हम उन्हें "psuedorandom" संख्या कहते हैं। एक जटिल और आम तौर पर अपरिवर्तनीय है, लेकिन अभी भी निर्धारिती है, हर यादृच्छिक कॉल के पीछे कार्य करता है; आमतौर पर एक साधारण सेलुलर-automaton। यादृच्छिकरण बीज के इतने सारे लोगों के लिए सत्य की वापसी इस कार्य का एक आर्टिफैक्ट है; यह सुनिश्चित करने के लिए कि आपको कुछ तर्कसंगत यादृच्छिकता मिल रही है, मैं सिस्टम और नैनोटाइम() से बड़े और भिन्न संख्या का उपयोग करने का सुझाव देता हूं।

संबंधित मुद्दे