C ++ 11 यादृच्छिक पुस्तकालय का उपयोग करके यादृच्छिक संख्या उत्पन्न करें


135

जैसा कि शीर्षक से पता चलता है, मैं नए C ++ 11 <random>पुस्तकालय का उपयोग करके यादृच्छिक संख्याओं को उत्पन्न करने का एक तरीका जानने की कोशिश कर रहा हूं । मैंने इसे इस कोड के साथ आज़माया है:

std::default_random_engine generator;
std::uniform_real_distribution<double> uniform_distance(1, 10.001);

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

मेरे विशेष उपयोग के मामले में, मैं सीमा के भीतर एक मूल्य प्राप्त करने की कोशिश कर रहा था [1, 10]


3
यह प्रश्न "मुख्य रूप से आधारित राय" पर खतरनाक रूप से सीमाबद्ध है। यदि आप राय के लिए आग्रह से छुटकारा पा सकते हैं, तो मैं इस प्रश्न को बहुत उपयोगी देख सकता हूं (यदि यह पहले से नहीं पूछा गया है)।
जॉन डिब्लिंग

4
मेरा सुझाव है कि std::mt19937जब तक आपके पास एक अच्छा कारण नहीं है, इंजन के रूप में उपयोग करें। और वितरण दोनों सिरों पर एक बंद अंतराल है।
क्रिस


2
@ वितरण दोनों सिरों पर बंद नहीं है, इस लिंक या इस लिंक की
memo1288

1
@ memo1288, धन्यवाद, मैंने सोचा था कि ओपी एक उपयोग कर रहा था std::uniform_int_distribution, जो है दोनों सिरों पर बंद हुआ।
क्रिस

जवाबों:


191

Microsoft से Stephan T. Lavavej (stl) ने गोइंग नेटिव में एक चर्चा की कि नए C ++ 11 रैंडम फ़ंक्शंस का उपयोग कैसे करें और क्यों न करें rand()। इसमें, उन्होंने एक स्लाइड शामिल की जो मूल रूप से आपके प्रश्न को हल करती है। मैंने नीचे उस स्लाइड से कोड कॉपी किया है।

आप उनकी पूरी बात यहाँ देख सकते हैं: http://channel9.msdn.com/Events/GoingNative/2013/rand-Considered-Harmful

#include <random>
#include <iostream>

int main() {
    std::random_device rd;
    std::mt19937 mt(rd());
    std::uniform_real_distribution<double> dist(1.0, 10.0);

    for (int i=0; i<16; ++i)
        std::cout << dist(mt) << "\n";
}

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


इस प्रश्न / उत्तर को देखते हुए , यह प्रतीत होता है कि uniform_real_distributionसीमा में एक संख्या लौटाता है [a, b), जहाँ आप चाहते हैं [a, b]। ऐसा करने के लिए, uniform_real_distibutionवास्तव में हमारी तरह दिखना चाहिए:

std::uniform_real_distribution<double> dist(1, std::nextafter(10, DBL_MAX));

3
चूँकि यह सवाल सबसे सामान्य तरीका है कि आप रैंडम संख्याएँ उत्पन्न कर सकते हैं default_random_engine, जिसका आप केवल उपयोग कर सकते हैं , c ++ प्राइमर के अनुसार यह वह है जिसे कार्यान्वयन ने सबसे उपयोगी माना है
aaronman

2
@ARonman: मैं STL की बात से जा रहा हूँ, जहाँ वह स्पष्ट रूप से default_random_engineमौजूद नहीं है।
बिल लिंच

5
@chris हम सभी एक सदिश और मानचित्र के बीच के अंतर को जानते हैं, हर कोई mt19937 और ranlux24 के बीच के अंतर को नहीं जानता है, अगर कोई व्यक्ति यह जानने के बिना प्रोग्रामर बनने में कामयाब रहा कि कोई सदिश और शब्दकोश क्या है std::default_container, तो हो सकता है कि उनके पास कोई उम्मीद हो, उम्मीद है कि नहीं खुद को प्रोग्रामर मानने वाले लोग जो मतभेदों को नहीं जानते हैं, बहुत सारी स्क्रिप्टिंग भाषाओं में एक डिफ़ॉल्ट मानचित्र प्रकार की संरचना होती है, जिसे पूरी तरह से विभिन्न तरीकों से लागू किया जा सकता है, जो उपयोगकर्ता को नहीं पता हो सकता है
aaronman

21
nextafterकॉल सबसे अनुप्रयोगों के लिए overkill है। doubleसमापन बिंदु पर एक यादृच्छिक लैंडिंग की संभावना इतनी कम है कि इसमें शामिल करने और बाहर करने के बीच कोई व्यावहारिक अंतर नहीं है।
मार्क रैनसम

