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


150

मैं पासा के साथ एक खेल बनाने की कोशिश कर रहा हूं, और मुझे इसमें यादृच्छिक संख्याओं की आवश्यकता है (मरने के पक्ष का अनुकरण करने के लिए। मुझे पता है कि इसे 1 और 6 के बीच कैसे बनाना है)। का उपयोग करते हुए

#include <cstdlib> 
#include <ctime> 
#include <iostream>

using namespace std;

int main() 
{ 
    srand((unsigned)time(0)); 
    int i;
    i = (rand()%6)+1; 
    cout << i << "\n"; 
}

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

6
1
1
1
1
1
2
2
2
2
5
2

इसलिए मुझे हर बार एक अलग यादृच्छिक संख्या उत्पन्न करने वाली एक कमांड चाहिए , एक पंक्ति में एक ही 5 बार नहीं। क्या कोई ऐसा आदेश है जो ऐसा करेगा?


55
वितरण की समस्याएं एक तरफ, ध्यान रखें कि यादृच्छिक संख्याओं के साथ एक ही परिणाम कई बार मिलने की संभावना आती है। यदि आपको एक ही नंबर को लगातार दो बार न पाने की गारंटी दी जाती है, तो परिणाम वास्तव में यादृच्छिक नहीं होंगे, क्या वे?
cdhowie

5
क्या आपको लगता है कि उन संख्या यादृच्छिक नहीं हैं? वास्तविक के लिए एक डाई फेंक दो और आप बहुत अच्छी तरह से उस परिणाम को प्राप्त कर सकते हैं। यदि उन्हें प्रत्येक फेंक के बीच अलग होने की गारंटी दी जाती है तो यह वास्तव में यादृच्छिक नहीं होगा।
Mattjgalloway

2
यह भी पढ़ें कि eternallyconfuzzled.com/arts/jsw_art_rand.aspx क्यों मापांक ऑपरेटर का उपयोग करना अक्सर एक अच्छा विचार नहीं होता है।
बेंजामिन बन्नियर

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

20
जब आप समय के साथ बीज। इसका मतलब यह भी है कि यदि आप एक से अधिक बार अपना प्रोग्राम चलाते हैं तो आपको एक ही नंबर मिलेगा।
मार्टिन यॉर्क

जवाबों:


79

आपके परीक्षण आवेदन की सबसे बुनियादी समस्या यह है कि आप srandएक बार कॉल करते हैं और फिर randएक बार कॉल करते हैं और बाहर निकलते हैं।

srandफ़ंक्शन का पूरा बिंदु यादृच्छिक बीज के साथ छद्म यादृच्छिक संख्याओं के अनुक्रम को प्रारंभ करना है

इसका मतलब यह है कि यदि आप एक ही मूल्य को srandदो अलग-अलग अनुप्रयोगों (एक ही srand/ randकार्यान्वयन के साथ) में पास करते हैं तो आपकोrand() दोनों अनुप्रयोगों में उसके बाद के मूल्यों के समान अनुक्रम प्राप्त होंगे

हालाँकि आपके उदाहरण में आवेदन छद्म यादृच्छिक अनुक्रम में केवल एक तत्व होता है - एक छद्म यादृच्छिक अनुक्रम का पहला तत्व जो बीज से secondसटीक और वर्तमान समय के बराबर होता है । फिर आउटपुट पर क्या देखने की उम्मीद है?

जाहिर है जब आप एक ही सेकंड में आवेदन चलाने के लिए होते हैं - आप एक ही बीज मूल्य का उपयोग करते हैं - इस प्रकार आपका परिणाम पाठ्यक्रम का एक ही है (जैसा कि मार्टिन यॉर्क ने पहले ही सवाल का एक टिप्पणी में उल्लेख किया है)।

वास्तव में आपको srand(seed)एक बार कॉल करना चाहिए और फिर rand() कई बार कॉल करना चाहिए और उस अनुक्रम का विश्लेषण करना चाहिए - यह यादृच्छिक दिखना चाहिए।

संपादित करें:

अच्छा मैं समझा। स्पष्ट रूप से मौखिक विवरण पर्याप्त नहीं है (शायद भाषा बाधा या कुछ और ... :))।

ठीक है। पुराने जमाने के सी कोड उदाहरण उन्हीं srand()/rand()/time()कार्यों पर आधारित है जिनका उपयोग प्रश्न में किया गया था:

#include <stdlib.h>
#include <time.h>
#include <stdio.h>

int main(void)
{
    unsigned long j;
    srand( (unsigned)time(NULL) );

    for( j = 0; j < 100500; ++j )
    {
        int n;

        /* skip rand() readings that would make n%6 non-uniformly distributed
          (assuming rand() itself is uniformly distributed from 0 to RAND_MAX) */
        while( ( n = rand() ) > RAND_MAX - (RAND_MAX-5)%6 )
        { /* bad value retrieved so get next one */ }

        printf( "%d,\t%d\n", n, n % 6 + 1 );
    }

    return 0;
}

^^^ कि कार्यक्रम की एक एकल रन से अनुक्रम यादृच्छिक देखने के लिए माना जाता है।

EDIT2:

C या C ++ मानक पुस्तकालय का उपयोग करते समय यह समझना महत्वपूर्ण है कि अब तक एक भी मानक फ़ंक्शन या वर्ग नहीं है जो वास्तव में यादृच्छिक डेटा निश्चित रूप से (मानक द्वारा गारंटीकृत) उत्पन्न करता है। एकमात्र मानक उपकरण जो इस समस्या से संपर्क करता है वह है std :: random_device जो दुर्भाग्य से अभी भी वास्तविक यादृच्छिकता की गारंटी नहीं देता है।

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

हालांकि सुरक्षा-ग्रेड यादृच्छिक संख्या एक अलग लेख के लायक एक अलग उद्योग है।

