সি ++ 11 এলোমেলো লাইব্রেরি ব্যবহার করে এলোমেলো সংখ্যা তৈরি করুন


135

শিরোনামের পরামর্শ অনুসারে, আমি নতুন সি ++ 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 থেকে স্টিফেন টি Lavavej (Stl) নতুন সি ++ 11 র্যান্ডম ফাংশন এবং কেন ব্যবহার না করার ব্যবহার সম্বন্ধে দেশীয় Going এ আলাপ করেনি rand()। এটিতে তিনি একটি স্লাইড অন্তর্ভুক্ত করেছিলেন যা মূলত আপনার প্রশ্নের সমাধান করে। আমি নীচে সেই স্লাইড থেকে কোডটি অনুলিপি করেছি।

আপনি তার সম্পূর্ণ আলোচনা এখানে দেখতে পারেন: http://channel9.msdn.com/Events/GoingNative/2013/rand-Conidered- 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 তবে এটি বীজযুক্ত হওয়ার দরকার নেই কারণ এটি আপনার অপারেটিং সিস্টেম থেকে র্যান্ডম ডেটা অনুরোধ করে (যা উদাহরণস্বরূপ আরডিআর্যান্ডের মতো বিভিন্ন স্থান থেকে উত্স করবে )।


এই প্রশ্ন / উত্তরটির দিকে তাকালে এটি প্রদর্শিত হয় যে আপনি যেখানে চান সেখানে 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, সি ++ প্রাইমার অনুসারে এটি বাস্তবায়ন সবচেয়ে কার্যকর বলে বিবেচিত
অ্যারোনম্যান

2
@ অ্যারোনম্যান: আমি এসটিএলের আলোচনায় যাচ্ছি, যেখানে স্পষ্টতই তার উপস্থিতি পছন্দ default_random_engineনয়।
বিল লিঞ্চ

5
@ ক্রিস আমরা সকলেই ভেক্টর এবং মানচিত্রের মধ্যে পার্থক্য জানি, সবাই এমটি ১৯৯37 এবং রেনলাক্স ২৪ এর মধ্যে পার্থক্য জানি না, যদি কেউ কোনও ভেক্টর এবং অভিধান কী তা না জেনে প্রোগ্রামার হয়ে উঠতে সক্ষম হন তবে তাদের অবশ্যই থাকতে হবে std::default_container, আশা করি সেখানে নেই লোকেরা নিজেদেরকে এমন প্রোগ্রামার হিসাবে বিবেচনা করে যা পার্থক্যগুলি জানে না, প্রচুর স্ক্রিপ্টিং ভাষার একটি ডিফল্ট মানচিত্র প্রকারের কাঠামো থাকে, যা ব্যবহারকারীরা না জানেন এমন বিভিন্ন উপায়ে প্রয়োগ করা যেতে পারে
aaronman

21
nextafterকল সবচেয়ে অ্যাপ্লিকেশনের জন্য Overkill হয়। doubleএকেবারে শেষের পয়েন্টে এলোমেলো অবতরণের সম্ভাবনা এতটা হ্রাস যে এটিকে অন্তর্ভুক্ত করা এবং বাদ দেওয়ার মধ্যে কোনও ব্যবহারিক পার্থক্য নেই।
মার্ক রান্সম

3
@ ক্রিস আনলেলেটেড (তবে আপনি দরজাটি খোলেন), আপনার std::vectorউপমা এখানে কাজ করে না কারণ সিপিইউ ক্যাশে করার কারণে std::vector এটি আসলে একটি ভাল ডিফল্ট। এমনকি std::listএটি মাঝখানে সন্নিবেশের চেয়েও ছাড়িয়ে যায় । আপনি সমস্ত ধারক বুঝতে না পারলেও এবং অ্যালগরিদমিক জটিলতার ভিত্তিতে একটি অবগত সিদ্ধান্ত নিতে পারলেও এটি সত্য।
void.pointer

24

আমার 'এলোমেলো' গ্রন্থাগারটি সি ++ 11 এলোমেলো ক্লাসের চারপাশে একটি উচ্চতর সুবিধাজনক মোড়ক সরবরাহ করে। আপনি একটি সাধারণ 'get' পদ্ধতিতে প্রায় সমস্ত জিনিস করতে পারেন।

