किसी श्रेणी के भीतर से एक यादृच्छिक पूर्णांक संख्या कैसे उत्पन्न करें


108

यह पहले से पोस्ट किए गए प्रश्न का अनुसरण है:

सी में एक यादृच्छिक संख्या कैसे उत्पन्न करें?

मैं एक विशेष श्रेणी के भीतर से एक यादृच्छिक संख्या उत्पन्न करने में सक्षम होना चाहता हूं, जैसे कि 1 से 6 एक मरने के पक्ष की नकल करना।

मैं ऐसा कैसे कर पाऊंगा?


3
यदि आप इस प्रश्न का दूसरा उत्तर देखते हैं तो आपके पास इसका उत्तर है। रैंड ()% 6.
मैट फ्रेडरिकसन

2
मुझे समझ नहीं आया कि यह कैसे काम करता है, इसलिए मैंने स्पष्टता के लिए एक अलग प्रश्न बनाने का फैसला किया।
जेमी कीलिंग

2
यादृच्छिक विचार: यदि आपने प्रोग्रामर का एक यादृच्छिक क्रॉस-सेक्शन चुना है, तो आप पाएंगे कि उनमें से एक यादृच्छिक संख्या यादृच्छिक रूप से संख्याओं को उत्पन्न करने के तरीकों के बारे में बेतरतीब ढंग से सोच रही है। ब्रह्मांड को ध्यान में रखते हुए सटीक और अनुमानित कानूनों द्वारा शासित किया जाता है, क्या यह दिलचस्प नहीं है कि हम चीजों को अधिक यादृच्छिक रूप से उत्पन्न करने की कोशिश करते हैं? इस तरह के सवाल हमेशा 10k + पोस्टर को सामने लाते हैं।
आर्मस्ट्रांगेस्ट

2
@ माट्स रैंड ()% 6 वापस कर सकते हैं 0. एक मरने के लिए अच्छा नहीं है।
new123456

क्या आप इसके लिंक के जवाब के बजाय स्वीकृत जवाब के रूप में stackoverflow.com/a/6852396/419 को चिह्नित कर सकते हैं :) धन्यवाद।
केव

जवाबों:


173

अब तक के सभी उत्तर गणितीय रूप से गलत हैं। रिटर्निंग rand() % Nएक समान रूप से रेंज में एक नंबर नहीं देता है [0, N)जब तक Nकि अंतराल की लंबाई को विभाजित नहीं करता है जिसमें rand()रिटर्न (यानी 2 की शक्ति) है। इसके अलावा, किसी को भी पता नहीं है कि क्या rand()स्वतंत्र हैं: यह संभव है कि वे जाएं 0, 1, 2, ..., जो एक समान हो लेकिन बहुत यादृच्छिक न हो। एकमात्र धारणा जिसे बनाना उचित लगता है, वह यह है कि rand()एक पॉइसन वितरण होता है: समान आकार के कोई भी दो नॉनओवरलैपिंग सबइंटरवल समान रूप से संभावित और स्वतंत्र होते हैं। मूल्यों के एक निश्चित सेट के लिए, यह एक समान वितरण का तात्पर्य करता है और यह भी सुनिश्चित करता है कि मूल्य rand()अच्छी तरह से बिखरे हुए हैं।

इसका मतलब यह है कि सीमा को बदलने का एकमात्र सही तरीका rand()इसे बक्से में विभाजित करना है; उदाहरण के लिए, यदि RAND_MAX == 11और आप एक सीमा चाहते हैं 1..6, तो आपको {0,1}1, {2,3}2, और इसी तरह से असाइन करना चाहिए । ये असमान हैं, समान रूप से अंतराल हैं और इस प्रकार समान रूप से और स्वतंत्र रूप से वितरित किए जाते हैं।