ज्यादातर मामलों में छद्म-यादृच्छिक संख्या जनरेटर पर्याप्त है - जैसे वैज्ञानिक सिमुलेशन या खेल के लिए। कुछ मामलों में लगातार परिभाषित छद्म यादृच्छिक क्रम की आवश्यकता होती है - उदाहरण के लिए, खेल में आप बहुत सारे डेटा के भंडारण से बचने के लिए रनटाइम में बिल्कुल एक ही नक्शे उत्पन्न करने के लिए चुन सकते हैं।

मूल प्रश्न और समरूप / समान प्रश्नों (और यहां तक ​​कि कई गुमराह "उत्तरों" की पुनरावृत्ति की भीड़) से संकेत मिलता है कि सबसे पहले और सबसे महत्वपूर्ण यह है कि छद्म यादृच्छिक संख्याओं से यादृच्छिक संख्याओं को अलग करना और समझने के लिए कि छद्म यादृच्छिक संख्या अनुक्रम क्या है। पहली जगह और यह महसूस करने के लिए कि छद्म यादृच्छिक संख्या जनरेटर का उपयोग उसी तरह नहीं किया जाता है जिस तरह से आप सच्चे यादृच्छिक संख्या जनरेटर का उपयोग कर सकते हैं।

सहज रूप से जब आप यादृच्छिक संख्या का अनुरोध करते हैं - परिणाम लौटाया जाना चाहिए पहले से दिए गए मूल्यों पर निर्भर नहीं होना चाहिए और यह निर्भर नहीं करना चाहिए कि किसी ने पहले किसी भी चीज का अनुरोध किया है और किस क्षण और किस प्रक्रिया से और किस कंप्यूटर पर और किस जनरेटर से और में निर्भर होना चाहिए क्या आकाशगंगा यह अनुरोध किया गया था। यही कारण है कि शब्द "यादृच्छिक" का मतलब आखिरकार है - अप्रत्याशित और किसी भी चीज से स्वतंत्र होना - अन्यथा यह यादृच्छिक नहीं है, है ना? इस अंतर्ज्ञान के साथ किसी भी संभावित संदर्भ में इस तरह के यादृच्छिक संख्या प्राप्त करने के लिए कुछ जादू मंत्रों के लिए वेब खोजना केवल प्राकृतिक है।

^ ^ ^ इन सहज तरह की अपेक्षाएं बहुत गलत हैं और छद्म-यादृच्छिक संख्या जनरेटरों से जुड़े सभी मामलों में हानिकारक हैं - सही यादृच्छिक संख्याओं के लिए उचित होने के बावजूद।

जबकि "यादृच्छिक संख्या" की सार्थक धारणा मौजूद है - "छद्म यादृच्छिक संख्या" जैसी कोई चीज नहीं है। एक छद्म यादृच्छिक संख्या जनरेटर वास्तव में छद्म यादृच्छिक संख्या अनुक्रम पैदा करता है ।

जब विशेषज्ञ PRNG की गुणवत्ता के बारे में बात करते हैं तो वे वास्तव में उत्पन्न अनुक्रम के सांख्यिकीय गुणों (और इसके उल्लेखनीय उप-अनुक्रमों) के बारे में बात करते हैं। उदाहरण के लिए यदि आप दो उच्च गुणवत्ता वाले PRNGs को बारी-बारी से दोनों का उपयोग करके जोड़ते हैं - तो आप खराब परिणामी अनुक्रम उत्पन्न कर सकते हैं - उनके बावजूद अलग-अलग अच्छे क्रम उत्पन्न करने के बावजूद (वे दो अच्छे क्रम बस एक-दूसरे से संबद्ध हो सकते हैं और इस प्रकार बुरी तरह से संयोजित हो सकते हैं)।

छद्म यादृच्छिक अनुक्रम वास्तव में हमेशा नियतात्मक होता है (इसके एल्गोरिथ्म और प्रारंभिक मापदंडों द्वारा पूर्वनिर्धारित) यानी वास्तव में इसके साथ यादृच्छिक कुछ भी नहीं है।

विशेष रूप से rand()/ srand(s)कार्यों की जोड़ी कार्यान्वयन-परिभाषित एल्गोरिथ्म के साथ उत्पन्न एक एकल प्रति-प्रक्रिया गैर-थ्रेड-सुरक्षित (!) छद्म यादृच्छिक संख्या अनुक्रम प्रदान करती है। समारोह rand()रेंज में मूल्यों का उत्पादन करता है [0, RAND_MAX]

C11 मानक से उद्धरण:

srandसमारोह छद्म यादृच्छिक संख्या का एक नया अनुक्रम को आगामी कॉल द्वारा दिए जाते के लिए एक बीज के रूप में तर्क का उपयोग करता है rand। यदि srandइसे उसी बीज मूल्य के साथ कहा जाता है, तो छद्म यादृच्छिक संख्याओं का क्रम दोहराया जाएगा। यदि randकोई कॉल किए जाने से पहले बुलाया जाता srandहै, तो उसी क्रम को उत्पन्न किया जाएगा जब srandपहली बार 1 के बीज मान के साथ कहा जाता है।

बहुत से लोग काफी उम्मीद करते हैं कि rand()रेंज में अर्द्ध स्वतंत्र समान रूप से वितरित संख्या का एक अनुक्रम का उत्पादन 0करने के लिए RAND_MAX। अच्छी तरह से यह निश्चित रूप से होना चाहिए (अन्यथा यह बेकार है) लेकिन दुर्भाग्य से न केवल मानक की आवश्यकता नहीं है - यहां तक ​​कि स्पष्ट अस्वीकरण भी है जो बताता है कि "उत्पादित यादृच्छिक अनुक्रम की गुणवत्ता के लिए कोई गारंटी नहीं है" । कुछ ऐतिहासिक मामलों में rand/ srandकार्यान्वयन वास्तव में बहुत खराब गुणवत्ता का था। भले ही आधुनिक कार्यान्वयन में यह सबसे अच्छा होने की संभावना है - लेकिन भरोसा टूट गया है और ठीक होना आसान नहीं है। इसके गैर-थ्रेड-सुरक्षित प्रकृति के अलावा बहु-थ्रेडेड अनुप्रयोगों में इसका सुरक्षित उपयोग मुश्किल और सीमित (अभी भी संभव है - आप उन्हें केवल एक समर्पित धागे से उपयोग कर सकते हैं)।

