नया यादृच्छिक पुस्तकालय std :: rand () से बेहतर क्यों है?


82

इसलिए मैंने रैंड नामक एक बात देखी () हार्मफुल माना जाता है और यह सरल std::rand()प्लस मापांक प्रतिमान पर यादृच्छिक संख्या पीढ़ी के इंजन-वितरण प्रतिमान का उपयोग करने की वकालत करता है ।

हालाँकि, मैं std::rand()पहली बार असफलताओं को देखना चाहता था इसलिए मैंने एक त्वरित प्रयोग किया:

  1. असल में, मैं 2 कार्यों लिखा था getRandNum_Old()और getRandNum_New()उस का उपयोग कर के बीच 0 और 5 समावेशी एक यादृच्छिक संख्या उत्पन्न std::rand()और std::mt19937+ std::uniform_int_distributionक्रमशः।
  2. फिर मैंने "पुराने" तरीके का उपयोग करके 960,000 (6 से विभाज्य) यादृच्छिक संख्याओं को उत्पन्न किया और संख्याओं की आवृत्तियों को 0-5 दर्ज किया। फिर मैंने इन आवृत्तियों के मानक विचलन की गणना की। मैं जिस चीज की तलाश कर रहा हूं, वह मानक विचलन जितना संभव हो उतना कम है क्योंकि वितरण सही मायने में समान होने पर क्या होगा।
  3. मैंने उस सिमुलेशन को 1000 बार चलाया और प्रत्येक सिमुलेशन के लिए मानक विचलन दर्ज किया। मिलीसेकंड में लगने वाले समय को भी मैंने रिकॉर्ड किया।
  4. बाद में, मैंने फिर से वही किया लेकिन इस बार रैंडम नंबर्स को "नया" तरीका बनाया।
  5. अंत में, मैंने पुराने और नए तरीके दोनों के लिए मानक विचलन की सूची के माध्य और मानक विचलन की गणना की और पुराने और नए दोनों तरीके से लिए गए समय की सूची के लिए औसत और मानक विचलन।

यहाँ परिणाम थे:

[OLD WAY]
Spread
       mean:  346.554406
    std dev:  110.318361
Time Taken (ms)
       mean:  6.662910
    std dev:  0.366301

[NEW WAY]
Spread
       mean:  350.346792
    std dev:  110.449190
Time Taken (ms)
       mean:  28.053907
    std dev:  0.654964

हैरानी की बात है कि दोनों तरीकों के लिए रोल का कुल प्रसार समान था। Ie, std::mt19937+ std::uniform_int_distributionसाधारण std::rand()+ से "अधिक समान" नहीं था %। मैंने जो एक और अवलोकन किया, वह यह था कि नया पुराने तरीके से लगभग 4 गुना धीमा था। कुल मिलाकर, ऐसा लग रहा था कि मैं गुणवत्ता में लगभग कोई लाभ नहीं होने के लिए गति में भारी लागत चुका रहा हूं।

क्या मेरा प्रयोग किसी तरह से दोषपूर्ण है? या std::rand()वास्तव में वह बुरा नहीं है, और शायद बेहतर भी?

संदर्भ के लिए, यहाँ मैं अपनी संपूर्णता में प्रयुक्त कोड है:

#include <cstdio>
#include <random>
#include <algorithm>
#include <chrono>

int getRandNum_Old() {
    static bool init = false;
    if (!init) {
        std::srand(time(nullptr)); // Seed std::rand
        init = true;
    }

    return std::rand() % 6;
}

int getRandNum_New() {
    static bool init = false;
    static std::random_device rd;
    static std::mt19937 eng;
    static std::uniform_int_distribution<int> dist(0,5);
    if (!init) {
        eng.seed(rd()); // Seed random engine
        init = true;
    }

    return dist(eng);
}

template <typename T>
double mean(T* data, int n) {
    double m = 0;
    std::for_each(data, data+n, [&](T x){ m += x; });
    m /= n;
    return m;
}

template <typename T>
double stdDev(T* data, int n) {
    double m = mean(data, n);
    double sd = 0.0;
    std::for_each(data, data+n, [&](T x){ sd += ((x-m) * (x-m)); });
    sd /= n;
    sd = sqrt(sd);
    return sd;
}