फ्लोटिंग-पॉइंट डिवीजन का उपयोग करने का सुझाव गणितीय रूप से प्रशंसनीय है, लेकिन सिद्धांत रूप में गोल मुद्दों से ग्रस्त है। शायद doubleयह काम करने के लिए उच्च-पर्याप्त परिशुद्धता है; शायद नहीं। मैं नहीं जानता और मुझे इसका पता नहीं लगाना है; किसी भी मामले में, जवाब प्रणाली पर निर्भर है।

सही तरीका पूर्णांक अंकगणित का उपयोग करना है। यही है, आप निम्नलिखित की तरह कुछ चाहते हैं:

#include <stdlib.h> // For random(), RAND_MAX

// Assumes 0 <= max <= RAND_MAX
// Returns in the closed interval [0, max]
long random_at_most(long max) {
  unsigned long
    // max <= RAND_MAX < ULONG_MAX, so this is okay.
    num_bins = (unsigned long) max + 1,
    num_rand = (unsigned long) RAND_MAX + 1,
    bin_size = num_rand / num_bins,
    defect   = num_rand % num_bins;

  long x;
  do {
   x = random();
  }
  // This is carefully written not to overflow
  while (num_rand - defect <= (unsigned long)x);

  // Truncated division is intentional
  return x/bin_size;
}

लूप पूरी तरह से समान वितरण प्राप्त करने के लिए आवश्यक है। उदाहरण के लिए, यदि आपको 0 से 2 तक रैंडम नंबर दिए गए हैं और आप केवल 0 से 1 तक ही चाहते हैं, तो आप बस तब तक खींचते रहेंगे जब तक आपको 2 नहीं मिलते; यह जांचना मुश्किल नहीं है कि यह समान संभावना के साथ 0 या 1 देता है। इस पद्धति का वर्णन उस लिंक में भी किया गया है, जो उनके उत्तर में दिया गया था, हालांकि अलग तरीके से कोडित किया गया था। मैं इसके random()बजाय उपयोग कर रहा हूं rand()क्योंकि इसका बेहतर वितरण है (जैसा कि मैन पेज के लिए नोट किया गया है rand())।

यदि आप डिफ़ॉल्ट रेंज के बाहर यादृच्छिक मान प्राप्त करना चाहते हैं [0, RAND_MAX], तो आपको कुछ मुश्किल करना होगा। शायद सबसे समीचीन एक समारोह को परिभाषित करने के लिए है random_extended()कि खींचती nबिट्स (का उपयोग कर random_at_most()में) और रिटर्न [0, 2**n), और फिर लागू random_at_most()साथ random_extended()के स्थान पर random()(और 2**n - 1के स्थान पर RAND_MAX) की तुलना में कम एक यादृच्छिक मूल्य खींचने के लिए 2**n, यह सोचते हैं आप एक संख्यात्मक प्रकार है कि इस तरह के पकड़ कर सकते हैं एक कीमत। अंत में, निस्संदेह, आप नकारात्मक मूल्यों सहित, [min, max]उपयोग करने में मान प्राप्त कर सकते हैं min + random_at_most(max - min)


1
@Adam Rosenfield, @ Ryan Reich: एक संबंधित प्रश्न में जहाँ एडम ने उत्तर दिया था: stackoverflow.com/questions/137783/… सबसे अधिक उत्तर दिया गया उत्तर: 'मापांक' का उपयोग तब गलत होगा, नहीं? 1..21 से 1..7 उत्पन्न करने के लिए, रयान ने जिस प्रक्रिया का वर्णन किया है, उसका उपयोग किया जाना चाहिए। कृपया मुझे गलत होने पर सही करें।
अरविंद

1
आगे की समीक्षा पर, यहां एक और मुद्दा यह है कि यह तब काम नहीं करेगा max - min > RAND_MAX, जब मैं ऊपर बताए गए मुद्दे से अधिक गंभीर हो (उदाहरण के लिए वीसी ++ में RAND_MAXकेवल 32767 है)।
इंटरजेड