नया वर्ग टेम्पलेट एसटीडी :: mersenne_twister_engine <> (और इसकी सुविधा टाइप्डिफ़्स - std::mt19937/ std::mt19937_64अच्छे टेम्पलेट पैरामीटर संयोजन के साथ) C ++ 11 मानक में परिभाषित प्रति-वस्तु छद्म यादृच्छिक संख्या जनरेटर प्रदान करता है । समान टेम्प्लेट पैरामीटर्स और समान इनिशियलाइज़ेशन पैरामीटर्स के साथ, विभिन्न ऑब्जेक्ट्स C ++ 11 कंप्लेंट स्टैंडर्ड लाइब्रेरी के साथ बनाए गए किसी भी एप्लिकेशन में किसी भी कंप्यूटर पर बिल्कुल समान ऑब्जेक्ट-ऑब्जेक्ट आउटपुट सीक्वेंस उत्पन्न करेंगे। इस वर्ग का लाभ इसके उच्च गुणवत्ता वाले आउटपुट अनुक्रम और कार्यान्वयन के दौरान पूर्ण स्थिरता है।

इसके अलावा C + 11 मानक में परिभाषित PRNG इंजन अधिक हैं - std :: linear_congruential_engine <> (ऐतिहासिक रूप srand/randसे कुछ सी मानक पुस्तकालय कार्यान्वयन में उचित गुणवत्ता एल्गोरिथ्म के रूप में इस्तेमाल किया जाता है ) और std :: subtract_with_carine_engine <> । वे पूरी तरह से परिभाषित पैरामीटर-निर्भर प्रति-ऑब्जेक्ट आउटपुट अनुक्रम भी उत्पन्न करते हैं।

उपरोक्त अप्रचलित सी कोड के लिए आधुनिक दिन C ++ 11 उदाहरण प्रतिस्थापन:

#include <iostream>
#include <chrono>
#include <random>

int main()
{
    std::random_device rd;
    // seed value is designed specifically to make initialization
    // parameters of std::mt19937 (instance of std::mersenne_twister_engine<>)
    // different across executions of application
    std::mt19937::result_type seed = rd() ^ (
            (std::mt19937::result_type)
            std::chrono::duration_cast<std::chrono::seconds>(
                std::chrono::system_clock::now().time_since_epoch()
                ).count() +
            (std::mt19937::result_type)
            std::chrono::duration_cast<std::chrono::microseconds>(
                std::chrono::high_resolution_clock::now().time_since_epoch()
                ).count() );

    std::mt19937 gen(seed);

    for( unsigned long j = 0; j < 100500; ++j )
    /* ^^^Yes. Generating single pseudo-random number makes no sense
       even if you use std::mersenne_twister_engine instead of rand()
       and even when your seed quality is much better than time(NULL) */    
    {
        std::mt19937::result_type n;
        // reject readings that would make n%6 non-uniformly distributed
        while( ( n = gen() ) > std::mt19937::max() -
                                    ( std::mt19937::max() - 5 )%6 )
        { /* bad value retrieved so get next one */ }

        std::cout << n << '\t' << n % 6 + 1 << '\n';
    }

    return 0;
}

पिछले कोड का संस्करण जो std :: वर्दी_int_distribution <> का उपयोग करता है

#include <iostream>
#include <chrono>
#include <random>

int main()
{
    std::random_device rd;
    std::mt19937::result_type seed = rd() ^ (
            (std::mt19937::result_type)
            std::chrono::duration_cast<std::chrono::seconds>(
                std::chrono::system_clock::now().time_since_epoch()
                ).count() +
            (std::mt19937::result_type)
            std::chrono::duration_cast<std::chrono::microseconds>(
                std::chrono::high_resolution_clock::now().time_since_epoch()
                ).count() );

    std::mt19937 gen(seed);
    std::uniform_int_distribution<unsigned> distrib(1, 6);

    for( unsigned long j = 0; j < 100500; ++j )
    {
        std::cout << distrib(gen) << ' ';
    }

    std::cout << '\n';
    return 0;
}

मैंने यहाँ लिंक में इसी तरह का प्रश्न पूछा है लेकिन फिर भी अभी तक कोई स्पष्ट उत्तर नहीं मिल सका है। क्या आप कृपया प्रदर्शन कर सकते हैं "वास्तव में आपको एक बार सरंड (बीज) को कॉल करना चाहिए और फिर कोड के साथ रैंड () कॉल करना चाहिए क्योंकि मैंने पहले ही कहा था कि आप क्या कहते हैं लेकिन यह ठीक से काम नहीं कर रहा है।
bashburak

2
@bashburak ऐसा लगता है कि आप इस उत्तर के बिंदु से पूरी तरह से चूक गए हैं। आपने मेरी बोली क्यों काट दी? मैंने अपने जवाब में शाब्दिक रूप से कहा "वास्तव में आपको एक बार सरंड (बीज) को कॉल करना चाहिए और फिर कई बार रैंड () कॉल करना चाहिए और उस अनुक्रम का विश्लेषण करना चाहिए - यह यादृच्छिक दिखना चाहिए।" क्या आपने देखा कि आपको सिंगल सरंड (...) कॉल के बाद रैंड () मैनी टाइम कॉल करना चाहिए? आपके लिंक में आपका प्रश्न ठीक उसी गलतफहमी के साथ इस प्रश्न का दोहराव है।
सर्ज डंडिच