3
असंबंधित @chris (लेकिन आप दरवाजा खोला), अपने std::vectorसादृश्य यहाँ काम नहीं करता क्योंकि std::vector है वास्तव में कारण सीपीयू के लिए कैशिंग एक अच्छा डिफ़ॉल्ट। यह std::listबीच में सम्मिलन के लिए भी बेहतर प्रदर्शन करता है। यह सच है भले ही आप सभी कंटेनरों को समझते हैं और एल्गोरिथम जटिलता के आधार पर एक सूचित निर्णय ले सकते हैं।
void.pointer

24

मेरी 'यादृच्छिक' लाइब्रेरी C ++ 11 यादृच्छिक कक्षाओं के आसपास एक उच्च सुविधाजनक आवरण प्रदान करती है। आप एक सरल 'प्राप्त' पद्धति के साथ लगभग सभी चीजें कर सकते हैं।

उदाहरण:

  1. एक सीमा में यादृच्छिक संख्या

    auto val = Random::get(-10, 10); // Integer
    auto val = Random::get(10.f, -10.f); // Float point
  2. बेतरतीब बूलियन

    auto val = Random::get<bool>( ) // 50% to generate true
    auto val = Random::get<bool>( 0.7 ) // 70% to generate true
  3. एक std :: initilizer_list से यादृच्छिक मूल्य

    auto val = Random::get( { 1, 3, 5, 7, 9 } ); // val = 1 or 3 or...
  4. रैंडम रेंजर या सभी कंटेनर से रैंडम इटरेटर

    auto it = Random::get( vec.begin(), vec.end() ); // it = random iterator
    auto it = Random::get( vec ); // return random iterator

और भी बातें! जीथब पृष्ठ देखें:

https://github.com/effolkronium/random


4

मैंने ऊपर दिए गए लगभग 40 अन्य पृष्ठों को इस तरह से c ++ के साथ लाल कर दिया और Stephan T. Lavavej "STL" से वीडियो देखा और फिर भी यह निश्चित नहीं था कि प्रैक्सी में यादृच्छिक संख्या कैसे काम करती है इसलिए मुझे पता लगाने के लिए एक पूरा रविवार लगा। इसके बारे में क्या और कैसे काम करता है और इसका इस्तेमाल किया जा सकता है।

मेरी राय में एसटीएल "सरंड का उपयोग नहीं करना" के बारे में सही है और उसने वीडियो 2 में इसे अच्छी तरह से समझाया । वह भी उपयोग करने की सलाह देते हैं:

a) void random_device_uniform()- एन्क्रिप्टेड जेनरेशन के लिए लेकिन धीमा (मेरे उदाहरण से)

बी) के साथ उदाहरण mt19937- तेज, बीज बनाने की क्षमता, एन्क्रिप्टेड नहीं


मैंने सभी दावा किए गए c ++ 11 पुस्तकों को बाहर निकाला है जिनकी मुझे एक्सेस है और पाया कि ब्रिमन (2015) जैसे जर्मन लेखक अभी भी इसके एक समूह का उपयोग करते हैं

srand( time( 0 ) );
srand( static_cast<unsigned int>(time(nullptr))); or
srand( static_cast<unsigned int>(time(NULL))); or

सिर्फ #includings के <random>बजाय <time> and <cstdlib>- तो बस एक किताब से सीखने के लिए सावधान रहें :)।

अर्थ - जिसका उपयोग c ++ 11 से नहीं किया जाना चाहिए क्योंकि:

कार्यक्रमों को अक्सर यादृच्छिक संख्याओं के स्रोत की आवश्यकता होती है। नए मानक से पहले, C और C ++ दोनों रैंड नामक एक साधारण सी लाइब्रेरी फ़ंक्शन पर निर्भर थे। यह फ़ंक्शन pseudorandom integers पैदा करता है जो समान रूप से 0 से एक सिस्टम तक निर्भर में वितरित किए जाते हैं- अधिकतम निर्भरता जो कि कम से कम 32767 है। रैंड फ़ंक्शन में कई समस्याएं हैं: कई, यदि अधिकांश नहीं, तो प्रोग्रामों को एक अलग श्रेणी में यादृच्छिक संख्याओं की आवश्यकता होती है एक रैंड द्वारा उत्पादित। कुछ अनुप्रयोगों के लिए रैंडम फ्लोटिंग-पॉइंट नंबरों की आवश्यकता होती है। कुछ कार्यक्रमों को संख्या की आवश्यकता होती है जो एक गैर-समान वितरण को दर्शाते हैं। प्रोग्रामर अक्सर गैर-आयामीता का परिचय देते हैं जब वे रैंड द्वारा उत्पन्न संख्याओं की सीमा, प्रकार, या वितरण को बदलने की कोशिश करते हैं। (लीपमैन सी ++ प्राइमर पांचवें संस्करण 2012 का उद्धरण)