2
जबकि लूप को अधिक पठनीय बनाया जा सकता है। सशर्त में असाइनमेंट करने के बजाय, आप शायद ए चाहते हैं do {} while()
theJPster

4
अरे, यह उत्तर धूमकेतु ओएस पुस्तक द्वारा उद्धृत किया गया है;) पहली बार मैं एक शिक्षण पुस्तक में देखता हूं
vpuente

3
इसे OSTEP किताब में भी उद्धृत किया गया है :) Pages.cs.wisc.edu/~remzi/OSTEP (अध्याय 9, पृष्ठ 4)
rafascar

33

@ रेयान रीच के जवाब के बाद, मैंने सोचा कि मैं अपना क्लीन अप संस्करण पेश करूंगा। पहले सीमा की जाँच के लिए दूसरी सीमा की जाँच की आवश्यकता नहीं है, और मैंने इसे पुनरावृत्ति के बजाय पुनरावृत्त बना दिया है। यह श्रेणी [न्यूनतम, अधिकतम], जहां max >= minऔर में मान लौटाता है 1+max-min < RAND_MAX

unsigned int rand_interval(unsigned int min, unsigned int max)
{
    int r;
    const unsigned int range = 1 + max - min;
    const unsigned int buckets = RAND_MAX / range;
    const unsigned int limit = buckets * range;

    /* Create equal size buckets all in a row, then fire randomly towards
     * the buckets until you land in one of them. All buckets are equally
     * likely. If you land off the end of the line of buckets, try again. */
    do
    {
        r = rand();
    } while (r >= limit);

    return min + (r / buckets);
}

28
ध्यान दें कि यह अनंत लूप में फंस जाएगा यदि रेंज> = RAND_MAX। मुझसे पूछें कि मुझे कैसे पता है: /
theJPster

24
आपको कैसे मालूम!?
शानदार श्री फॉक्स

1
ध्यान दें कि आप एक int से अहस्ताक्षरित int (r> = limit) की तुलना कर रहे हैं। < और <= के बाद से limitएक इंट (और वैकल्पिक रूप से bucketभी) बनाकर समस्या को आसानी से हल किया जाता है । संपादित करें: मैंने प्रस्ताव प्रस्तुत और संपादित किया है। RAND_MAX / rangeINT_MAXbuckets * rangeRAND_MAX
rrrrrrrrrrrrrrrrrr

@ रेयान रीच का समाधान अभी भी मुझे बेहतर (कम पक्षपाती) वितरण देता है
व्लादिमीर

20

यदि आप किसी सीमा का अधिकतम और न्यूनतम मान जानते हैं, तो यह एक सूत्र है, और आप श्रेणी के बीच में समावेशी संख्याएँ उत्पन्न करना चाहते हैं:

r = (rand() % (max + 1 - min)) + min

9
जैसा कि रेयान के जवाब में कहा गया है, यह एक पक्षपाती परिणाम पैदा करता है।
डेविड वूल्वर

6
बायस्ड परिणाम, संभावित intअतिप्रवाह max+1-min
chux -

1
यह केवल पूर्णांक मिनट और अधिकतम के साथ काम करता है। यदि न्यूनतम और अधिकतम फ्लोट हैं, तो% ऑपरेशन करना संभव नहीं है
ताइओली फ्रांसेस्को

17
unsigned int
randr(unsigned int min, unsigned int max)
{
       double scaled = (double)rand()/RAND_MAX;

       return (max - min +1)*scaled + min;
}

अन्य विकल्पों के लिए यहां देखें ।


2
@ एस.लॉट - वास्तव में नहीं। प्रत्येक थोड़ा अलग-अलग-अलग मामलों को अलग-अलग वितरित करता है, बस इतना ही। दोहरा गणित यह आभास देता है कि वहां अधिक सटीकता है, लेकिन आप आसानी से उपयोग कर सकते हैं (((max-min+1)*rand())/RAND_MAX)+minऔर संभवत: सटीक समान वितरण प्राप्त कर सकते हैं (यह मानते हुए कि RAND_MAX अतिप्रवाहित नहीं होने के सापेक्ष बहुत छोटा है)।
173 पर स्टीव 314

