रैंड ()% 6 पक्षपाती क्यों है?


109

जब पढ़ने का उपयोग करने के लिए std :: rand, मुझे यह कोड cppreference.com पर मिला

int x = 7;
while(x > 6) 
    x = 1 + std::rand()/((RAND_MAX + 1u)/6);  // Note: 1+rand()%6 is biased

सही पर अभिव्यक्ति के साथ क्या गलत है? कोशिश की और यह पूरी तरह से काम करता है।


24
ध्यान दें कि पासा के लिए उपयोग करना और भी बेहतर हैstd::uniform_int_distribution
Caleth

1
@ कैलेथ हां, यह समझना था कि यह कोड 'गलत' क्यों था ..
yO_

15
परिवर्तित "गलत है" से "पक्षपाती है"
Cubbi

3
rand()विशिष्ट कार्यान्वयन में इतना बुरा है, आप xkcd RNG का उपयोग कर सकते हैं । इसलिए यह गलत है क्योंकि यह उपयोग करता है rand()
कोडइन्चोयोस

3
मैंने यह बात लिखी (ठीक है, टिप्पणी नहीं - यह @Cubbi है) और उस समय मेरे मन में जो था वह पीट बेकर के उत्तर के बारे में बताया गया था। (FYI करें, यह मूल रूप से libstdc ++ के रूप में एक ही एल्गोरिदम है uniform_int_distribution।)
TC

जवाबों:


136

दो समस्याएँ हैं rand() % 6( 1+या तो समस्या को प्रभावित नहीं करती है)।

पहले, जैसा कि कई उत्तरों ने बताया है, यदि कम बिट्स rand()उचित रूप से समान नहीं हैं, तो शेष ऑपरेटर का परिणाम भी समान नहीं है।

दूसरा, यदि उत्पादित अलग-अलग मूल्यों की संख्या rand()6 से अधिक नहीं है, तो शेष उच्च मूल्यों की तुलना में अधिक कम मूल्यों का उत्पादन करेगा। यह सच है भले ही rand()रिटर्न पूरी तरह से वितरित मूल्यों।

एक चरम उदाहरण के रूप में, बहाना है कि rand()सीमा में समान रूप से वितरित मूल्यों का उत्पादन करता है [0..6]। यदि आप उन मानों के लिए अवशेषों को देखते हैं, जब rand()रेंज में एक मूल्य वापस आता है [0..5], तो शेष सीमा में समान रूप से वितरित परिणाम पैदा करता है [0..5]। जब rand()रिटर्न ६, rand() % 6रिटर्न ०, जैसे कि rand()०. लौटाया था। तो आपको ० के रूप में दो बार वितरण मिलता है ० किसी अन्य मूल्य के रूप में।

दूसरी वास्तविक समस्या है rand() % 6