int main() {
    const int N = 960000; // Number of trials
    const int M = 1000;   // Number of simulations
    const int D = 6;      // Num sides on die

    /* Do the things the "old" way (blech) */

    int freqList_Old[D];
    double stdDevList_Old[M];
    double timeTakenList_Old[M];

    for (int j = 0; j < M; j++) {
        auto start = std::chrono::high_resolution_clock::now();
        std::fill_n(freqList_Old, D, 0);
        for (int i = 0; i < N; i++) {
            int roll = getRandNum_Old();
            freqList_Old[roll] += 1;
        }
        stdDevList_Old[j] = stdDev(freqList_Old, D);
        auto end = std::chrono::high_resolution_clock::now();
        auto dur = std::chrono::duration_cast<std::chrono::microseconds>(end-start);
        double timeTaken = dur.count() / 1000.0;
        timeTakenList_Old[j] = timeTaken;
    }

    /* Do the things the cool new way! */

    int freqList_New[D];
    double stdDevList_New[M];
    double timeTakenList_New[M];

    for (int j = 0; j < M; j++) {
        auto start = std::chrono::high_resolution_clock::now();
        std::fill_n(freqList_New, D, 0);
        for (int i = 0; i < N; i++) {
            int roll = getRandNum_New();
            freqList_New[roll] += 1;
        }
        stdDevList_New[j] = stdDev(freqList_New, D);
        auto end = std::chrono::high_resolution_clock::now();
        auto dur = std::chrono::duration_cast<std::chrono::microseconds>(end-start);
        double timeTaken = dur.count() / 1000.0;
        timeTakenList_New[j] = timeTaken;
    }

    /* Display Results */

    printf("[OLD WAY]\n");
    printf("Spread\n");
    printf("       mean:  %.6f\n", mean(stdDevList_Old, M));
    printf("    std dev:  %.6f\n", stdDev(stdDevList_Old, M));
    printf("Time Taken (ms)\n");
    printf("       mean:  %.6f\n", mean(timeTakenList_Old, M));
    printf("    std dev:  %.6f\n", stdDev(timeTakenList_Old, M));
    printf("\n");
    printf("[NEW WAY]\n");
    printf("Spread\n");
    printf("       mean:  %.6f\n", mean(stdDevList_New, M));
    printf("    std dev:  %.6f\n", stdDev(stdDevList_New, M));
    printf("Time Taken (ms)\n");
    printf("       mean:  %.6f\n", mean(timeTakenList_New, M));
    printf("    std dev:  %.6f\n", stdDev(timeTakenList_New, M));
}

32
यही कारण है कि यह सलाह मौजूद है। यदि आप पर्याप्त एन्ट्रोपी के लिए RNG का परीक्षण करना नहीं जानते हैं या यह आपके प्रोग्राम के लिए मायने रखता है या नहीं, तो आपको यह मान लेना चाहिए कि std :: rand () पर्याप्त अच्छा नहीं है। en.wikipedia.org/wiki/Entropy_(computing)
हंस पैसेंट

4
चाहे rand()अच्छा-पर्याप्त हो, इसके बारे में नीचे की रेखा इस बात पर काफी हद तक निर्भर करती है कि आप किसके लिए यादृच्छिक संख्याओं के संग्रह का उपयोग कर रहे हैं। आपको एक विशेष प्रकार के यादृच्छिक वितरण की आवश्यकता है, फिर, निश्चित रूप से पुस्तकालय कार्यान्वयन बेहतर होगा। यदि आपको बस यादृच्छिक संख्याओं की आवश्यकता है और "यादृच्छिकता" के बारे में परवाह नहीं है या किस प्रकार का वितरण उत्पन्न होता है, तो rand()ठीक है। हाथ में काम करने के लिए उचित उपकरण का मिलान करें।
डेविड सी। रैंकिन

2
मुमकिन है डुबोना: stackoverflow.com/questions/52869166/… मैं सिर्फ इस एक को हथौड़ा नहीं करना चाहता, इसलिए मैं वास्तव में मतदान से बचना चाहता हूं।
बोलोव

18
for (i=0; i<k*n; i++) a[i]=i%n;वही सटीक माध्य और मानक विचलन पैदा करता है क्योंकि वहां से सबसे अच्छा आरएनजी निकलता है। यदि यह आपके आवेदन के लिए पर्याप्त है, तो बस इस क्रम का उपयोग करें।
एन। 'सर्वनाम' मी।