4
यह थोड़ा खतरनाक है: इसके लिए (बहुत कम ही) वापसी संभव है max + 1, यदि या तो rand() == RAND_MAX, या rand()बहुत करीब है RAND_MAXऔर फ्लोटिंग-पॉइंट त्रुटियां अंतिम परिणाम अतीत को धक्का देती हैं max + 1। सुरक्षित होने के लिए, आपको यह देखना चाहिए कि परिणाम इसे वापस करने से पहले सीमा के भीतर है।
मार्क डिकिंसन

1
@ क्रिसटोफ: मैं इसके बारे में सहमत हूं RAND_MAX + 1.0। मुझे अभी भी यकीन नहीं है कि max + 1वापसी को रोकने के लिए यह काफी अच्छा है , हालांकि: विशेष रूप से, + minअंत में एक दौर शामिल है जो max + 1रैंड के बड़े मूल्यों के लिए उत्पादन को समाप्त कर सकता है ()। इस दृष्टिकोण को पूरी तरह से छोड़ दें और पूर्णांक अंकगणितीय का उपयोग करें।
मार्क डिकिंसन

3
यदि क्रिस्टोफ RAND_MAXद्वारा RAND_MAX+1.0सुझाए गए अनुसार प्रतिस्थापित किया जाता है, तो मेरा मानना ​​है कि यह सुरक्षित है बशर्ते कि + minपूर्णांक अंकगणितीय का उपयोग करके किया जाए return (unsigned int)((max - min + 1) * scaled) + min:। (गैर स्पष्ट) कारण यह है कि यहां तक कि दौर से डेढ़-टू-, (और यह भी कि यह सोचते हैं आईईईई 754 गणित और है max - min + 1है एक डबल के रूप में वास्तव में प्रदर्शनीय, लेकिन यह एक ठेठ मशीन पर सच हो जाएगा), यह हमेशा सच है कि x * scaled < xके लिए किसी भी सकारात्मक डबल xऔर किसी भी डबल scaledसंतोषजनक 0.0 <= scaled && scaled < 1.0
मार्क डिकिंसन

1
के लिए विफल randr(0, UINT_MAX): हमेशा 0. उत्पन्न करता है
chux -

12

क्या आप ऐसा नहीं करेंगे:

srand(time(NULL));
int r = ( rand() % 6 ) + 1;

%मापांक ऑपरेटर है। अनिवार्य रूप से यह सिर्फ 6 से विभाजित होगा और शेष ... 0 - 5 से वापस करेगा


1
यह 1 से परिणाम देगा - 6. यही वह + 1 है जिसके लिए है।
आर्मस्ट्रांगेस्ट

4
साइमन, मुझे कहीं भी उपयोग में एक लिबास दिखाएं rand()जिसमें जनरेटर की स्थिति के कम-क्रम वाले बिट्स शामिल हैं (यदि यह एक एलसीजी का उपयोग करता है)। मैंने अब तक एक भी नहीं देखा है - उनमें से सभी (हाँ, जिसमें RVC_MAX के साथ MSVC सिर्फ 32767 है) कम-ऑर्डर बिट्स को हटा दें । अन्य कारणों से मापांक का उपयोग करने की अनुशंसा नहीं की जाती है, अर्थात् यह वितरण को छोटी संख्या के पक्ष में करता है।
जोए

@ जोहान्स: तो यह कहना सुरक्षित है कि स्लॉट मशीन मापांक का उपयोग नहीं करती हैं?
आर्मस्ट्रांगेस्ट

मैं 0 को कैसे छोड़ूंगा? ऐसा लगता है कि अगर मैं इसे 30 के लूप में चलाता हूं, तो शायद यह दूसरी या तीसरी बार चलता है, इसमें लगभग 0 रास्ता है। क्या यह किसी प्रकार की लपट है?
जेमी कीलिंग