यह एक पुराना उत्तर है, लेकिन यह तब दिखाई देता है जब आप "C ++ रैंडम नंबर जेनरेशन" गूगल करते हैं। यह C ++ प्रोग्रामर के लिए खराब सलाह है, क्योंकि यह आपको उपयोग करने की सलाह देता है rand()और srand()। क्या आप इसे अपडेट कर सकते हैं?
यक्क - एडम नेवेरुमोंट

@ यक-आदमनेवरुमोंट यह वास्तव में उपयोग करने की सलाह नहीं देता है rand()और srand()। वास्तव में यह सिर्फ दिए गए विवरण के साथ प्रश्न का उत्तर देता है। यह विवरण (जो उपयोग करता है rand/ srand) से स्पष्ट है कि छद्म यादृच्छिक संख्या पीढ़ी की बुनियादी अवधारणाओं को समझाया जाना चाहिए - छद्म यादृच्छिक अनुक्रम और इसके बीज के बहुत अर्थ की तरह। मैं बिल्कुल ऐसा करने की कोशिश कर रहा हूं और सबसे सरल और परिचित rand/ srandसंयोजन का उपयोग करता हूं । मजेदार बात यह है कि कुछ अन्य उत्तर - बहुत बड़ी रेटिंग के साथ भी - प्रश्न के लेखक के समान गलतफहमी से पीड़ित हैं।
सर्ग डंडिच

@ यक-आदमनेवरुमोंट मैंने आपकी सलाह ली और नवीनतम सी ++ परिवर्धन के बारे में कुछ जानकारी के साथ मेरे उत्तर में संशोधन किया। हालाँकि मैं इसे थोड़ा सा विषय मानता हूँ - लेकिन आपके सुझाव के साथ-साथ कुछ अन्य उत्तरों से यह संकेत मिलता है कि दोनों अच्छे पुराने std::rand/std::srandऔर नए C ++ पुस्तकालय जैसे std::random_device<>, std :: mersenne_twister_engine <> और यादृच्छिक वितरणों की भीड़ को कुछ स्पष्टीकरण की आवश्यकता है।
सर्ज डंडिच

216

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

बेहतर वितरण के लिए कुछ C ++ 11 सुविधाओं का प्रयास करें:

#include <random>
#include <iostream>

int main()
{
    std::random_device dev;
    std::mt19937 rng(dev());
    std::uniform_int_distribution<std::mt19937::result_type> dist6(1,6); // distribution in range [1, 6]

    std::cout << dist6(rng) << std::endl;
}

C ++ 11 यादृच्छिक संख्याओं के बारे में अधिक जानकारी के लिए इस प्रश्न / उत्तर को देखें। उपरोक्त ऐसा करने का एकमात्र तरीका नहीं है, लेकिन एक तरीका है।


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

9
HotLicks: सहमत हैं, लेकिन यदि आप C ++ के संस्करण का उपयोग कर रहे हैं, जो समर्थन करता है random_deviceऔर mt19937पहले से ही, वस्तुतः कोई कारण नहीं है कि सभी बाहर जाएं और मानक का उपयोग न करें uniform_int_distribution
क्क्सप्लसोन 21

4
सभी प्रोग्रामर लोगों को प्लेग की तरह मोडुलो से बचने के लिए सलाह देना चाहिए क्योंकि यह विभाजन का उपयोग करता है और जिसकी लागत सैकड़ों घड़ी चक्र होती है और यह आपके एप्लिकेशन के समय को गड़बड़ कर सकता है और / या बहुत अधिक बैटरी शक्ति को जला सकता है।

3
"रेंज" के लिए आरएनजी है?
क्रिस्टोफर

4
@ ChristofferHjärtström: यह r -om n umber g enerator के लिए है ।
कॉर्नस्टॉक

11

यदि आप बूस्ट लिब का उपयोग कर रहे हैं तो आप इस तरह से एक यादृच्छिक जनरेटर प्राप्त कर सकते हैं:

#include <iostream>
#include <string>

// Used in randomization
#include <ctime>
#include <boost/random/mersenne_twister.hpp>
#include <boost/random/uniform_int_distribution.hpp>
#include <boost/random/variate_generator.hpp>

using namespace std;
using namespace boost;

int current_time_nanoseconds(){
    struct timespec tm;
    clock_gettime(CLOCK_REALTIME, &tm);
    return tm.tv_nsec;
}

int main (int argc, char* argv[]) {
    unsigned int dice_rolls = 12;
    random::mt19937 rng(current_time_nanoseconds());
    random::uniform_int_distribution<> six(1,6);

    for(unsigned int i=0; i<dice_rolls; i++){
        cout << six(rng) << endl;
    }
}

जहां फ़ंक्शन current_time_nanoseconds()नैनोसेकंड में वर्तमान समय देता है जो बीज के रूप में उपयोग किया जाता है।


एक श्रेणी में यादृच्छिक पूर्णांक और दिनांक प्राप्त करने के लिए यहां एक अधिक सामान्य वर्ग है:

#include <iostream>
#include <ctime>
#include <boost/random/mersenne_twister.hpp>
#include <boost/random/uniform_int_distribution.hpp>
#include <boost/random/variate_generator.hpp>
#include "boost/date_time/posix_time/posix_time.hpp"
#include "boost/date_time/gregorian/gregorian.hpp"


using namespace std;
using namespace boost;
using namespace boost::posix_time;
using namespace boost::gregorian;


class Randomizer {
private:
    static const bool debug_mode = false;
    random::mt19937 rng_;

    // The private constructor so that the user can not directly instantiate
    Randomizer() {
        if(debug_mode==true){
            this->rng_ = random::mt19937();
        }else{
            this->rng_ = random::mt19937(current_time_nanoseconds());
        }
    };