3
"मानक विचलन जितना संभव हो उतना कम" - नहीं। यह गलत है। आप उम्मीद करते हैं कि आवृत्तियाँ थोड़ी भिन्न होंगी - sqrt (फ़्रीक्वेंसी) के बारे में जो आप मानक विचलन होने की अपेक्षा करते हैं। "इंक्रीमेंटिंग काउंटर" जो nm निर्मित है, उसमें बहुत कम एसडी होगा (और यह बहुत खराब है)।
मार्टिन बोनर

जवाबों:


106

"पुराने" के बहुत से किसी भी कार्यान्वयन में एलसीजी काrand() उपयोग होता है ; जब वे आम तौर पर आसपास के सबसे अच्छे जनरेटर नहीं होते हैं, तो आमतौर पर आप उन्हें इस तरह के मूल परीक्षण में विफल होते नहीं देख रहे होते हैं - मतलब और मानक विचलन आमतौर पर सबसे खराब PRNGs द्वारा भी सही हो जाते हैं।

"खराब" की सामान्य विफलताएं - लेकिन पर्याप्त सामान्य - rand()कार्यान्वयन हैं:

  • कम-क्रम बिट्स की कम यादृच्छिकता;
  • अल्प अवधि;
  • कम RAND_MAX;
  • क्रमिक अर्क के बीच कुछ सहसंबंध (सामान्य तौर पर, एलसीजी उन संख्याओं का उत्पादन करते हैं जो सीमित संख्या में हाइपरप्लेन हैं, हालांकि यह किसी तरह कम हो सकता है)।

फिर भी, इनमें से कोई भी एपीआई के लिए विशिष्ट नहीं है rand()। एक विशेष कार्यान्वयन एक xorshift-family जनरेटर को पीछे रख सकता है srand/ randऔर, algoritmically बोलने के लिए, इंटरफ़ेस की कोई भी बदलाव के साथ कला PRNG की स्थिति प्राप्त नहीं करता है, इसलिए आपके द्वारा किए गए किसी भी परीक्षण का आउटपुट में कोई कमजोरी नहीं दिखाई देगी।

संपादित करें: @R सही ढंग से नोट करता है कि rand/ srandइंटरफ़ेस इस तथ्य से सीमित है कि srandएक लेता है unsigned int, इसलिए किसी भी जनरेटर के कार्यान्वयन को उनके पीछे रखा जा सकता है आंतरिक रूप से UINT_MAXसंभव शुरुआती बीजों (और इस प्रकार उत्पन्न अनुक्रम) तक सीमित है । यह वास्तव में सच है, हालांकि एपीआई को अलग से srandलेने unsigned long long, या एक अलग srand(unsigned char *, size_t)अधिभार जोड़ने के लिए तुच्छ रूप से बढ़ाया जा सकता है ।


दरअसल, वास्तविक समस्या सिद्धांत रूप मेंrand() कार्यान्वयन की बहुत नहीं है लेकिन:

  • पिछेड़ी संगतता; कई मौजूदा कार्यान्वयन आमतौर पर बुरी तरह से चुने गए मापदंडों के साथ उप-रूपी जनरेटर का उपयोग करते हैं; एक कुख्यात उदाहरण विजुअल सी ++ है, जो RAND_MAXसिर्फ 32767 का खेल है । हालांकि, इसे आसानी से नहीं बदला जा सकता है, क्योंकि यह अतीत के साथ संगतता को तोड़ देगा - srandप्रतिलिपि प्रस्तुत करने योग्य सिमुलेशन के लिए एक निश्चित बीज के साथ उपयोग करने वाले लोग बहुत खुश नहीं होंगे (वास्तव में, IICC) पूर्वोक्त कार्यान्वयन Microsoft C के प्रारंभिक संस्करणों में वापस चला जाता है - या यहाँ तक कि अट्ठारहवीं सदी के मध्य से);
  • सरलीकृत इंटरफ़ेस; rand()पूरे कार्यक्रम के लिए वैश्विक राज्य के साथ एक एकल जनरेटर प्रदान करता है। हालांकि यह कई सरल उपयोग के मामलों के लिए पूरी तरह से ठीक है (और वास्तव में काफी आसान है), यह समस्याएं पैदा करता है:

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

अंत में, randमामलों की स्थिति:

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