@ जोहान्स: शायद यह आजकल इतना मुद्दा नहीं है, लेकिन परंपरागत रूप से कम-ऑर्डर बिट्स का उपयोग करना उचित नहीं है। c-faq.com/lib/randrange.html
jamesdlin

9

उन लोगों के लिए जो पूर्वाग्रह की समस्या को समझते हैं, लेकिन अस्वीकृति-आधारित विधियों के अप्रत्याशित रन-टाइम को बर्दाश्त नहीं कर सकते, यह श्रृंखला [0, n-1]अंतराल में उत्तरोत्तर कम पक्षपातपूर्ण यादृच्छिक पूर्णांक पैदा करती है :

r = n / 2;
r = (rand() * n + r) / (RAND_MAX + 1);
r = (rand() * n + r) / (RAND_MAX + 1);
r = (rand() * n + r) / (RAND_MAX + 1);
...

यह i * log_2(RAND_MAX + 1)बिट्स (जहां iपुनरावृत्तियों की संख्या है) के एक उच्च-सटीक निश्चित-बिंदु यादृच्छिक संख्या का संश्लेषण करके और एक लंबे गुणा का प्रदर्शन करके ऐसा करता है n

जब बिट्स की संख्या पर्याप्त रूप से बड़ी होती है n, तो पूर्वाग्रह बहुत छोटा हो जाता है।

इससे कोई फर्क नहीं पड़ता कि RAND_MAX + 1क्या n( इस प्रश्न के अनुसार ) से कम है , या यदि यह दो की शक्ति नहीं है, लेकिन RAND_MAX * nबड़े होने पर पूर्णांक अतिप्रवाह से बचने के लिए देखभाल की जानी चाहिए ।


2
RAND_MAXअक्सर होता है INT_MAX, इसलिए RAND_MAX + 1-> UB (जैसे INT_MIN)
chux -

@chux का मतलब है कि " RAND_MAX * nबड़े होने पर पूर्णांक अतिप्रवाह से बचने के लिए देखभाल की जानी चाहिए "। आपको अपनी आवश्यकताओं के लिए उपयुक्त प्रकारों का उपयोग करने की व्यवस्था करने की आवश्यकता है।
sh1

@chux " RAND_MAXअक्सर INT_MAX" हाँ, लेकिन केवल 16 बिट सिस्टम पर! किसी भी कारण से आधुनिक आर्किटेकचर INT_MAX2 ^ 32/2 और 2 ^ 16/2 पर रखा जाएगा RAND_MAX। क्या यह गलत धारणा है?
बिल्ली

2
@ टैट ने आज 2 32-बिट intसंकलक का परीक्षण किया , मुझे RAND_MAX == 32767एक RAND_MAX == 2147483647पर और दूसरे पर मिला । मेरा समग्र अनुभव (दशकों) वह RAND_MAX == INT_MAXअधिक बार है। तो इससे सहमत नहीं है कि एक यथोचित आधुनिक 32-बिट संरचना निश्चित रूप से एक होगा RAND_MAXपर 2^16 / 2। चूंकि सी कल्पना की अनुमति देता है 32767 <= RAND_MAX <= INT_MAX, मैं प्रवृत्ति के बजाय उस रास्ते को कोड करता हूं।
चक्स - मोनिका

3
फिर भी "पूर्णांक से बचने के लिए देखभाल की जानी चाहिए"।
sh1

4

मोडुलो पूर्वाग्रह (अन्य उत्तरों में सुझाए गए) से बचने के लिए आप हमेशा उपयोग कर सकते हैं:

arc4random_uniform(MAX-MIN)+MIN

जहाँ "MAX" ऊपरी बाउंड है और "MIN" कम बाउंड है। उदाहरण के लिए, 10 और 20 के बीच की संख्याओं के लिए:

arc4random_uniform(20-10)+10

arc4random_uniform(10)+10