    int current_time_nanoseconds(){
        struct timespec tm;
        clock_gettime(CLOCK_REALTIME, &tm);
        return tm.tv_nsec;
    }

    // C++ 03
    // ========
    // Dont forget to declare these two. You want to make sure they
    // are unacceptable otherwise you may accidentally get copies of
    // your singleton appearing.
    Randomizer(Randomizer const&);     // Don't Implement
    void operator=(Randomizer const&); // Don't implement

public:
    static Randomizer& get_instance(){
        // The only instance of the class is created at the first call get_instance ()
        // and will be destroyed only when the program exits
        static Randomizer instance;
        return instance;
    }
    bool method() { return true; };

    int rand(unsigned int floor, unsigned int ceil){
        random::uniform_int_distribution<> rand_ = random::uniform_int_distribution<> (floor,ceil);
        return (rand_(rng_));
    }

    // Is not considering the millisecons
    time_duration rand_time_duration(){
        boost::posix_time::time_duration floor(0, 0, 0, 0);
        boost::posix_time::time_duration ceil(23, 59, 59, 0);
        unsigned int rand_seconds = rand(floor.total_seconds(), ceil.total_seconds());
        return seconds(rand_seconds);
    }


    date rand_date_from_epoch_to_now(){
        date now = second_clock::local_time().date();
        return rand_date_from_epoch_to_ceil(now);
    }

    date rand_date_from_epoch_to_ceil(date ceil_date){
        date epoch = ptime(date(1970,1,1)).date();
        return rand_date_in_interval(epoch, ceil_date);
    }

    date rand_date_in_interval(date floor_date, date ceil_date){
        return rand_ptime_in_interval(ptime(floor_date), ptime(ceil_date)).date();
    }

    ptime rand_ptime_from_epoch_to_now(){
        ptime now = second_clock::local_time();
        return rand_ptime_from_epoch_to_ceil(now);
    }

    ptime rand_ptime_from_epoch_to_ceil(ptime ceil_date){
        ptime epoch = ptime(date(1970,1,1));
        return rand_ptime_in_interval(epoch, ceil_date);
    }

    ptime rand_ptime_in_interval(ptime floor_date, ptime ceil_date){
        time_duration const diff = ceil_date - floor_date;
        long long gap_seconds = diff.total_seconds();
        long long step_seconds = Randomizer::get_instance().rand(0, gap_seconds);
        return floor_date + seconds(step_seconds);
    }
};

1
अब जब तक हम मानक के हिस्से के रूप में यादृच्छिक होते हैं तब तक मैं बूस्ट संस्करण के उपयोग को हतोत्साहित करूंगा जब तक कि आप वास्तव में पुराने संकलक का उपयोग नहीं कर रहे हैं।
मार्टिन यॉर्क

9
#include <iostream>
#include <cstdlib>
#include <ctime>

int main() {
    srand(time(NULL));
    int random_number = std::rand(); // rand() return a number between ​0​ and RAND_MAX
    std::cout << random_number;
    return 0;
}

http://en.cppreference.com/w/cpp/numeric/random/rand


प्रश्न लेखक के कोड में क्या अंतर है? (सिवाय है कि आप का उपयोग नहीं करते %6।) और अगर आप का उपयोग करने का निर्णय लिया std::randसी ++ के एपीआई randतो सी पुस्तकालय समारोह का उपयोग क्यों नहीं std::timeऔर std::srandC ++ शैली स्थिरता की खातिर?
सर्ज डुंडिच

4

Randomerयहां से रैंडम नंबर जेनरेट करने के लिए फुल क्लास कोड प्राप्त कर सकते हैं!

यदि आपको परियोजना के विभिन्न हिस्सों में यादृच्छिक संख्याओं की आवश्यकता है, तो आप इसके अंदर के Randomerसभी randomसामान को अलग करने के लिए एक अलग वर्ग बना सकते हैं ।

ऐसा कुछ:

class Randomer {
    // random seed by default
    std::mt19937 gen_;
    std::uniform_int_distribution<size_t> dist_;

public:
    /*  ... some convenient ctors ... */ 

    Randomer(size_t min, size_t max, unsigned int seed = std::random_device{}())
        : gen_{seed}, dist_{min, max} {
    }

    // if you want predictable numbers
    void SetSeed(unsigned int seed) {
        gen_.seed(seed);
    }

    size_t operator()() {
        return dist_(gen_);
    }
};

इस तरह की कक्षा बाद में काम आएगी:

int main() {
    Randomer randomer{0, 10};
    std::cout << randomer() << "\n";
}

आप इस लिंक को एक उदाहरण के रूप में देख सकते हैं कि कैसे मैंRandomer यादृच्छिक स्ट्रिंग्स उत्पन्न करने के लिए इस तरह के वर्ग का उपयोग करता हूं । आप Randomerचाहें तो उपयोग भी कर सकते हैं ।


क्या आप अपने सभी रैंडम ऑब्जेक्ट्स के लिए जनरेटर का फिर से उपयोग नहीं करना चाहेंगे? खासकर जब से यह इनिशियलाइज़ बनाना और अपने राज्य को बनाए रखना अपेक्षाकृत महंगा है।
मार्टिन यॉर्क

3

हर बार एक अलग यादृच्छिक संख्या बनाएं, एक पंक्ति में एक ही छह बार नहीं।

केस परिदृश्य का उपयोग करें

मैंने प्रिडिक्टबिलिटी की समस्या को पेपर के छह बिट्स के एक बैग की तरह बताया, जिसमें से प्रत्येक पर 0 से 5 तक का मान है। हर बार एक नए मूल्य की आवश्यकता होने पर बैग से कागज का एक टुकड़ा निकाला जाता है। यदि बैग खाली है, तो नंबर वापस बैग में डाल दिए जाते हैं।