उस समस्या से बचने का तरीका उन मूल्यों को त्यागना है जो गैर-समान डुप्लिकेट का उत्पादन करेंगे। आप 6 की सबसे बड़ी बहु की गणना करते हैं जो उससे कम या बराबर होती है RAND_MAX, और जब भी rand()कोई मान लौटाता है, जो उस से अधिक या उसके बराबर होता है, तो आप इसे अस्वीकार कर देते हैं और `रैंड '(फिर से, कई बार आवश्यकतानुसार) कॉल करते हैं।

इसलिए:

int max = 6 * ((RAND_MAX + 1u) / 6)
int value = rand();
while (value >= max)
    value = rand();

यह प्रश्न में कोड का एक अलग कार्यान्वयन है, जो स्पष्ट रूप से दिखा रहा है कि क्या चल रहा है।


2
मैंने इस साइट पर कम से कम एक नियमित रूप से इस पर एक पेपर का उत्पादन करने का वादा किया है, लेकिन मुझे लगता है कि नमूना और अस्वीकृति उच्च क्षणों को फेंक सकते हैं ; उदाहरण के लिए, विचरण को अधूरा करना।
बाथशीबा

30
मैंने एक ग्राफ किया कि इस तकनीक का कितना पूर्वाग्रह है अगर रैंड_मैक्स 32768 है, जो कुछ कार्यान्वयन में है। ericlippert.com/2013/12/16/…
Eric Lippert

2
@ बाथशीबा: यह सच है कि कुछ अस्वीकृति कार्य इसका कारण बन सकते हैं, लेकिन यह सरल अस्वीकृति एक समान IID को एक समान वर्दी IID वितरण में बदल देगी। कोई भी बिट नहीं ले जाता है, इसलिए स्वतंत्र है, सभी नमूने एक समान अस्वीकृति का उपयोग करते हैं इसलिए समान, और एकरूपता दिखाने के लिए तुच्छ। और एक समान अभिन्न यादृच्छिक चर के उच्च क्षण पूरी तरह से इसकी सीमा से परिभाषित होते हैं।
MSalters

4
@MSalters: आपका पहला वाक्य एक सच्चे जनरेटर के लिए सही है, जरूरी नहीं कि छद्म जनरेटर के लिए सही हो। जब मैं रिटायर हो रहा हूं, तो मैं इस पर एक पेपर लिखने जा रहा हूं।
बथशेबा

2
@Athony पासा के संदर्भ में सोचें। आप 1 और 3 के बीच एक यादृच्छिक संख्या चाहते हैं और आपके पास केवल मानक 6-पक्षीय डाई है। यदि आप 4-6 रोल करते हैं तो आप 3 घटा सकते हैं। लेकिन मान लीजिए कि इसके बजाय आप 1 और 5 के बीच एक संख्या चाहते हैं। यदि आप 6 को रोल करने पर 5 घटाते हैं, तो आप किसी भी अन्य संख्या के रूप में कई 1s के साथ दो बार समाप्त करेंगे। यह मूल रूप से cppreference कोड क्या है। सही काम 6s को फिर से करना है। यहाँ पीट कर रहा है: मरने को विभाजित करें ताकि प्रत्येक संख्या को रोल करने के समान तरीके हों, और किसी भी संख्या को फिर से विभाजित करें जो कि विभाजनों में भी फिट नहीं हुआ है
रे

19

यहाँ छिपी हुई गहराइयाँ हैं:

  1. छोटे के उपयोग uमें RAND_MAX + 1uRAND_MAXएक intप्रकार के रूप में परिभाषित किया गया है , और अक्सर सबसे बड़ा संभव है int। इस तरह के मामलों में अपरिभाषित किया RAND_MAX + 1जाएगा जैसा कि आप एक प्रकार से बह निकला होगा । राइटिंग फोर्स के रूपांतरण को टाइप करता है , इसलिए ओवरफ्लो को कम करता है।signed1uRAND_MAXunsigned

  2. के उपयोग % 6 कर सकते हैं (लेकिन के हर कार्यान्वयन पर std::randमैंने देखा है नहीं करता है ) के ऊपर और प्रस्तुत विकल्प के अलावा कोई अतिरिक्त सांख्यिकीय पूर्वाग्रह परिचय। ऐसे उदाहरण जहां % 6खतरनाक होते हैं, ऐसे मामले होते हैं जहां संख्या जनरेटर में निम्न क्रम बिट्स में सहसंबंध मैदान होते हैं, जैसे कि आईबीएम कार्यान्वयन (के सी) randमें, मुझे लगता है कि 1970 के दशक में उच्च और निम्न बिट्स को "अंतिम" के रूप में फ़्लिप किया गया था। पनपने "। एक और विचार यह है कि 6 बहुत छोटा cf है। RAND_MAX, इसलिए RAND_MAX6 का गुणक नहीं होने पर कम से कम प्रभाव पड़ेगा , जो कि ऐसा नहीं है।

अंत में, इन दिनों, इसकी सुवाह्यता के कारण, मैं उपयोग करूँगा % 6। यह किसी भी सांख्यिकीय विसंगतियों को स्वयं जनरेटर द्वारा पेश किए जाने से परे पेश करने की संभावना नहीं है। यदि आप अभी भी संदेह में हैं, तो अपने जनरेटर का परीक्षण करके देखें कि उसमें आपके उपयोग के मामले के लिए उपयुक्त सांख्यिकीय गुण हैं या नहीं।


12
% 6जब भी उत्पन्न अलग-अलग मानों की संख्या rand()6 से अधिक नहीं होती है तो एक पक्षपाती परिणाम उत्पन्न होता है। कबूतर-छेद सिद्धांत। दी, पूर्वाग्रह छोटा है जब RAND_MAX6 से बहुत बड़ा है, लेकिन यह वहाँ है। और बड़े लक्ष्य के लिए, प्रभाव निश्चित रूप से बड़ा होता है।
पीट बेकर

2
@ पेबैकबॉकर: दरअसल, मुझे यह स्पष्ट करना चाहिए। लेकिन ध्यान दें कि पूर्णांक विभाजन ट्रेंकुलेशन प्रभाव के कारण आप नमूना रेंज रेंज RAND_MAX के रूप में कबूतर-होलिंग भी प्राप्त करते हैं।
बतशेबा

2
@ बाथशीबा उस छंटनी के प्रभाव को 6 से बड़ा परिणाम नहीं देता है और इस तरह पूरे ऑपरेशन को दोहराया जाता है?
गेरहार्ड

1
@ गिरधर: सही। वास्तव में, यह परिणाम की ओर जाता हैx==7 । bsically, आप श्रेणी [0, RAND_MAX]को 7 सबरेंज में विभाजित करते हैं , 6 एक ही आकार के और एक छोटे सबरेंज के अंत में। अंतिम व्यवस्था से परिणाम छोड़ दिए जाते हैं। यह बिल्कुल स्पष्ट है कि आपके पास इस तरह से दो छोटी उप-श्रेणियां नहीं हो सकती हैं।
MSalters 16

@ दलाल: वास्तव में। लेकिन ध्यान दें कि ट्रंकेशन के कारण दूसरा तरीका अभी भी ग्रस्त है। मेरी परिकल्पना यह है कि बाद के लिए लोक काँप क्योंकि सांख्यिकीय कमियाँ समझना कठिन हैं!
बाथशीबा

13

यह उदाहरण कोड दिखाता है कि 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 यदि आप आश्वस्त हैं ( उदाहरण के लिए , मोंटे कार्लो सिमुलेशन में) प्राकृतिक विज्ञानों में अनुसंधान) कि यदि राज्य कभी समझौता करता है तो पिछले परिणामों की भविष्यवाणी करने के लिए कोई प्रतिकूल परिणाम नहीं हैं।


4
"एक अश्लील सेटअप समय" आपको वास्तव में वैसे भी एक से अधिक यादृच्छिक संख्या जनरेटर (प्रति थ्रेड) का उपयोग नहीं करना चाहिए, इसलिए सेटअप समय को तब तक संशोधित किया जाएगा जब तक कि आपका कार्यक्रम बहुत लंबा नहीं चलता।
JAB

2
डाउनवोट बीटीडब्ल्यू को यह समझने के लिए नहीं कि प्रश्न में लूप ठीक उसी अस्वीकृति का नमूना कर रहा है, बिल्कुल समान (RAND_MAX + 1 )% 6मूल्यों का। इससे कोई फर्क नहीं पड़ता कि आपके संभावित परिणामों को कैसे घटाया जाए। आप उन्हें सीमा में कहीं से भी अस्वीकार कर सकते हैं [0, RAND_MAX), जब तक कि स्वीकृत सीमा का आकार 6. 6 से अधिक नर्क हो, आप किसी भी परिणाम को अस्वीकार कर सकते हैं x>6, और आपको %6अब और आवश्यकता नहीं होगी ।
MSalters

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

3
मुझे यह जवाब पसंद आया। यह थोड़ा कठिन है, लेकिन इसे बहुत अच्छी पृष्ठभूमि की जानकारी मिली है। ध्यान रखें, वास्तविक विशेषज्ञ कभी हार्डवेयर यादृच्छिक जनरेटर का उपयोग करते हैं, समस्या यह है कि कठिन है।
Tiger4Hire

10
मेरे लिए यह उल्टा है। हालांकि इसमें अच्छी जानकारी होती है, लेकिन किसी भी चीज़ के बारे में राय के रूप में यह बहुत अधिक है। एक तरफ उपयोगिता।
मिस्टर लिस्टर

2

मैं किसी भी तरह से एक अनुभवी सी ++ उपयोगकर्ता नहीं हूं, लेकिन यह देखने के लिए दिलचस्पी थी कि क्या वास्तव में सही std::rand()/((RAND_MAX + 1u)/6)होने की तुलना 1+std::rand()%6में कम पक्षपाती होने के बारे में अन्य उत्तर हैं । इसलिए मैंने दोनों तरीकों के परिणामों को सारणीबद्ध करने के लिए एक परीक्षण कार्यक्रम लिखा था (मैंने उम्र में C ++ नहीं लिखा है, कृपया इसे देखें)। कोड चलाने के लिए एक लिंक यहाँ पाया गया है । इसे निम्नानुसार पुन: प्रस्तुत किया गया है:

// Example program
#include <cstdlib>
#include <iostream>
#include <ctime>
#include <string>

int main()
{
    std::srand(std::time(nullptr)); // use current time as seed for random generator

    // Roll the die 6000000 times using the supposedly unbiased method and keep track of the results

    int results[6] = {0,0,0,0,0,0};

    // roll a 6-sided die 20 times
    for (int n=0; n != 6000000; ++n) {
        int x = 7;
        while(x > 6) 
            x = 1 + std::rand()/((RAND_MAX + 1u)/6);  // Note: 1+rand()%6 is biased

        results[x-1]++;
    }

    for (int n=0; n !=6; n++) {
        std::cout << results[n] << ' ';
    }

    std::cout << "\n";


    // Roll the die 6000000 times using the supposedly biased method and keep track of the results

    int results_bias[6] = {0,0,0,0,0,0};

    // roll a 6-sided die 20 times
    for (int n=0; n != 6000000; ++n) {
        int x = 7;
        while(x > 6) 
            x = 1 + std::rand()%6;

        results_bias[x-1]++;
    }

    for (int n=0; n !=6; n++) {
        std::cout << results_bias[n] << ' ';
    }
}

मैंने तब इसका आउटपुट लिया और chisq.testआर में फ़ंक्शन का उपयोग करके ची-स्क्वायर टेस्ट चलाने के लिए देखा कि क्या परिणाम उम्मीद से काफी अलग हैं। यह स्टैकएक्सचेंज प्रश्न ची फेयर टेस्ट टू डाई फेयरनेस का उपयोग करने के अधिक विवरण में जाता है: मैं कैसे परीक्षण कर सकता हूं कि क्या डाई फेयर है? । यहाँ कुछ रन के लिए परिणाम हैं:

> ?chisq.test
> unbias <- c(100150, 99658, 100319, 99342, 100418, 100113)
> bias <- c(100049, 100040, 100091, 99966, 100188, 99666 )

> chisq.test(unbias)

Chi-squared test for given probabilities

data:  unbias
X-squared = 8.6168, df = 5, p-value = 0.1254

> chisq.test(bias)

Chi-squared test for given probabilities

data:  bias
X-squared = 1.6034, df = 5, p-value = 0.9008

> unbias <- c(998630, 1001188, 998932, 1001048, 1000968, 999234 )
> bias <- c(1000071, 1000910, 999078, 1000080, 998786, 1001075   )
> chisq.test(unbias)

Chi-squared test for given probabilities

data:  unbias
X-squared = 7.051, df = 5, p-value = 0.2169

> chisq.test(bias)

Chi-squared test for given probabilities

data:  bias
X-squared = 4.319, df = 5, p-value = 0.5045

> unbias <- c(998630, 999010, 1000736, 999142, 1000631, 1001851)
> bias <- c(999803, 998651, 1000639, 1000735, 1000064,1000108)
> chisq.test(unbias)

Chi-squared test for given probabilities

data:  unbias
X-squared = 7.9592, df = 5, p-value = 0.1585

> chisq.test(bias)

Chi-squared test for given probabilities

data:  bias
X-squared = 2.8229, df = 5, p-value = 0.7273

मेरे द्वारा किए गए तीन रनों में, दोनों तरीकों के लिए पी-वैल्यू हमेशा सामान्य अल्फा वैल्यू से अधिक था जो महत्व (0.05) का परीक्षण करने के लिए उपयोग किया जाता था। इसका मतलब है कि हम दोनों में से किसी को भी पक्षपाती नहीं मानेंगे। दिलचस्प है, माना जाता है कि निष्पक्ष तरीके से लगातार पी-मान कम होता है, जो बताता है कि यह वास्तव में अधिक पक्षपाती हो सकता है। यह कहते हुए कि मैंने केवल 3 रन बनाए।

अद्यतन: जब मैं अपना उत्तर लिख रहा था, कोनराड रूडोल्फ ने एक उत्तर पोस्ट किया जो समान दृष्टिकोण लेता है, लेकिन एक बहुत ही अलग परिणाम प्राप्त करता है। मेरे पास उसके उत्तर पर टिप्पणी करने की प्रतिष्ठा नहीं है, इसलिए मैं इसे यहाँ संबोधित करने जा रहा हूँ। सबसे पहले, मुख्य बात यह है कि वह जिस कोड का उपयोग करता है वह हर बार चलने वाले यादृच्छिक संख्या जनरेटर के लिए एक ही बीज का उपयोग करता है। यदि आप बीज को बदलते हैं, तो आपको वास्तव में कई प्रकार के परिणाम मिलते हैं। दूसरा, यदि आप बीज को नहीं बदलते हैं, लेकिन परीक्षण की संख्या को बदलते हैं, तो आपको कई प्रकार के परिणाम मिलते हैं। जो कुछ मेरा मतलब है उसे देखने के लिए परिमाण के क्रम से बढ़ाने या घटाने का प्रयास करें। तीसरा, कुछ पूर्णांक ट्रंकेशन या राउंडिंग चल रहा है जहां अपेक्षित मान बिल्कुल सटीक नहीं हैं। यह शायद एक अंतर बनाने के लिए पर्याप्त नहीं है, लेकिन यह वहाँ है।

मूल रूप से, संक्षेप में, वह सिर्फ सही बीज और परीक्षणों की संख्या प्राप्त करने के लिए हुआ था कि वह एक गलत परिणाम प्राप्त कर सकता है।


आपका कार्यान्वयन अपनी ओर से एक गलतफहमी के कारण एक मिथ्या दोष शामिल हैं: उद्धृत पारित होने है नहीं की तुलना rand()%6के साथ rand()/(1+RAND_MAX)/6। बल्कि, यह शेष को अस्वीकृति नमूना लेने के साथ तुलना कर रहा है (स्पष्टीकरण के लिए अन्य उत्तर देखें)। नतीजतन, आपका दूसरा कोड गलत है ( whileलूप कुछ नहीं करता है)। आपके सांख्यिकीय परीक्षण में भी समस्याएं हैं (आप मजबूती के लिए अपने परीक्षण के दोहराव को नहीं चला सकते, आपने सुधार नहीं किया, ...)।
कोनराड रुडोल्फ

1
@KonradRudolph मुझे आपके उत्तर पर टिप्पणी करने का निरसन नहीं है, इसलिए मैंने इसे एक अद्यतन के रूप में खदान में जोड़ा। आपका यह भी एक घातक दोष है कि यह एक सेट बीज और हर परीक्षण की संख्या का उपयोग करने के लिए होता है जो एक गलत परिणाम देता है। यदि आप विभिन्न बीजों के साथ दोहराए गए थे, तो आप इसे पकड़ सकते हैं। लेकिन हाँ, आप सही हैं जबकि लूप कुछ नहीं करता है, लेकिन यह उस विशेष कोड ब्लॉक के परिणामों को भी नहीं बदलता है
आजमा

मैं वास्तव में दोहराता था। बीज जानबूझकर सेट नहीं किया गया है क्योंकि std::srand(और कोई उपयोग नहीं <random>) के साथ एक यादृच्छिक बीज सेट करने के लिए मानकों के अनुरूप तरीके से करना काफी कठिन है और मैं नहीं चाहता था कि इसकी जटिलता शेष कोड से अलग हो जाए। यह गणना के लिए भी अप्रासंगिक है: एक सिमुलेशन में एक ही क्रम को दोहराना पूरी तरह से स्वीकार्य है। बेशक विभिन्न बीज होगा अलग परिणाम है, और कुछ गैर-महत्वपूर्ण हो जाएगा। यह पूरी तरह से उम्मीद है कि पी-मूल्य कैसे परिभाषित किया गया है।
कोनराड रूडोल्फ

1
चूहों, मैंने अपने दोहराव में गलती की; और आप सही हैं, रिपीट रनों का ९ ५ वाँ भाग p = ०.०५ के काफी करीब है - यानी ठीक उसी तरह जिसकी हम तब तक उम्मीद करेंगे। संक्षेप में, मेरे मानक पुस्तकालय में std::randपैदावार का अच्छा क्रम यादृच्छिक रूप से डी 6 के लिए सिमुलेशन, यादृच्छिक बीजों की सीमा के पार है।
कोनराड रूडोल्फ

1
सांख्यिकीय महत्व कहानी का केवल एक हिस्सा है। आपके पास एक शून्य परिकल्पना (समान रूप से वितरित) और एक वैकल्पिक परिकल्पना (मोडुलो पूर्वाग्रह) है - वास्तव में, वैकल्पिक परिकल्पनाओं का एक परिवार RAND_MAX, जिसकी पसंद के आधार पर अनुक्रमित किया गया है , जो कि मोडुलस पूर्वाग्रह के प्रभाव का आकार निर्धारित करता है । सांख्यिकीय महत्व शून्य परिकल्पना के तहत संभावना है कि आप इसे गलत तरीके से अस्वीकार करते हैं। सांख्यिकीय शक्ति क्या है - एक वैकल्पिक परिकल्पना के तहत संभावना है कि आपका परीक्षण शून्य परिकल्पना को सही ढंग से अस्वीकार करता है? क्या आप rand() % 6इस तरह का पता लगाएंगे जब RAND_MAX = 2 ^ 31 - 1?
स्क्वीमिश ओसफ्रीज

2

द्विआधारी अंकों की एक धारा पर काम करने के रूप में एक यादृच्छिक संख्या जनरेटर के बारे में सोच सकते हैं। जेनरेटर धारा को टुकड़ों में काटकर संख्या में बदल देता है। यदि std:randफ़ंक्शन RAND_MAX32767 के साथ काम कर रहा है , तो यह प्रत्येक स्लाइस में 15 बिट्स का उपयोग कर रहा है।

जब कोई ० और ३२ inc६ number के बीच किसी संख्या के मॉड्यूल को लेता है, तो वह पाता है कि ५४६२ 'का ० और' १ का, लेकिन केवल ५४६१ 'का २,' ३ का,'s का ४, और '5 का है। इसलिए परिणाम पक्षपाती है। RAND_MAX मान जितना बड़ा होगा, उतना ही कम पक्षपात होगा, लेकिन यह अपरिहार्य है।

जो पक्षपाती नहीं है, वह [0 .. (2 ^ n) -1] श्रेणी की एक संख्या है। आप 3 बिट्स निकालकर, 0. 0. रेंज में (सैद्धांतिक रूप से) बेहतर संख्या उत्पन्न कर सकते हैं, उन्हें सीमा में एक पूर्णांक में परिवर्तित करके 0..7 और 6 और 7 को अस्वीकार कर सकते हैं।

एक उम्मीद करता है कि बिट स्ट्रीम में हर बिट के पास '0' या '1' होने का एक समान मौका है, भले ही वह स्ट्रीम में हो या अन्य बिट्स के मान हो। यह अभ्यास में असाधारण रूप से कठिन है। सॉफ्टवेयर PRNGs के कई अलग-अलग कार्यान्वयन गति और गुणवत्ता के बीच अलग-अलग समझौता करते हैं। std::randसबसे कम गुणवत्ता के लिए सबसे तेज गति प्रदान करता है जैसे एक रैखिक बधाई जनरेटर । एक क्रिप्टोग्राफिक जनरेटर न्यूनतम गति के लिए उच्चतम गुणवत्ता प्रदान करता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.