सरल उपाय और "रैंड ()% एन" का उपयोग करने से बेहतर है।


1
वूहू, यह अन्य उत्तरों की तुलना में एक अरब गुना बेहतर है। #include <bsd/stdlib.h>सबसे पहले आपको ध्यान देने योग्य है । इसके अलावा, किसी भी विचार कैसे बिना MinGW या CygWin के साथ विंडोज पर प्राप्त करने के लिए?
बिल्ली

1
नहीं, यह अन्य उत्तरों की तुलना में बेहतर नहीं है, क्योंकि अन्य उत्तर अधिक सामान्य हैं। यहां आप arc4random तक सीमित हैं, अन्य उत्तर आपको एक अलग यादृच्छिक स्रोत चुनने, विभिन्न संख्या-प्रकारों के साथ काम करने की अनुमति देते हैं ... और अंतिम लेकिन कम से कम वे किसी को समस्या को समझने में मदद कर सकते हैं। यह मत भूलो कि प्रश्न अन्य लोगों के लिए भी दिलचस्प है, जिनकी कुछ विशेष आवश्यकताएं हो सकती हैं या आर्क 4 आयामी तक पहुंच नहीं हो सकती है ... फिर भी, यदि आपके पास इसकी पहुंच है और त्वरित समाधान चाहते हैं, तो यह वास्तव में एक बहुत अच्छा जवाब है
के। बियर्मन

4

यहाँ रेयान रीच के समाधान की तुलना में थोड़ा सरल एल्गोरिथ्म है:

/// Begin and end are *inclusive*; => [begin, end]
uint32_t getRandInterval(uint32_t begin, uint32_t end) {
    uint32_t range = (end - begin) + 1;
    uint32_t limit = ((uint64_t)RAND_MAX + 1) - (((uint64_t)RAND_MAX + 1) % range);

    /* Imagine range-sized buckets all in a row, then fire randomly towards
     * the buckets until you land in one of them. All buckets are equally
     * likely. If you land off the end of the line of buckets, try again. */
    uint32_t randVal = rand();
    while (randVal >= limit) randVal = rand();

    /// Return the position you hit in the bucket + begin as random number
    return (randVal % range) + begin;
}

Example (RAND_MAX := 16, begin := 2, end := 7)
    => range := 6  (1 + end - begin)
    => limit := 12 (RAND_MAX + 1) - ((RAND_MAX + 1) % range)

The limit is always a multiple of the range,
so we can split it into range-sized buckets:
    Possible-rand-output: 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16
    Buckets:             [0, 1, 2, 3, 4, 5][0, 1, 2, 3, 4, 5][X, X, X, X, X]
    Buckets + begin:     [2, 3, 4, 5, 6, 7][2, 3, 4, 5, 6, 7][X, X, X, X, X]

1st call to rand() => 13
     13 is not in the bucket-range anymore (>= limit), while-condition is true
         retry...
2nd call to rand() => 7
     7 is in the bucket-range (< limit), while-condition is false
         Get the corresponding bucket-value 1 (randVal % range) and add begin
    => 3

1
RAND_MAX + 1आसानी से अतिप्रवाह intजोड़ सकते हैं । उस स्थिति में, (RAND_MAX + 1) % rangeसंदिग्ध परिणाम उत्पन्न करेगा। विचार करें(RAND_MAX + (uint32_t)1)
chux -

2

जबकि रयान सही है, यादृच्छिकता के स्रोत के बारे में जो ज्ञात है, उसके आधार पर समाधान बहुत सरल हो सकता है। समस्या को फिर से बताने के लिए:

  • यादृच्छिकता का एक स्रोत है, [0, MAX)समान वितरण के साथ पूर्णांक संख्याओं को आउटपुट करना ।
  • लक्ष्य रेंज में समान रूप से वितरित यादृच्छिक पूर्णांक संख्या का उत्पादन होता है [rmin, rmax], जहां 0 <= rmin < rmax < MAX