... इससे, मैं एक एल्गोरिथ्म बना सकता हूं।

कलन विधि

एक बैग आमतौर पर एक है Collection। मैंने bool[]बैग की भूमिका लेने के लिए एक (अन्यथा बूलियन सरणी, बिट प्लेन या बिट मैप के रूप में जाना जाता है) को चुना।

कारण मैंने चुना bool[]है क्योंकि प्रत्येक आइटम का सूचकांक पहले से ही कागज के प्रत्येक टुकड़े का मूल्य है। अगर कागज़ों को उन पर लिखे गए किसी और चीज़ की आवश्यकता होती है, तो मैं Dictionary<string, bool>उसकी जगह एक का उपयोग करता । बूलियन मान का उपयोग इस बात पर नज़र रखने के लिए किया जाता है कि संख्या अभी तक खींची गई है या नहीं।

रैंडम नंबर चुने जाने पर काउंटर RemainingNumberCountको प्रारंभिक कहा जाता है 5। यह हमें यह गिनने से बचाता है कि हर बार जब हम एक नया नंबर निकालना चाहते हैं, तो कागज के कितने टुकड़े छोड़ दिए जाते हैं।

अगले यादृच्छिक मूल्य का चयन करने के लिए, मैं for..loopअनुक्रमित के बैग के माध्यम से स्कैन करने के लिए एक का उपयोग कर रहा हूं , और जब indexयह falseकहा जाता है तो काउंटर को बंद करने के लिए NumberOfMoves

NumberOfMovesअगले उपलब्ध संख्या को चुनने के लिए उपयोग किया जाता है। NumberOfMovesपहले के बीच एक यादृच्छिक मूल्य होने के लिए सेट कर दिया जाता 0है और 5क्योंकि वहाँ 0..5 उपलब्ध कदम हम बैग के माध्यम से कर सकते हैं कर रहे हैं। अगले पुनरावृत्ति के NumberOfMovesबीच एक यादृच्छिक मान सेट किया जाता है 0और 4, क्योंकि अब 0..4 चरण हैं जो हम बैग के माध्यम से बना सकते हैं। जैसा कि संख्याओं का उपयोग किया जाता है, उपलब्ध संख्या कम हो जाती है इसलिए हम इसके बजाय rand() % (RemainingNumberCount + 1)अगले मूल्य की गणना करने के लिए उपयोग करते हैं NumberOfMoves

जब NumberOfMovesकाउंटर शून्य तक पहुंचता है, तो for..loopनिम्नानुसार होना चाहिए:

  1. वर्तमान मान को उसी for..loopइंडेक्स के रूप में सेट करें ।
  2. बैग में सभी नंबरों को सेट करें false
  3. से टूट गया for..loop

कोड

उपरोक्त समाधान के लिए कोड निम्नानुसार है:

(निम्नलिखित तीन ब्लॉक मुख्य में रखें। एक के बाद एक फाइल करें।)

#include "stdafx.h"
#include <ctime> 
#include <iostream>
#include <string>

class RandomBag {
public:
    int Value = -1;

    RandomBag() {
        ResetBag();

    }

    void NextValue() {
        int BagOfNumbersLength = sizeof(BagOfNumbers) / sizeof(*BagOfNumbers);

        int NumberOfMoves = rand() % (RemainingNumberCount + 1);

        for (int i = 0; i < BagOfNumbersLength; i++)            
            if (BagOfNumbers[i] == 0) {
                NumberOfMoves--;

                if (NumberOfMoves == -1)
                {
                    Value = i;

                    BagOfNumbers[i] = 1;

                    break;

                }

            }



        if (RemainingNumberCount == 0) {
            RemainingNumberCount = 5;

            ResetBag();

        }
        else            
            RemainingNumberCount--; 

    }

    std::string ToString() {
        return std::to_string(Value);

    }

private:
    bool BagOfNumbers[6]; 

    int RemainingNumberCount;

    int NumberOfMoves;

    void ResetBag() {
        RemainingNumberCount = 5;

        NumberOfMoves = rand() % 6;

        int BagOfNumbersLength = sizeof(BagOfNumbers) / sizeof(*BagOfNumbers);

        for (int i = 0; i < BagOfNumbersLength; i++)            
            BagOfNumbers[i] = 0;

    }

};

एक कंसोल क्लास

मैं यह कंसोल क्लास बनाता हूं क्योंकि यह आउटपुट को रीडायरेक्ट करना आसान बनाता है।

कोड में नीचे ...

Console::WriteLine("The next value is " + randomBag.ToString());

... द्वारा प्रतिस्थापित किया जा सकता है ...

std::cout << "The next value is " + randomBag.ToString() << std::endl; 

... और Consoleयदि वांछित हो तो इस वर्ग को हटाया जा सकता है।

class Console {
public:
    static void WriteLine(std::string s) {
        std::cout << s << std::endl;

    }

};

मुख्य विधि

उदाहरण का उपयोग निम्नानुसार है:

int main() {
    srand((unsigned)time(0)); // Initialise random seed based on current time

    RandomBag randomBag;

    Console::WriteLine("First set of six...\n");

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    Console::WriteLine("\nSecond set of six...\n");

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    Console::WriteLine("\nThird set of six...\n");

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    Console::WriteLine("\nProcess complete.\n");

    system("pause");

}

उदाहरण आउटपुट

जब मैंने कार्यक्रम चलाया, तो मुझे निम्नलिखित आउटपुट मिले:

First set of six...

The next value is 2
The next value is 3
The next value is 4
The next value is 5
The next value is 0
The next value is 1

Second set of six...

The next value is 3
The next value is 4
The next value is 2
The next value is 0
The next value is 1
The next value is 5

Third set of six...

The next value is 4
The next value is 5
The next value is 2
The next value is 0
The next value is 3
The next value is 1

Process complete.

Press any key to continue . . .

बंद बयान