इसलिए नए <random>हेडर, जो एल्गोरिदम प्रदान करने वाले इस गड़बड़ को ठीक करने की कोशिश करते हैं:

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

... और एक डिफ़ॉल्ट के random_deviceरूप में अच्छी तरह से उन्हें बीज के लिए।

अब, अगर आप मुझसे पूछें कि मुझे "आसान" के लिए इसके ऊपर बना एक साधारण एपीआई भी पसंद आया होगा , तो "एक संख्या का अनुमान करें" मामले (जैसे कि पायथन "जटिल" एपीआई कैसे प्रदान करता है, बल्कि तुच्छ random.randintऔर सह भी। हमारे लिए एक वैश्विक, पूर्व-वरीयता वाले PRNG का उपयोग करते हुए, उन लोगों को बिना सोचे समझे, जो बेतरतीब डिवाइस / इंजन / एडेप्टर / जो भी हर बार हम बिंगो कार्ड के लिए नंबर निकालना चाहते हैं) में डूबना नहीं चाहते, लेकिन यह सच है कि आप आसानी से कर सकते हैं वर्तमान सुविधाओं पर इसे अपने आप से निर्मित करें (एक साधारण से अधिक "पूर्ण" एपीआई का निर्माण करते समय यह संभव नहीं होगा)।


अंत में, अपने प्रदर्शन की तुलना पर वापस जाने के लिए: जैसा कि दूसरों ने निर्दिष्ट किया है, आप एक तेज एलसीजी की तुलना एक धीमे (लेकिन आमतौर पर बेहतर गुणवत्ता के रूप में) मेरसेन ट्विस्टर से कर रहे हैं; यदि आप एक LCG की गुणवत्ता के साथ ठीक हैं, तो आप std::minstd_randइसके बजाय उपयोग कर सकते हैं std::mt19937

वास्तव में, उपयोग करने के लिए अपने फ़ंक्शन को ट्विक करने के बाद std::minstd_randऔर प्रारंभ के लिए बेकार स्थिर चर से बचें

int getRandNum_New() {
    static std::minstd_rand eng{std::random_device{}()};
    static std::uniform_int_distribution<int> dist{0, 5};
    return dist(eng);
}

मुझे 9 एमएस (पुराना) बनाम 21 एमएस (नया) मिलता है; अंत में, अगर मुझे छुटकारा मिल जाता है dist(जो, क्लासिक मोडुलो ऑपरेटर की तुलना में, आउटपुट रेंज के लिए वितरण तिरछा नहीं संभालता है, तो इनपुट रेंज के एक से अधिक नहीं) और जो आप कर रहे हैं उसे वापस पाएं।getRandNum_Old()

int getRandNum_New() {
    static std::minstd_rand eng{std::random_device{}()};
    return eng() % 6;
}

मैं इसे 6 एमएस (इसलिए, 30% तेज) तक ले जाता हूं, शायद, क्योंकि कॉल के विपरीत rand(), std::minstd_randइनलाइन करना आसान है।


संयोग से, मैंने हाथ से लुढ़का (लेकिन मानक पुस्तकालय इंटरफ़ेस के अनुरूप बहुत अधिक) का उपयोग करके एक ही परीक्षण किया XorShift64*, और यह 2.3 गुना rand()(3.68 एमएस बनाम 8.61 एमएस) की तुलना में तेज़ी से है ; यह देखते हुए कि, मेर्सेन ट्विस्टर और विभिन्न प्रदान किए गए एलसीजी के विपरीत, यह उड़ने वाले रंगों के साथ वर्तमान यादृच्छिकता परीक्षण सूट को पारित करता है और यह बहुत तेज़ी से चमकता है, यह आपको आश्चर्यचकित करता है कि यह अभी तक मानक पुस्तकालय में शामिल क्यों नहीं है।


3
यह वास्तव में srandऔर अनिर्दिष्ट एल्गोरिथ्म का संयोजन है std::rand जो मुसीबत में पड़ जाता है। एक अन्य प्रश्न का मेरा उत्तर भी देखें ।
पीटर ओ।

2
randमूल रूप से एपीआई स्तर पर सीमित है जिसमें बीज (और इस प्रकार उत्पन्न होने वाले संभावित अनुक्रमों की संख्या) से घिरा हुआ है UINT_MAX+1
R .. गिटहब स्टॉप हेल्पिंग ICE