मुझे अंततः बेज़र्न स्ट्रॉन्स्टअप्स में 20 पुस्तकों में से एक सबसे अच्छा स्पष्टीकरण मिला - और उसे अपना सामान जानना चाहिए - "C ++ 2019 का एक दौरा", "प्रोग्रामिंग सिद्धांतों और अभ्यास का उपयोग C ++ 2016" और "C ++ प्रोग्रामिंग लैंग्वेज 4th संस्करण"। 2014 "और" लिप्समैन सी ++ प्राइमर पांचवें संस्करण 2012 "में भी कुछ उदाहरण:

और यह वास्तव में सरल है क्योंकि एक यादृच्छिक संख्या जनरेटर में दो भाग होते हैं: (1) एक इंजन जो यादृच्छिक या छद्म यादृच्छिक मूल्यों के अनुक्रम का उत्पादन करता है। (2) एक वितरण जो उन मानों को एक श्रेणी में गणितीय वितरण में मैप करता है।


Microsofts STL आदमी की राय के बावजूद, Bjarne Stroustrups लिखते हैं:

में, मानक पुस्तकालय यादृच्छिक संख्या इंजन और वितरण ()24.7) प्रदान करता है। डिफ़ॉल्ट रूप से default_random_engine का उपयोग करें, जिसे व्यापक प्रयोज्यता और कम लागत के लिए चुना जाता है।

इसका void die_roll()उदाहरण ब्रेज़न स्ट्रॉस्ट्रुप्स से है - अच्छा विचार पैदा करने वाला इंजन और इसके साथ वितरण using (अधिक मुक्केबाज़ी)


मानक पुस्तकालय द्वारा प्रदान किए गए यादृच्छिक संख्या जनरेटर का व्यावहारिक उपयोग करने में सक्षम होने के लिए <random> यहां कुछ अलग-अलग उदाहरणों के साथ कुछ निष्पादन योग्य कोड कम से कम आवश्यक हैं जो उम्मीद करते हैं कि आप लोगों के लिए सुरक्षित समय और धन:

    #include <random>     //random engine, random distribution
    #include <iostream>   //cout
    #include <functional> //to use bind

    using namespace std;


    void space() //for visibility reasons if you execute the stuff
    {
       cout << "\n" << endl;
       for (int i = 0; i < 20; ++i)
       cout << "###";
       cout << "\n" << endl;
    }

    void uniform_default()
    {
    // uniformly distributed from 0 to 6 inclusive
        uniform_int_distribution<size_t> u (0, 6);
        default_random_engine e;  // generates unsigned random integers

    for (size_t i = 0; i < 10; ++i)
        // u uses e as a source of numbers
        // each call returns a uniformly distributed value in the specified range
        cout << u(e) << " ";
    }

    void random_device_uniform()
    {
         space();
         cout << "random device & uniform_int_distribution" << endl;

         random_device engn;
         uniform_int_distribution<size_t> dist(1, 6);

         for (int i=0; i<10; ++i)
         cout << dist(engn) << ' ';
    }

    void die_roll()
    {
        space();
        cout << "default_random_engine and Uniform_int_distribution" << endl;

    using my_engine = default_random_engine;
    using my_distribution = uniform_int_distribution<size_t>;

        my_engine rd {};
        my_distribution one_to_six {1, 6};

        auto die = bind(one_to_six,rd); // the default engine    for (int i = 0; i<10; ++i)

        for (int i = 0; i <10; ++i)
        cout << die() << ' ';

    }


    void uniform_default_int()
    {
       space();
       cout << "uniform default int" << endl;

       default_random_engine engn;
       uniform_int_distribution<size_t> dist(1, 6);

        for (int i = 0; i<10; ++i)
        cout << dist(engn) << ' ';
    }

    void mersenne_twister_engine_seed()
    {
        space();
        cout << "mersenne twister engine with seed 1234" << endl;

        //mt19937 dist (1234);  //for 32 bit systems
        mt19937_64 dist (1234); //for 64 bit systems

        for (int i = 0; i<10; ++i)
        cout << dist() << ' ';
    }


    void random_seed_mt19937_2()
    {
        space();
        cout << "mersenne twister split up in two with seed 1234" << endl;

        mt19937 dist(1234);
        mt19937 engn(dist);

        for (int i = 0; i < 10; ++i)
        cout << dist() << ' ';

        cout << endl;

        for (int j = 0; j < 10; ++j)
        cout << engn() << ' ';
    }



    int main()
    {
            uniform_default(); 
            random_device_uniform();
            die_roll();
            random_device_uniform();
            mersenne_twister_engine_seed();
            random_seed_mt19937_2();
        return 0;
    }

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