यह कार्यक्रम विज़ुअल स्टूडियो 2017 का उपयोग करके लिखा गया था , और मैंने इसका Visual C++ Windows Console Applicationउपयोग करके एक प्रोजेक्ट बनाने के लिए चुना .Net 4.6.1

मैं यहाँ कुछ विशेष नहीं कर रहा हूँ, इसलिए कोड को Visual Studio के पुराने संस्करणों पर भी काम करना चाहिए।


यदि यह वीएस 2017 है, तो आपको मानक लाइब्रेरी के सबसे हाल के संस्करण का उपयोग करना चाहिए: en.cppreference.com/w/cpp/numeric/random । वर्तमान में यह उदाहरण सी यादृच्छिक पुस्तकालय कार्यों का उपयोग करता है और "उत्पादित यादृच्छिक अनुक्रम की गुणवत्ता के अनुसार कोई गारंटी नहीं है"।
रॉबर्ट एंड्रेजजुक

3

जब भी आप random number generationC ++ प्रोग्रामिंग लैंग्वेज में बेसिक वेब सर्च करते हैं तो यह सवाल आमतौर पर सबसे पहले आता है! मैं अपनी टोपी को अंगूठी में फेंकना चाहता हूं ताकि भविष्य के कोडर्स के लिए C ++ में छद्म यादृच्छिक संख्या पीढ़ी की अवधारणा को बेहतर ढंग से स्पष्ट किया जा सके जो वेब पर इस प्रश्न को अनिवार्य रूप से खोजेगा!

मूल बातें

छद्म यादृच्छिक संख्या पीढ़ी में एक नियतात्मक एल्गोरिथ्म का उपयोग करने की प्रक्रिया शामिल होती है जो संख्याओं के अनुक्रम का उत्पादन करती है जिनके गुण लगभग यादृच्छिक संख्याओं के समान होते हैं । मैं कहता हूं कि लगभग सदृश , क्योंकि सत्य यादृच्छिकता गणित और कंप्यूटर विज्ञान में एक नहीं बल्कि गूढ़ रहस्य है। इसलिए, छद्म यादृच्छिक शब्द का उपयोग अधिक सटीक रूप से सही होने के लिए किया जाता है!

इससे पहले कि आप वास्तव में एक PRNG का उपयोग कर सकते हैं, यानी, pseudo-random number generatorआपको एल्गोरिथ्म प्रदान करना होगा प्रारंभिक मूल्य जिसे अक्सर बीज के रूप में भी संदर्भित किया जाता है । हालाँकि, बीज को केवल एल्गोरिथम का उपयोग करने से पहले एक बार सेट किया जाना चाहिए !

/// Proper way!
seed( 1234 ) /// Seed set only once...
for( x in range( 0, 10) ):
  PRNG( seed ) /// Will work as expected

/// Wrong way!
for( x in rang( 0, 10 ) ):
  seed( 1234 ) /// Seed reset for ten iterations!
  PRNG( seed ) /// Output will be the same...

इस प्रकार, यदि आप संख्याओं का एक अच्छा क्रम चाहते हैं, तो आपको PRNG को पर्याप्त बीज प्रदान करना होगा!

ओल्ड सी वे

C ++ का C का बैकवर्ड कम्पैटिबल स्टैंडर्ड लाइब्रेरी है, हेडर फाइल में पाया जाने वाला एक लीनियर कंज्यूमेन्शनल जेनरेटर कहलाता है cstdlib! यह PRNG एक डिसकंटेंट पीस वाइज फंक्शन के माध्यम से कार्य करता है जो मॉड्यूलर अंकगणित का उपयोग करता है, अर्थात, एक त्वरित एल्गोरिथ्म जिसका उपयोग करना पसंद करता है modulo operator '%'। इस PRNG का सामान्य उपयोग निम्नलिखित है, @Predictability द्वारा पूछे गए मूल प्रश्न के संबंध में:

#include <iostream>
#include <cstdlib>
#include <ctime>

int main( void )
{
  int low_dist  = 1;
  int high_dist = 6;
  std::srand( ( unsigned int )std::time( nullptr ) );
  for( int repetition = 0; repetition < 10; ++repetition )
    std::cout << low_dist + std::rand() % ( high_dist - low_dist ) << std::endl;
  return 0;
}

C के PRNG के आम उपयोग में इस तरह के मुद्दों की पूरी मेजबानी होती है:

  1. std::rand()किसी दिए गए रेंज के बीच छद्म-यादृच्छिक संख्याओं की उचित पीढ़ी के लिए समग्र इंटरफ़ेस बहुत सहज नहीं है, उदाहरण के लिए, [1, 6] जिस तरह से @Predictability चाहते थे।
  2. कबूतर के सिद्धांत के कारण छद्म यादृच्छिक संख्याओं std::rand()के एक समान वितरण की संभावना को समाप्त करता है ।
  3. तकनीकी रूप std::rand()से बीज बोया जाना सामान्य तरीका std::srand( ( unsigned int )std::time( nullptr ) )सही नहीं है, क्योंकि time_tइसे एक प्रतिबंधित प्रकार माना जाता है । इसलिए, से रूपांतरण time_tके लिए unsigned int इसकी गारंटी नहीं है!

सी के PRNG का उपयोग करने के समग्र मुद्दों के बारे में अधिक विस्तृत जानकारी के लिए, और संभवतः उन्हें कैसे दरकिनार किया जाए, कृपया रैंड () (C / C ++) का उपयोग करने के लिए देखें : C मानक लाइब्रेरी के रैंड () फ़ंक्शन के लिए सलाह !

मानक C ++ मार्ग