मेरे अनुभव में, यदि डिब्बे की संख्या (या "बक्से") मूल संख्याओं की सीमा से काफी कम है, और मूल स्रोत क्रिप्टोग्राफिक रूप से मजबूत है - तो उस सभी कठोरता, और सरल मोड्यूलर डिवीजन से गुजरने की कोई आवश्यकता नहीं है प्रत्यय (जैसे output = rnd.next() % (rmax+1), यदि rmin == 0), और यादृच्छिक संख्याएं उत्पन्न होती हैं जो समान रूप से "पर्याप्त" वितरित की जाती हैं, और गति के किसी भी नुकसान के बिना। मुख्य कारक यादृच्छिकता स्रोत है (यानी, बच्चों, घर पर यह कोशिश मत करो rand())।

यहाँ एक उदाहरण / प्रमाण है कि यह व्यवहार में कैसे काम करता है। मैं 1 से 22 तक यादृच्छिक संख्या उत्पन्न करना चाहता था, जिसमें क्रिप्टोग्राफिक रूप से मजबूत स्रोत था जो यादृच्छिक बाइट्स (इंटेल RDRAND के आधार पर) का उत्पादन करता था। परिणाम हैं:

Rnd distribution test (22 boxes, numbers of entries in each box):     
 1: 409443    4.55%
 2: 408736    4.54%
 3: 408557    4.54%
 4: 409125    4.55%
 5: 408812    4.54%
 6: 409418    4.55%
 7: 408365    4.54%
 8: 407992    4.53%
 9: 409262    4.55%
10: 408112    4.53%
11: 409995    4.56%
12: 409810    4.55%
13: 409638    4.55%
14: 408905    4.54%
15: 408484    4.54%
16: 408211    4.54%
17: 409773    4.55%
18: 409597    4.55%
19: 409727    4.55%
20: 409062    4.55%
21: 409634    4.55%
22: 409342    4.55%   
total: 100.00%