2
बस एक ध्यान दें: minstd एक खराब PRNG है, mt19973 बेहतर है लेकिन बहुत ज्यादा नहीं: pcg-random.org/… (उस चार्ट में, minstd == LCG32 / 64)। यह काफी शर्म की बात है कि C ++ किसी भी उच्च-गुणवत्ता, तेज, PRGG जैसे PCG या xoroshiro128 + प्रदान नहीं करता है।
user60561

2
@MatteoItalia हम असहमति में नहीं हैं। यह बज्ने की बात भी थी। हम वास्तव <random>में मानक चाहते हैं , लेकिन हम यह भी चाहते हैं कि "बस मुझे एक अच्छा कार्यान्वयन दें जिसे मैं अभी उपयोग कर सकता हूं" विकल्प। PRNGs के साथ-साथ अन्य चीजों के लिए।
रावणसागर

2
एक दो नोट: 1. कोड को ग्रस्त करने वाले तिरछा कारक std::uniform_int_distribution<int> dist{0, 5}(eng);को eng() % 6पुन : उत्पन्न करने से std::randकोड इस स्थिति में (जहां मामूली रूप से मामूली तिरछा होता है, जहां इंजन 2**31 - 1आउटपुट होता है, और आप उन्हें 6 बाल्टी में वितरित कर रहे हैं)। 2. आपके नोट के बारे में " srandएक " लेता है unsigned intजो संभव आउटपुट को सीमित करता है, जैसा कि लिखा गया है, बस आपके इंजन को सीडिंग std::random_device{}()करने में वही समस्या है; आपको seed_seqअधिकांश PRNGs को ठीक से आरंभ करने के लिए एक की आवश्यकता है
शैडो रेंजर

6

यदि आप अपने प्रयोग को 5 से बड़ी सीमा के साथ दोहराते हैं तो आप शायद अलग परिणाम देखेंगे। जब आपकी सीमा काफी छोटी होती है RAND_MAXतो अधिकांश अनुप्रयोगों के लिए कोई समस्या नहीं होती है।

उदाहरण के लिए यदि हमारी संख्या RAND_MAX25 है, तो rand() % 5निम्न आवृत्तियों के साथ संख्याओं का उत्पादन होगा:

0: 6
1: 5
2: 5
3: 5
4: 5

जैसा कि RAND_MAX32767 से अधिक होने की गारंटी है और कम से कम संभावना और सबसे अधिक संभावना के बीच आवृत्तियों में अंतर केवल 1 है, छोटी संख्या के लिए वितरण अधिकांश उपयोग के मामलों के लिए पर्याप्त यादृच्छिक के पास है।


3
यह एसटीएल की दूसरी स्लाइड में बताया गया है
एलन बर्टल्स

4
ठीक है, लेकिन ... एसटीएल कौन है? और क्या स्लाइड? (गंभीर प्रश्न)
केब्स

@kebs, Stephan Lavavej, प्रश्न में Youtube संदर्भ देखें।
Evg

3

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

भविष्यवाणी: अनुक्रम 01234501234545232345012345 ... आपके नमूने में प्रत्येक नंबर का एक समान वितरण प्रदान करेगा, लेकिन स्पष्ट रूप से यादृच्छिक नहीं है। अनुक्रम के यादृच्छिक होने के लिए, n + 1 के मूल्य को आसानी से n के मूल्य (या यहां तक ​​कि n, n-1, n-2, n-3, आदि के मूल्यों द्वारा) का अनुमान नहीं लगाया जा सकता है। एक ही अंक एक पतित मामला है, लेकिन किसी भी रैखिक congruential जनरेटर के साथ उत्पन्न एक अनुक्रम विश्लेषण के अधीन किया जा सकता है; यदि आप एक आम पुस्तकालय से एक सामान्य एलसीजी की डिफ़ॉल्ट आउट-द-बॉक्स सेटिंग्स का उपयोग करते हैं, तो एक दुर्भावनापूर्ण व्यक्ति बिना किसी प्रयास के "अनुक्रम को तोड़ सकता है"। अतीत में, कई ऑन-लाइन केसिनो (और कुछ ईंट-और-मोर्टार वाले) खराब यादृच्छिक यादृच्छिक जनरेटर का उपयोग करके मशीनों द्वारा नुकसान के लिए हिट किए गए थे। यहां तक ​​कि जिन लोगों को बेहतर पता होना चाहिए, वे भी पकड़े गए हैं;