चूंकि ISO / IEC 14882: 2011 मानक प्रकाशित हुआ था, अर्थात, C ++ 11, randomपुस्तकालय कुछ समय के लिए C ++ प्रोग्रामिंग भाषा से अलग रहा है। यह लाइब्रेरी कई PRNG, और विभिन्न वितरण प्रकारों से सुसज्जित है : जैसे: समान वितरण , सामान्य वितरण , द्विपद वितरण , आदि। निम्न स्रोत कोड उदाहरण randomलाइब्रेरी के बहुत ही मूल उपयोग को दर्शाता है , @ प्रिडिबिलिटी के मूल प्रश्न के संबंध में:

#include <iostream>
#include <cctype>
#include <random>

using u32    = uint_least32_t; 
using engine = std::mt19937;

int main( void )
{
  std::random_device os_seed;
  const u32 seed = os_seed();

  engine generator( seed );
  std::uniform_int_distribution< u32 > distribute( 1, 6 );

  for( int repetition = 0; repetition < 10; ++repetition )
    std::cout << distribute( generator ) << std::endl;
  return 0;
}

32-बिट Mersenne ट्विस्टर इंजन, पूर्णांक मानों के समान वितरण के साथ उपरोक्त उदाहरण में उपयोग किया गया था। (सोर्स कोड में इंजन का नाम अजीब लगता है, क्योंकि इसका नाम इसकी अवधि 2 ^ 19937-1 से आता है )। उदाहरण इंजन को बीज करने के लिए भी उपयोग करता है, जो ऑपरेटिंग सिस्टम से अपना मूल्य प्राप्त करता है (यदि आप लिनक्स सिस्टम का उपयोग कर रहे हैं, तो एक मान लौटाता है )।std::random_devicestd::random_device/dev/urandom

ध्यान दें, कि आपको किसी इंजनstd::random_device को सीड करने के लिए उपयोग करने की आवश्यकता नहीं है । आप स्थिरांक या पुस्तकालय का उपयोग कर सकते हैं ! आपको इंजन के 32-बिट संस्करण का उपयोग करने की भी आवश्यकता नहीं है , अन्य विकल्प हैं ! पुस्तकालय की क्षमताओं के बारे में अधिक जानकारी के लिए , कृपया cplusplus.com को देखेंchronostd::mt19937random

सभी में, C ++ प्रोग्रामर को std::rand()अब और उपयोग नहीं करना चाहिए , क्योंकि इसका बुरा नहीं है , लेकिन क्योंकि वर्तमान मानक बेहतर विकल्प प्रदान करता है जो अधिक सीधे और विश्वसनीय हैं । उम्मीद है, आप में से कई लोगों को यह मददगार लगता है, खासकर आप में से जिन्होंने हाल ही में वेब सर्च किया है generating random numbers in c++!


2

यहाँ एक समाधान है। एक फ़ंक्शन बनाएं जो यादृच्छिक संख्या देता है और इसे वैश्विक बनाने के लिए मुख्य फ़ंक्शन के बाहर रखता है। उम्मीद है की यह मदद करेगा

#include <iostream>
#include <cstdlib>
#include <ctime>
int rollDie();
using std::cout;
int main (){
    srand((unsigned)time(0));
    int die1;
    int die2;
    for (int n=10; n>0; n--){
    die1 = rollDie();
    die2 = rollDie();
    cout << die1 << " + " << die2 << " = " << die1 + die2 << "\n";
}
system("pause");
return 0;
}
int rollDie(){
    return (rand()%6)+1;
}

2

इस कोड से यादृच्छिक संख्या का उत्पादन होता nहै m

int random(int from, int to){
    return rand() % (to - from + 1) + from;
}

उदाहरण:

int main(){
    srand(time(0));
    cout << random(0, 99) << "\n";
}

2
यह वास्तव में सवाल का जवाब नहीं देता है।
होलीब्लैककट

1
आपने इसे ठीक नहीं किया। सवाल का मुद्दा यह है कि यदि आप प्रति सेकंड कई बार प्रोग्राम चलाते हैं, तो यह समान यादृच्छिक मान उत्पन्न करता है। आपका कोड भी यही करता है।
होलीब्लैककट

1
@HolyBlackCat मैंने इसे कई रनों के लिए जाँच लिया है, यह काम कर रहा है। क्या आपने srand(time(0))पहले मुख्य समारोह में जोड़ा है random(n, m)?
आमिर फ़ॉ

1
आपको srand(time(0))मुख्य कार्य में लूप के लिए या फ़ंक्शन कार्यान्वयन के अंदर नहीं जोड़ना चाहिए ।
अमीर

1
मैंने आपका कोड वर्बेटिम कॉपी कर लिया है। क्या आपने इसे प्रति सेकंड कई बार चलाया ?
होलीब्लैककट

1

यादृच्छिक हर रुन फ़ाइल के लिए

size_t randomGenerator(size_t min, size_t max) {
    std::mt19937 rng;
    rng.seed(std::random_device()());
    //rng.seed(std::chrono::high_resolution_clock::now().time_since_epoch().count());
    std::uniform_int_distribution<std::mt19937::result_type> dist(min, max);

    return dist(rng);
}

1
आप कई बार जनरेटर बनाने वाले नहीं हैं। यह राज्य का एक समूह बनाए रखता है ताकि यह यादृच्छिक संख्याओं का एक क्रम उत्पन्न करे जिसमें उपयुक्त वितरण हो (इसे यादृच्छिक दिखने के लिए)।
मार्टिन यॉर्क

-2

यहाँ लगभग एक साधारण यादृच्छिक जनरेटर है। 0 के आसपास सकारात्मक और नकारात्मक मान उत्पन्न करने की समान संभावना:

  int getNextRandom(const size_t lim) 
  {
        int nextRand = rand() % lim;
        int nextSign = rand() % lim;
        if (nextSign < lim / 2)
            return -nextRand;
        return nextRand;
  }


   int main()
   {
        srand(time(NULL));
        int r = getNextRandom(100);
        cout << r << endl;
        return 0;
   }
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.