0

यहाँ कुछ है जो मैंने अभी उन पंक्तियों के साथ लिखा है ::

#include <random>
#include <chrono>
#include <thread>

using namespace std;

//==============================================================
// RANDOM BACKOFF TIME
//==============================================================
class backoff_time_t {
  public:
    random_device                      rd;
    mt19937                            mt;
    uniform_real_distribution<double>  dist;

    backoff_time_t() : rd{}, mt{rd()}, dist{0.5, 1.5} {}

    double rand() {
      return dist(mt);
    }
};

thread_local backoff_time_t backoff_time;


int main(int argc, char** argv) {
   double x1 = backoff_time.rand();
   double x2 = backoff_time.rand();
   double x3 = backoff_time.rand();
   double x4 = backoff_time.rand();
   return 0;
}

~


0

यहाँ कुछ संसाधन है जो आप छद्म यादृच्छिक संख्या जनरेटर के बारे में पढ़ सकते हैं।

https://en.wikipedia.org/wiki/Pseudorandom_number_generator

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

बदलने के

std::default_random_engine generator;

द्वारा

std::default_random_engine generator(<some seed number>);

-3

आपको दो सामान्य स्थितियाँ मिली हैं। पहला यह है कि आप यादृच्छिक संख्या चाहते हैं और गुणवत्ता या निष्पादन की गति के बारे में बहुत अधिक नहीं हैं। उस स्थिति में, निम्न मैक्रो का उपयोग करें

#define uniform() (rand()/(RAND_MAX + 1.0))

यह आपको 0 से 1 तक की रेंज में देता है - एप्सिलॉन (जब तक कि RAND_MAX एक दोहरे की सटीकता से बड़ा नहीं है, लेकिन इस बात की चिंता करें कि आप कब आते हैं)।

int x = (int) (यूनिफॉर्म (* * N);

अब 0 से N -1 पर एक यादृच्छिक पूर्णांक देता है।

यदि आपको अन्य वितरण की आवश्यकता है, तो आपको पी को बदलना होगा। या कभी-कभी वर्दी () को कई बार कॉल करना आसान होता है।

यदि आप दोहराए जाने वाले व्यवहार चाहते हैं, तो एक स्थिर के साथ बीज, अन्यथा समय पर कॉल करें ()।

अब यदि आप गुणवत्ता के बारे में परेशान हैं या समय प्रदर्शन चलाते हैं, तो वर्दी को फिर से लिखें। लेकिन अन्यथा कोड को स्पर्श न करें। हमेशा 0 से 1 माइनस एप्सिलॉन पर वर्दी () रखें। अब आप एक बेहतर यूनिफ़ॉर्म () बनाने के लिए C ++ रैंडम नंबर लाइब्रेरी को रैप कर सकते हैं, लेकिन यह एक तरह का माध्यम-स्तरीय विकल्प है। यदि आप आरएनजी की विशेषताओं के बारे में परेशान हैं, तो यह समझने के लिए भी थोड़ा समय निवेश करना उचित है कि अंतर्निहित तरीके कैसे काम करते हैं, फिर एक प्रदान करें। इसलिए आपको कोड का पूर्ण नियंत्रण मिल गया है, और आप गारंटी दे सकते हैं कि एक ही बीज के साथ, अनुक्रम हमेशा एक ही होगा, चाहे आप प्लेटफ़ॉर्म या C ++ के किस संस्करण से लिंक कर रहे हों।


3
सिवाय इसके कि वर्दी (0 से N-1) नहीं है। कारण आसान है, मान लीजिए कि N = 100 और RAND_MAX = 32758 है। 100 इनपुट के लिए समान रूप से 32758 तत्वों (RAND_MAX) को मैप करने का कोई तरीका नहीं है। अनूठे तरीके से 32000 पर एक सीमा तय की जाती है और यदि वह सीमा से बाहर हो जाता है तो रैंड () को फिर से अंजाम देता है
amchacon

1
यदि एन 100 है, तो आपका आरएनजी एक फ्लैट वितरण से विचलन का पता लगाने में सक्षम होने के लिए बहुत अच्छा होना चाहिए।
मैल्कम मैकलीन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.