यह मेरे उद्देश्य के लिए समान रूप से समान है, जैसे कि मुझे अपने उद्देश्य (उचित पासा फेंक, WWII सिफर मशीनों जैसे http://users.telenet.be/d.rijmenants/en/kl-7sim.htm , आदि के लिए क्रिप्टोग्राफिक रूप से मजबूत कोडबुक बनाने की आवश्यकता है) )। आउटपुट कोई प्रशंसनीय पूर्वाग्रह नहीं दिखाता है।

यहाँ क्रिप्टोग्राफिकली स्ट्रॉन्ग (ट्रू) रैंडम नंबर जेनरेटर का स्रोत है: इंटेल डिजिटल रैंडम नंबर जेनरेटर और एक सैंपल कोड जो 64-बिट (अहस्ताक्षरित) रैंडम नंबर का उत्पादन करता है।

int rdrand64_step(unsigned long long int *therand)
{
  unsigned long long int foo;
  int cf_error_status;

  asm("rdrand %%rax; \
        mov $1,%%edx; \
        cmovae %%rax,%%rdx; \
        mov %%edx,%1; \
        mov %%rax, %0;":"=r"(foo),"=r"(cf_error_status)::"%rax","%rdx");
        *therand = foo;
  return cf_error_status;
}

मैंने इसे clang-6.0.1 (स्ट्रेट), और gcc-4.8.3 के साथ "-Wa, q" फ्लैग (क्योंकि GAS इन नए निर्देशों का समर्थन नहीं करता है) के साथ मैक OS X पर संकलित किया।


gcc randu.c -o randu -Wa,q(GCC 5.3.1 उबंटू 16 पर) के साथ संकलित या clang randu.c -o randu(क्लैंग 3.8.0) काम करता है, लेकिन रनटाइम पर कोर को डंप करता है Illegal instruction (core dumped)। कोई विचार?
बिल्ली

सबसे पहले, मुझे नहीं पता कि आपका CPU वास्तव में RDRAND निर्देश का समर्थन करता है या नहीं। आपका OS काफी हाल ही में है, लेकिन सीपीयू नहीं हो सकता है। दूसरा (लेकिन इसकी संभावना कम है) - मुझे नहीं पता कि किस तरह के कोडांतरक उबंटू में शामिल हैं (और उबंटू काफी आगे की तरफ बढ़ता है। रिट पैकेज अपडेट कर रहा है)। अपने सीपीयू RDRAND का समर्थन करता है या नहीं, यह जांचने के लिए मैंने जिस इंटेल साइट का उल्लेख किया है, उसकी जांच करें।
माउस

आपके पास वास्तव में अच्छे अंक हैं। जो मुझे अभी भी नहीं मिल रहा है वह इतना गलत है rand()। मैंने कुछ परीक्षणों की कोशिश की और इस प्रश्न को पोस्ट किया लेकिन मुझे अभी तक कोई निश्चित उत्तर नहीं मिला है।
मिरादियो

1

जैसा कि मॉडुलो के पहले कहा गया था, क्योंकि यह वितरण को सीमित नहीं करता है। मेरे कोड का उपयोग करता है जो बिट्स को मास्क करता है और यह सुनिश्चित करने के लिए उनका उपयोग करता है कि वितरण तिरछा नहीं है।

static uint32_t randomInRange(uint32_t a,uint32_t b) {
    uint32_t v;
    uint32_t range;
    uint32_t upper;
    uint32_t lower;
    uint32_t mask;

    if(a == b) {
        return a;
    }

    if(a > b) {
        upper = a;
        lower = b;
    } else {
        upper = b;
        lower = a; 
    }

    range = upper - lower;

    mask = 0;
    //XXX calculate range with log and mask? nah, too lazy :).
    while(1) {
        if(mask >= range) {
            break;
        }
        mask = (mask << 1) | 1;
    }


    while(1) {
        v = rand() & mask;
        if(v <= range) {
            return lower + v;
        }
    }

}

निम्नलिखित सरल कोड आपको वितरण को देखने देता है:

int main() {

    unsigned long long int i;


    unsigned int n = 10;
    unsigned int numbers[n];


    for (i = 0; i < n; i++) {
        numbers[i] = 0;
    }

    for (i = 0 ; i < 10000000 ; i++){
        uint32_t rand = random_in_range(0,n - 1);
        if(rand >= n){
            printf("bug: rand out of range %u\n",(unsigned int)rand);
            return 1;
        }
        numbers[rand] += 1;
    }

    for(i = 0; i < n; i++) {
        printf("%u: %u\n",i,numbers[i]);
    }

}

जब आप रैंड () से संख्या को अस्वीकार करते हैं तो काफी अक्षम हो जाता है। यह विशेष रूप से अक्षम होगा जब सीमा का आकार 2 ^ k + 1 के रूप में लिखा जा सकता है। फिर धीरे-धीरे रैंड () कॉल से आपके सभी प्रयासों के लगभग आधे को शर्त से खारिज कर दिया जाएगा। क्या यह RAND_MAX मोडुलो रेंज को शांत करने के लिए बेहतर हो सकता है। जैसे: v = rand(); if (v > RAND_MAX - (RAND_MAX % range) -> reject and try again; else return v % range;मैं समझता हूं कि मॉडुलो मास्किंग की तुलना में बहुत धीमा ऑपरेशन है, लेकिन मुझे अभी भी लगता है ..... इसका परीक्षण किया जाना चाहिए।
senystein Schønning-Johansen

rand()intसीमा में रिटर्न देता है [0..RAND_MAX]। यह श्रेणी आसानी से एक सबरेंज हो सकती है uint32_tऔर फिर randomInRange(0, ,b)रेंज में कभी भी मान उत्पन्न नहीं करती है (INT_MAX...b]
chux -

0

सीमा में एक अस्थायी बिंदु संख्या लौटाएगा [0,1]:

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