यह उदाहरण कोड दिखाता है कि std::rand
विरासत कार्गो पंथ बल्डडैश का एक मामला है जो आपको हर बार जब भी आप इसे देखते हैं तो अपनी भौंहों को ऊपर उठाना चाहिए।
यहाँ कई मुद्दे हैं:
अनुबंध लोग आम तौर पर मान-यहां तक कि गरीब असहाय आत्मा है जो किसी भी बेहतर नहीं जानते और ठीक इन में इसके बारे में सोच भी नहीं होगा शर्तों-यह है कि rand
से नमूने समान वितरण 0 में पूर्णांकों पर, 1, 2, ..., RAND_MAX
, और प्रत्येक कॉल एक स्वतंत्र नमूना देता है।
पहली समस्या यह है कि प्रत्येक कॉल में ग्रहण किए गए अनुबंध, स्वतंत्र वर्दी यादृच्छिक नमूने, वास्तव में दस्तावेज क्या कहते हैं- और व्यवहार में, कार्यान्वयन ऐतिहासिक रूप से स्वतंत्रता के सबसे अच्छे simulacrum प्रदान करने में विफल रहे हैं। उदाहरण के लिए, C99 §7.20.2.1 ' rand
फ़ंक्शन' विस्तार के बिना कहता है:
rand
समारोह रेंज 0 करने के लिए छद्म यादृच्छिक पूर्णांकों का एक दृश्य की गणना करता है RAND_MAX
।
यह एक अर्थहीन वाक्य है, क्योंकि छद्मता एक फ़ंक्शन (या फ़ंक्शंस के परिवार ) की एक संपत्ति है , जो एक पूर्णांक की नहीं है, लेकिन यह आईएसओ नौकरशाहों को भाषा का दुरुपयोग करने से भी नहीं रोकती है। आखिरकार, केवल वे पाठक जो इससे परेशान होंगे rand
, वे अपने मस्तिष्क की कोशिकाओं के क्षय होने के डर से प्रलेखन को पढ़ने से बेहतर जानते हैं ।
सी में एक विशिष्ट ऐतिहासिक कार्यान्वयन इस तरह काम करता है:
static unsigned int seed = 1;
static void
srand(unsigned int s)
{
seed = s;
}
static unsigned int
rand(void)
{
seed = (seed*1103515245 + 12345) % ((unsigned long)RAND_MAX + 1);
return (int)seed;
}
यह दुर्भाग्यपूर्ण संपत्ति है कि भले ही एक ही नमूना समान रूप से यादृच्छिक बीज (जो विशिष्ट मूल्य पर निर्भर करता है RAND_MAX
) के तहत समान रूप से वितरित किया जा सकता है , यह लगातार कॉल में भी और विषम पूर्णांक के बीच वैकल्पिक होता है - के बाद
int a = rand();
int b = rand();
अभिव्यक्ति (a & 1) ^ (b & 1)
100% संभावना के साथ 1 प्राप्त करती है, जो कि किसी भी वितरण पर स्वतंत्र यादृच्छिक नमूनों के लिए भी मामला नहीं है और विषम पूर्णांक पर भी समर्थित है। इस प्रकार, एक कार्गो पंथ का उदय हुआ कि किसी को 'बेहतर यादृच्छिकता' के मायावी जानवर का पीछा करने के लिए कम-क्रम बिट्स को छोड़ देना चाहिए। (स्पॉयलर अलर्ट: यह एक तकनीकी शब्द नहीं है। यह एक संकेत है कि जिसका भी गद्य आप पढ़ रहे हैं, वह यह नहीं जानता कि वे किस बारे में बात कर रहे हैं, या आपको लगता है कि आप क्लूलेस हैं और इसके लिए कृपालु होना चाहिए।)
दूसरी समस्या यह है कि भले ही प्रत्येक कॉल ने 0, 1, 2,… पर एक समान यादृच्छिक वितरण से स्वतंत्र रूप से नमूना लिया होRAND_MAX
, का परिणाम rand() % 6
समान रूप से 0, 1, 2, 3, 4, 5 में वितरित नहीं किया जाएगा रोल, जब तक RAND_MAX
-1 मॉडुलो के अनुरूप नहीं होता। 6. सरल प्रतिधारण: यदि RAND_MAX
= 6, तो rand()
, सभी परिणामों में समान संभावना 1/7 है, लेकिन rand() % 6
, परिणाम 0 से संभाव्यता 2/7 है, जबकि अन्य सभी परिणामों में संभावना 1/7 है। ।
ऐसा करने का सही तरीका अस्वीकृति नमूनाकरण है: बार-बारs
0, 1, 2,… RAND_MAX
, और उदाहरण के लिए एक स्वतंत्र वर्दी यादृच्छिक नमूना ड्रा , (उदाहरण के लिए) परिणाम 0, 1, 2,…, को अस्वीकार करें -((RAND_MAX + 1) % 6) - 1
यदि आपको एक मिल जाए उन, शुरू; अन्यथा, उपज s % 6
।
unsigned int s;
while ((s = rand()) < ((unsigned long)RAND_MAX + 1) % 6)
continue;
return s % 6;
इस तरह, से परिणामों के सेट rand()
हम स्वीकार करते हैं कि समान रूप से 6 से विभाज्य है, और से प्रत्येक संभव परिणाम s % 6
के एक ही संख्या से प्राप्त किया जाता है स्वीकार किए जाते हैं से परिणामों rand()
, इसलिए यदि rand()
समान रूप से वितरित किया जाता है तो इतना है s
। परीक्षणों की संख्या पर कोई बाध्य नहीं है , लेकिन अपेक्षित संख्या 2 से कम है, और सफलता की संभावना परीक्षणों की संख्या के साथ तेजी से बढ़ती है।
के चुनाव जो परिणामों की rand()
आप अस्वीकार सारहीन है, बशर्ते कि आप 6. नीचे प्रत्येक पूर्णांक के लिए उनमें से एक समान संख्या के नक्शे cppreference.com पर कोड एक बनाता है विभिन्न पहली समस्या के कारण, चुनाव के ऊपर कि कुछ भी नहीं के बारे में गारंटी दी गई है वितरण या आउटपुट की स्वतंत्रता rand()
, और व्यवहार में कम-क्रम बिट्स प्रदर्शित पैटर्न हैं जो 'यादृच्छिक रूप से पर्याप्त नहीं दिखते हैं' (कभी भी मन नहीं है कि अगला आउटपुट पिछले एक का निर्धारण कार्य है)।
पाठक के लिए व्यायाम: सिद्ध कीजिए कि cppreference.com पर कोड rand()
0, 1, 2,…, पर एक समान वितरण होने पर डाई रोल पर एक समान वितरण देता है RAND_MAX
।
पाठक के लिए व्यायाम: आप अस्वीकार करने के लिए एक या दूसरे सबसेट को क्यों पसंद कर सकते हैं? दो मामलों में प्रत्येक परीक्षण के लिए क्या संगणना आवश्यक है?
एक तीसरी समस्या यह है कि बीज का स्थान इतना छोटा है कि भले ही बीज समान रूप से वितरित किया जाता है, एक विरोधी आपके कार्यक्रम और एक परिणाम के ज्ञान से लैस है, लेकिन बीज आसानी से बीज और बाद के परिणामों की भविष्यवाणी नहीं कर सकता है, जिससे उन्हें ऐसा नहीं लगता है सब के बाद यादृच्छिक। तो क्रिप्टोग्राफी के लिए इसका उपयोग करने के बारे में भी मत सोचो।
आप std::uniform_int_distribution
एक उपयुक्त यादृच्छिक डिवाइस के साथ फैंसी अतिरंजित मार्ग और C ++ 11 की कक्षा में जा सकते हैं और अपने पसंदीदा यादृच्छिक इंजन जैसे कभी लोकप्रिय मर्सन ट्विस्टर std::mt19937
अपने चार वर्षीय चचेरे भाई के साथ पासा खेलने के लिए, लेकिन वह भी नहीं जा रहा है क्रिप्टोग्राफ़िक कुंजी सामग्री उत्पन्न करने के लिए फिट रहें - और मर्सिएने ट्विस्टर एक भयानक स्पेस हॉग है जिसमें एक मल्टी-किलोबाइट राज्य है जो आपके सीपीयू के कैश पर एक अश्लील सेटअप समय के साथ कहर बरपा रहा है, इसलिए यह भी खराब है, जैसे , समानांतर मोंटे कार्लो सिमुलेशन उप-विच्छेदन के प्रजनन योग्य पेड़; इसकी लोकप्रियता की संभावना मुख्य रूप से इसके आकर्षक नाम से उत्पन्न होती है। लेकिन आप इसे इस तरह के उदाहरण के लिए खिलौना पासा रोलिंग के लिए उपयोग कर सकते हैं!
एक अन्य दृष्टिकोण एक छोटे से राज्य के साथ एक सरल क्रिप्टोग्राफ़िक छद्म आयामी संख्या जनरेटर का उपयोग करना है, जैसे कि एक साधारण तेज़ कुंजी इरेज़र PRNG , या बस एक स्ट्रीम सिफर जैसे AES-CTR या ChaCha20 यदि आप आश्वस्त हैं ( उदाहरण के लिए , मोंटे कार्लो सिमुलेशन में) प्राकृतिक विज्ञानों में अनुसंधान) कि यदि राज्य कभी समझौता करता है तो पिछले परिणामों की भविष्यवाणी करने के लिए कोई प्रतिकूल परिणाम नहीं हैं।
std::uniform_int_distribution