উদাহরণ:

  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. পুনরুক্তি পরিসীমা বা সমস্ত ধারক থেকে এলোমেলো rator

    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 অন্য কোন মত এটা গ মাধ্যমে পৃষ্ঠাগুলি ++, সম্পর্কে এই এবং প্রেক্ষিত স্টিফেন টি Lavavej থেকে "STL" ভিডিও এবং এখনও ছিল না কিভাবে নিশ্চিত র্যান্ডম সংখ্যা কাজ অনুশীলনের যাতে আমি একটি পূর্ণ রবিবার নেন জিনিসটা এটি সমস্ত কী এবং এটি কীভাবে কাজ করে এবং কীভাবে ব্যবহার করা যায়।

আমার মতে এসটিএল "আর আর শ্রান্ড ব্যবহার না করা" সম্পর্কে সঠিক এবং তিনি ভিডিও 2 তে এটি ভালভাবে ব্যাখ্যা করেছেন । তিনি ব্যবহার করার পরামর্শও দেন:

ক) void random_device_uniform()- এনক্রিপ্ট করা প্রজন্মের জন্য তবে ধীর (আমার উদাহরণ থেকে)

খ) এর উদাহরণগুলি mt19937- দ্রুত, বীজ তৈরির ক্ষমতা, এনক্রিপ্ট করা হয়নি


আমি সমস্ত দাবী করা সি ++ 11 টি বই আমার কাছে অ্যাক্সেস করে খুঁজে পেয়েছি এবং ফে যে ব্রেইম্যান (2015) এর মতো জার্মান লেখকরা এখনও একটি ক্লোন ব্যবহার করেন

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

কেবল # অন্তর্ভুক্তের <random>পরিবর্তে <time> and <cstdlib>- সুতরাং কেবলমাত্র একটি বই থেকে শিখতে যত্নবান হন :)।

অর্থ - এটি সি ++ 11 সাল থেকে ব্যবহার করা উচিত নয় কারণ:

প্রোগ্রামগুলি প্রায়শই এলোমেলো সংখ্যার উত্স প্রয়োজন। নতুন স্ট্যান্ডার্ডের আগে, সি এবং সি ++ উভয়ই র‌্যান্ড নামে একটি সাধারণ সি লাইব্রেরি ফাংশনে নির্ভর করেছিল। এই ফাংশনটি সিউডোরডম পূর্ণসংখ্যার উত্পাদন করে যা 0 থেকে একটি সিস্টেম-নির্ভর সর্বাধিক মান যা কমপক্ষে 32767 অবধি বিস্তৃত হয় rand র্যান্ড দ্বারা উত্পাদিত। কিছু অ্যাপ্লিকেশনগুলির জন্য এলোমেলো ভাসমান-পয়েন্ট সংখ্যা প্রয়োজন। কিছু প্রোগ্রামের এমন একটি সংখ্যা প্রয়োজন যা একটি অদ্বিতীয় বিতরণকে প্রতিফলিত করে। প্রোগ্রামাররা প্রায়শই ননরানডমনেস পরিচয় দেয় যখন তারা র‌্যান্ড দ্বারা উত্পাদিত সংখ্যার পরিসর, প্রকার বা বিতরণকে রূপান্তরিত করার চেষ্টা করে। (লিপম্যানস সি ++ প্রাইমার পঞ্চম সংস্করণ 2012 এর উদ্ধৃতি)


অবশেষে আমি বজরেন স্ট্রোপ্রস্পস নবীন বইয়ের 20 টি বইয়ের মধ্যে একটি সেরা ব্যাখ্যা খুঁজে পেয়েছি - এবং তার জিনিসগুলি জানা উচিত - "একটি সফর সি ++ 2019", "প্রোগ্রামিং নীতি ও অনুশীলন সি ++ 2016 ব্যবহার করে" এবং "দ্য সি ++ প্রোগ্রামিং ল্যাঙ্গুয়েজ 4 র্থ সংস্করণে in 2014 "এবং" লিপম্যানস সি ++ প্রাইমার পঞ্চম সংস্করণ 2012 "এর কয়েকটি উদাহরণ:

এবং এটি সত্যিই সহজ কারণ একটি এলোমেলো সংখ্যা জেনারেটর দুটি অংশ নিয়ে গঠিত: (1) এমন একটি ইঞ্জিন যা এলোমেলো বা সিউডো-র্যান্ডম মানের ক্রম উত্পাদন করে। (২) এমন একটি বিতরণ যা সেই মানগুলিকে একটি পরিসরে গাণিতিক বিতরণে ম্যাপ করে।