वितरण: जैसा कि वीडियो में बताया गया है, 100 का मोडुलो लेना (या किसी भी मूल्य को समान रूप से अनुक्रम की लंबाई में विभाजित नहीं करना) गारंटी देगा कि कुछ परिणाम अन्य परिणामों की तुलना में कम से कम थोड़ा अधिक हो जाएंगे। 32767 संभावित शुरुआती मानों के ब्रह्मांड में मोडुलो 100, 66 के माध्यम से संख्या 0 328/327 (0.3%) दिखाई देगी जो कि मानों की तुलना में अधिक बार 99 के माध्यम से 67 होगी; एक कारक जो एक हमलावर को एक लाभ प्रदान कर सकता है।


1
"प्रिडिक्टिबिलिटी: सीक्वेंस 01234501234545232345012345 ..." बेतरतीबी "के लिए आपका टेस्ट पास करेगा, जिसमें आपके नमूने में प्रत्येक नंबर का समान वितरण भी होगा। वास्तव में, वास्तव में नहीं; वह जो माप रहा है, वह रनों के बीच के स्टैडदेवों का स्टैण्डदेव है , अर्थात अनिवार्य रूप से विभिन्न रनों के हिस्टोग्राम को कैसे फैलाया जाता है। 01234501232345012345 ... जनरेटर के साथ यह हमेशा शून्य होगा।
इटालिया

अच्छी बात; मैं ओपी के कोड के माध्यम से थोड़ा जल्दी से पढ़ता हूं, मुझे डर है। मेरे उत्तर को प्रतिबिंबित करने के लिए संपादित किया।
जैकल्टहॉर्टन

हेहे मुझे पता है क्योंकि मैं उस परीक्षण को भी करना चाहता हूं, और मैंने देखा कि मुझे अलग-अलग परिणाम मिले know
Matteo Italia

1

सही उत्तर है: यह इस बात पर निर्भर करता है कि आप "बेहतर" से क्या मतलब है।

"नए" <random>इंजनों को 13 साल पहले C ++ में पेश किया गया था, इसलिए वे वास्तव में नए नहीं हैं। सी लाइब्रेरी rand()को दशकों पहले पेश किया गया था और यह उस समय में किसी भी चीज के लिए बहुत उपयोगी रही है।

सी ++ मानक पुस्तकालय यादृच्छिक संख्या जनरेटर इंजनों के तीन वर्ग प्रदान करता है: रैखिक बधाई (जिनमें rand()से एक उदाहरण है), लैग्ड फाइबोनैचि, और मेरसेन ट्विस्टर। प्रत्येक वर्ग के ट्रेडऑफ़ हैं, और प्रत्येक वर्ग कुछ मायनों में "सर्वश्रेष्ठ" है। उदाहरण के लिए, LCG में बहुत छोटी अवस्था होती है और यदि सही मापदंडों को चुना जाता है, तो आधुनिक डेस्कटॉप प्रोसेसर पर काफी तेज होता है। एलएफजी में बड़ा राज्य है और केवल मेमोरी फ़िंच और अतिरिक्त ऑपरेशन का उपयोग करते हैं, इसलिए एम्बेडेड सिस्टम और माइक्रोकंट्रोलर पर बहुत तेज़ हैं जो विशेष गणित हार्डवेयर की कमी है। एमटीजी में विशाल राज्य है और यह धीमा है, लेकिन उत्कृष्ट वर्णक्रमीय विशेषताओं के साथ एक बहुत बड़ा गैर-दोहराव अनुक्रम हो सकता है।

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

<random>ओवर rand()का एक अन्य लाभ यह है कि rand()वैश्विक राज्य का उपयोग करता है, रीएन्स्ट्रेंट या थ्रेडसेफ़ नहीं है, और प्रति प्रक्रिया एक ही उदाहरण देता है। यदि आपको ठीक-ठाक नियंत्रण या पूर्वानुमेयता की आवश्यकता है (यानी RNG बीज अवस्था दी गई बग को पुन: उत्पन्न करने में सक्षम है) तो rand()बेकार है। <random>जनरेटर स्थानीय स्तर पर instanced और serializable (और restorable) राज्य है कर रहे हैं।

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