মাইক্রোসফ্টস এসটিএল লোকের মতামত সত্ত্বেও, বার্জার্ন স্ট্রোস্পেস লিখেছেন:

ইন, স্ট্যান্ডার্ড লাইব্রেরি এলোমেলো নম্বর ইঞ্জিন এবং বিতরণ সরবরাহ করে (.7 24.7)। ডিফল্টরূপে ডিফল্ট_র্যান্ডম_জিনি ব্যবহার করুন, যা প্রশস্ত প্রয়োগযোগ্যতা এবং কম খরচের জন্য বেছে নেওয়া হয়েছে।

void die_roll()সঙ্গে ভাল ধারণা উৎপাদিত ইঞ্জিন ও বন্টন - উদাহরণ বিয়ারনে Stroustrups থেকে 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;
    }

আমি মনে করি এটি সমস্ত যোগ করেছে এবং যেমনটি আমি বলেছিলাম যে, এটি উদাহরণগুলিতে নিখরচায় পড়তে আমার সময় এবং সময় লেগেছিল - যদি আপনার সংখ্যা সংখ্যা প্রজন্মের বিষয়ে আরও জিনিস থাকে তবে আমি সে সম্পর্কে সন্ধ্যা বা মন্তব্য বিভাগে শুনে খুশী এবং প্রয়োজনে এটি যুক্ত করবে বা এই পোস্টটি সম্পাদনা করবে। bool


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) (ইউনিফর্ম () * এন);

এখন 0 থেকে N -1 এ এলোমেলো পূর্ণসংখ্যা দেয়।

আপনার যদি অন্যান্য বিতরণ প্রয়োজন হয়, আপনাকে পি। রুপান্তর করতে হবে। অথবা কখনও কখনও ইউনিফর্ম () কয়েকবার কল করা সহজ।

আপনি যদি পুনরাবৃত্তযোগ্য আচরণ চান তবে একটি ধ্রুবক সহ বীজ, অন্যথায় সময়ের সাথে কল করুন ()।

এখন আপনি যদি মানের বা রান টাইম পারফরম্যান্স নিয়ে বিরক্ত হন তবে ইউনিফর্ম () পুনর্লিখন করুন। তবে অন্যথায় কোডটি স্পর্শ করবেন না। সর্বদা 0 থেকে 1 বিয়োগ ইপসিলনে ইউনিফর্ম () রাখুন। আরও ভাল ইউনিফর্ম তৈরি করতে এখন আপনি সি ++ এলোমেলো নম্বর লাইব্রেরিটি लपेटতে পারেন () তবে এটি এক ধরণের মাঝারি স্তরের বিকল্প। আপনি যদি আরএনজির বৈশিষ্ট্যগুলি নিয়ে উদ্বিগ্ন হন তবে অন্তর্নিহিত পদ্ধতিগুলি কীভাবে কাজ করে তা বোঝার জন্য কিছুটা সময় ব্যয় করাও গুরুত্বপূর্ণ, তবে একটি সরবরাহ করুন। সুতরাং আপনি কোডটির সম্পূর্ণ নিয়ন্ত্রণ পেয়েছেন এবং আপনি গ্যারান্টি দিতে পারবেন যে একই বীজের সাথে ক্রমটি সর্বদা হুবহু একই রকম হবে, প্ল্যাটফর্ম নির্বিশেষে বা সি ++ এর কোন সংস্করণে আপনি লিঙ্ক করছেন।


3
এটি অভিন্ন নয় ব্যতীত (0 থেকে এন -1)। কারণটি সহজ, ধরা যাক N = 100 এবং RAND_MAX = 32758। 32758 উপাদানগুলি (RAND_MAX) থেকে 100 ইনপুটগুলিতে অভিন্ন ম্যাপ করার কোনও উপায় নেই। অনন্য
উপায়টি

1
যদি এন 100 হয় তবে ফ্ল্যাট বিতরণ থেকে বিচ্যুতি সনাক্ত করতে আপনার আরএনজি অবশ্যই চূড়ান্ত হতে হবে।
ম্যালকম ম্যাকলিন
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.