एक सीमा से यादृच्छिक पूर्णांक बनाना


157

मुझे एक फ़ंक्शन की आवश्यकता है जो दी गई सीमा (सीमा मूल्यों सहित) में एक यादृच्छिक पूर्णांक उत्पन्न करेगा। मैं अनुचित गुणवत्ता / यादृच्छिकता आवश्यकताओं के लिए नहीं है, मेरी चार आवश्यकताएं हैं:

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

वर्तमान में मेरे पास C ++ कोड है:

output = min + (rand() * (int)(max - min) / RAND_MAX)

समस्या यह है, कि यह वास्तव में एक समान नहीं है - अधिकतम केवल तभी वापस किया जाता है जब रैंड () = RAND_MAX (विजुअल C ++ के लिए यह 1/32727 है)। यह छोटी श्रेणियों जैसे <-1, 1> के लिए प्रमुख मुद्दा है, जहां अंतिम मूल्य लगभग कभी वापस नहीं आता है।

इसलिए मैंने पेन और पेपर पकड़ा और निम्न सूत्र के साथ आया (जो कि (int) (n + 0.5) पूर्णांक राउंडिंग ट्रिक का निर्माण करता है):

यहां छवि विवरण दर्ज करें

लेकिन यह अभी भी मुझे एक समान वितरण नहीं देता है। 10000 नमूनों के साथ बार-बार दौड़ने से मुझे मूल्यों -1, 0. 1 के लिए 37:50:13 का अनुपात मिलता है।

क्या आप बेहतर फार्मूला सुझा सकते हैं? (या पूरे छद्म यादृच्छिक संख्या जनरेटर फ़ंक्शन)



3
@ बिल मैग्रिफ: हां। इसकी भी यही समस्या है। एक सरलीकृत संस्करण है: आप कैंडी के 10 टुकड़ों को 3 बच्चों के बीच समान रूप से विभाजित कर सकते हैं (बिना किसी कैंडी को तोड़ने के)? जवाब है, आप नहीं कर सकते हैं - आपको प्रत्येक बच्चे को तीन देने होंगे, और दसवें को किसी को भी नहीं देना होगा।
जेरी कॉफिन

5
क्या आपने Boost.Random को देखा है ?
फ्रेड नर्क

3
एंड्रयू कोएनिग लेख की जांच करें "एक सरल समस्या जो लगभग कभी भी सही ढंग से हल नहीं होती है": drdobbs.com/blog/archives/2010/11/a_simple_proble.html
Gene Bushuyev

1
@ गेन बुशुयेव: एंड्रयू और मैं दोनों इस विषय पर काफी समय से नुकसान कर रहे हैं। देखें: group.google.com/group/comp.lang.c++/browse_frm/thread/… , और: group.google.com/group/comp.os.ms-ms-windows.programmer.tools.mfc/…
जैरी कॉफ़िन

जवाबों:


105

एक तेज, कुछ हद तक आपकी तुलना में बेहतर है, लेकिन अभी भी ठीक से समान रूप से वितरित समाधान नहीं है

output = min + (rand() % static_cast<int>(max - min + 1))

सिवाय जब रेंज का आकार 2 की शक्ति है, तो यह विधि गुणवत्ता की परवाह किए बिना पक्षपाती गैर-समान वितरित संख्याओं का उत्पादन करती है rand()। इस पद्धति की गुणवत्ता के व्यापक परीक्षण के लिए, कृपया इसे पढ़ें


2
धन्यवाद, यह त्वरित परीक्षणों से मेरे लिए काफी अच्छा लगता है - -1, 0, 1 के लिए इसका वितरण लगभग 33:33:33 है।
Mat --j Zábský

3
यह हमेशा अधिकतम मूल्य देता है। क्या मैं यहाँ कुछ याद कर रहा हूँ? : |
रोहन-पटेल

15
rand()C ++ में हानिकारक माना जाना चाहिए कि कुछ पाने के बेहतर तरीके हैं जो समान रूप से वितरित हैं और वास्तव में यादृच्छिक हैं।
मगताज

1
क्या यह वास्तव में समय की 100% सीमा के भीतर एक सही संख्या देता है? मुझे यहां कुछ अन्य
स्टैकओवरफ़्लो का

2
चूंकि यह एक उच्च उत्थान (वांछित से अधिक) उत्तर है, जो कई नए पाठकों के लिए जानकारी का विश्वसनीय स्रोत लगता है, मुझे लगता है कि इस समाधान की गुणवत्ता और संभावित खतरों का उल्लेख करना बहुत महत्वपूर्ण है, इसलिए मैंने एक संपादन किया।
plasmacel

296

सबसे सरल (और इसलिए सर्वोत्तम) C ++ (2011 मानक का उपयोग करके) उत्तर है

#include <random>

std::random_device rd;     // only used once to initialise (seed) engine
std::mt19937 rng(rd());    // random-number engine used (Mersenne-Twister in this case)
std::uniform_int_distribution<int> uni(min,max); // guaranteed unbiased

auto random_integer = uni(rng);

पहिया को फिर से आविष्कार करने की आवश्यकता नहीं है। पूर्वाग्रह के बारे में चिंता करने की जरूरत नहीं है। यादृच्छिक बीज के रूप में समय का उपयोग करने के बारे में चिंता करने की आवश्यकता नहीं है।


1
आजकल इसका उत्तर होना चाहिए । अधिक सुविधाओं के लिए छद्म यादृच्छिक संख्या पीढ़ी संदर्भ
alextoind

8
मैं "सरलतम" (और सबसे मुहावरेदार) पर सहमत हूं, "सर्वश्रेष्ठ" पर नहीं। दुर्भाग्य से मानक के बारे में कोई गारंटी नहीं है random_device, जो कुछ मामलों में पूरी तरह से टूट सकता है । इसके अलावा, mt19937जबकि एक बहुत अच्छा सामान्य-उद्देश्य विकल्प, अच्छी गुणवत्ता वाले जनरेटर का सबसे तेज नहीं है ( यह तुलना देखें ) और इसलिए ओपी के लिए आदर्श उम्मीदवार नहीं हो सकता है।
अल्बर्टो M

1
@AlbertoM दुर्भाग्य से, आपके संदर्भ की तुलना पर्याप्त विवरण प्रदान नहीं करती है और यह प्रतिलिपि प्रस्तुत करने योग्य नहीं है, जो इसे संदिग्ध (इसके अलावा, यह 2015 से प्रदान करता है, जबकि मेरा जवाब 2013 तक है)। यह अच्छी तरह से सच हो सकता है कि आसपास बेहतर तरीके हैं (और भविष्य में उम्मीद है, minstdऐसी विधि होगी), लेकिन यह प्रगति है। खराब कार्यान्वयन के रूप में random_device- यह भयानक है और इसे बग माना जाना चाहिए (संभवतः सी ++ मानक का भी, यदि यह अनुमति देता है)।
वाल्टर

1
मैं आपसे पूरी तरह सहमत हूं; मैं वास्तव में आपके समाधान के प्रति आलोचना नहीं करना चाहता था, बस आकस्मिक पाठक को चेतावनी देना चाहता था कि C ++ 11 के वादों के बावजूद, मामले पर निश्चित उत्तर लिखा जाना बाकी है। मैं संबंधित प्रश्न के उत्तर के रूप में 2015 के विषय का अवलोकन पोस्ट करने जा रहा हूं ।
अल्बर्टो M

1
वह "सरलतम" है? क्या आप स्पष्ट रूप से बता सकते हैं कि स्पष्ट रूप से बहुत सरल rand()विकल्प क्यों नहीं है, और क्या यह गैर-महत्वपूर्ण उपयोग के लिए कोई फर्क नहीं पड़ता है, जैसे कि यादृच्छिक अक्ष सूचकांक बनाना? इसके अलावा, क्या मुझे एक तंग लूप / इनलाइन फ़ंक्शन में निर्माण random_device/ mt19937/ के बारे में चिंता uniform_int_distributionकरना है? क्या मुझे उन्हें पास करना पसंद करना चाहिए?
bluenote10

60

यदि आपका कंपाइलर C ++ 0x का समर्थन करता है और इसका उपयोग करना आपके लिए एक विकल्प है, तो नए मानक <random>हेडर आपकी आवश्यकताओं को पूरा करने की संभावना है। इसकी एक उच्च गुणवत्ता है uniform_int_distributionजो न्यूनतम और अधिकतम सीमा (आपको आवश्यकतानुसार समावेशी) को स्वीकार करेगी, और आप उस वितरण में प्लग करने के लिए विभिन्न यादृच्छिक संख्या जनरेटर के बीच चयन कर सकते हैं।

यहाँ वह कोड है जो int[-57, 365] में समान रूप से वितरित एक लाख यादृच्छिक s उत्पन्न करता है । मैंने <chrono>समय के साथ नई std सुविधाओं का उपयोग किया है जैसा कि आपने बताया कि प्रदर्शन आपके लिए एक बड़ी चिंता का विषय है।

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

int main()
{
    typedef std::chrono::high_resolution_clock Clock;
    typedef std::chrono::duration<double> sec;
    Clock::time_point t0 = Clock::now();
    const int N = 10000000;
    typedef std::minstd_rand G;
    G g;
    typedef std::uniform_int_distribution<> D;
    D d(-57, 365);
    int c = 0;
    for (int i = 0; i < N; ++i) 
        c += d(g);
    Clock::time_point t1 = Clock::now();
    std::cout << N/sec(t1-t0).count() << " random numbers per second.\n";
    return c;
}

मेरे लिए (2.8 GHz इंटेल कोर i5) यह प्रिंट करता है:

2.10268e + 07 यादृच्छिक संख्या प्रति सेकंड।

आप अपने कंस्ट्रक्टर में एक इंट पास करके जनरेटर को बीज कर सकते हैं:

    G g(seed);

यदि आपको बाद में पता चलता intहै कि आपके वितरण के लिए आवश्यक सीमा को कवर नहीं किया गया है, तो इसे इस प्रकार बदला जा सकता है uniform_int_distribution(जैसे long long):

    typedef std::uniform_int_distribution<long long> D;

यदि आपको बाद में पता चलता है कि minstd_randयह एक उच्च गुणवत्ता वाला जनरेटर नहीं है, तो इसे आसानी से स्वैप भी किया जा सकता है। उदाहरण के लिए:

    typedef std::mt19937 G;  // Now using mersenne_twister_engine

यादृच्छिक संख्या जनरेटर पर अलग नियंत्रण रखने, और यादृच्छिक वितरण काफी मुक्त हो सकता है।

मैंने इस वितरण के पहले 4 "क्षणों" को भी (गणना करके) दिखाया है (उपयोग करते हुए minstd_rand) और वितरण की गुणवत्ता को निर्धारित करने के प्रयास में उनकी तुलना सैद्धांतिक मूल्यों से की है:

min = -57
max = 365
mean = 154.131
x_mean = 154
var = 14931.9
x_var = 14910.7
skew = -0.00197375
x_skew = 0
kurtosis = -1.20129
x_kurtosis = -1.20001

( x_उपसर्ग "अपेक्षित" को संदर्भित करता है)


3
यह उत्तर एक संक्षिप्त सारांश कोड स्निपेट का उपयोग कर सकता है जो केवल उस कोड को दिखाता है जो वास्तव में एक सीमा से यादृच्छिक पूर्णांक उत्पन्न करने के लिए आवश्यक है।
arekolek

समस्या को इस तथ्य से आसान बना दिया गया है कि वितरण के अधिकतम और अधिकतम कभी नहीं बदलते हैं। क्या होगा अगर आपको dअलग-अलग सीमा के साथ प्रत्येक पुनरावृत्ति पर बनाना था ? यह लूप को कितना धीमा करेगा?
क्वांट_देव quant

15

आइए समस्या को दो भागों में विभाजित करते हैं:

  • n0 (अधिकतम-मिनट) के माध्यम से सीमा 0 में एक यादृच्छिक संख्या उत्पन्न करें ।
  • उस नंबर पर मिनट जोड़ें

पहला भाग स्पष्ट रूप से सबसे कठिन है। मान लेते हैं कि रैंड का वापसी मूल्य () पूरी तरह से समान है। मॉडुलो के प्रयोग से पहले (RAND_MAX + 1) % (max-min+1)नंबरों में पूर्वाग्रह जुड़ जाएंगे । तो अगर हम जादुई बदल सकता है RAND_MAXके लिए RAND_MAX - (RAND_MAX + 1) % (max-min+1), वहाँ अब किसी भी पूर्वाग्रह होगा।

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

चलने का समय अब ज्यामितीय रूप से वितरित किया जाता है , अपेक्षित मूल्य के साथ 1/pजहां pपहली कोशिश में एक छोटी संख्या प्राप्त करने की संभावना है। चूँकि हम RAND_MAX - (RAND_MAX + 1) % (max-min+1)हमेशा से कम होते हैं (RAND_MAX + 1) / 2, हम जानते हैं p > 1/2, इसलिए पुनरावृत्तियों की अपेक्षित संख्या किसी भी सीमा के लिए हमेशा दो से कम होगी। इस तकनीक के साथ एक मानक CPU पर एक सेकंड से भी कम समय में लाखों यादृच्छिक संख्याओं को उत्पन्न करना संभव होना चाहिए।

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

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


पूर्णता के लिए: यह अस्वीकृति नमूनाकरण है
21

3
मजेदार तथ्य: जोएल स्पोल्स्की ने एक बार इस सवाल के एक संस्करण का उल्लेख किया था कि स्टैकऑवरफ्लो का जवाब देने में क्या अच्छा था। मैं उस समय साइट से जुड़े अस्वीकृति नमूने पर जवाब के माध्यम से देखा और हर एक एक गलत था।
जोर्जेन फॉग

13

Mersenne ट्विस्टर के बारे में कैसे ? बूस्ट कार्यान्वयन का उपयोग करना आसान है और कई वास्तविक दुनिया के अनुप्रयोगों में अच्छी तरह से परीक्षण किया गया है। मैंने इसे कई अकादमिक परियोजनाओं जैसे कृत्रिम बुद्धिमत्ता और विकासवादी एल्गोरिदम में स्वयं उपयोग किया है।

यहां उनका उदाहरण है जहां वे छह-पक्षीय मरने के लिए एक सरल कार्य करते हैं:

#include <boost/random/mersenne_twister.hpp>
#include <boost/random/uniform_int.hpp>
#include <boost/random/variate_generator.hpp>

boost::mt19937 gen;

int roll_die() {
    boost::uniform_int<> dist(1, 6);
    boost::variate_generator<boost::mt19937&, boost::uniform_int<> > die(gen, dist);
    return die();
}

ओह, और यहाँ इस जेनरेटर के कुछ और अधिक होने की स्थिति में आप आश्वस्त नहीं हैं कि आपको इसका अत्यधिक हीनता से उपयोग करना चाहिए rand():

मर्सें ट्विस्टर एक "रैंडम नंबर" जनरेटर है जिसका आविष्कार मकोतो मात्सुमोतो और ताकुजी निशिमुरा ने किया था; उनकी वेबसाइट में एल्गोरिथ्म के कई कार्यान्वयन शामिल हैं।

अनिवार्य रूप से, Mersenne ट्विस्टर एक बहुत बड़ी रैखिक-प्रतिक्रिया शिफ्ट रजिस्टर है। एल्गोरिथ्म एक 19,937 बिट बीज पर संचालित होता है, जो 32-बिट अहस्ताक्षरित पूर्णांक के 624-तत्व सरणी में संग्रहीत होता है। मान 2 ^ 19937-1 एक मेर्सन प्राइम है; बीज में हेरफेर करने की तकनीक एक पुराने "घुमा" एल्गोरिथ्म पर आधारित है - इसलिए इसका नाम "मेर्सेन ट्विस्टर" है।

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


1
Mersenne ट्विस्टर एक अच्छा जनरेटर है, लेकिन जिस समस्या से वह निपट रहा है, वह अंतर्निहित जनरेटर की परवाह किए बिना है।
जेरी कॉफिन

मैं केवल यादृच्छिक जनरेटर के लिए बूस्ट का उपयोग नहीं करना चाहता, क्योंकि (चूंकि मेरी परियोजना एक पुस्तकालय है) इसका मतलब है कि परियोजना के लिए एक और निर्भरता का परिचय। मुझे भविष्य में इसका उपयोग करने के लिए मजबूर किया जाएगा, तो मैं इस जनरेटर पर स्विच कर सकता हूं।
Mat --j Zábský

1
@ जेरी कॉफ़िन कौन सी समस्या? मैंने इसकी पेशकश की क्योंकि यह उसकी सभी आवश्यकताओं को पूरा करता है: यह तेज़ है, यह एक समान है ( boost::uniform_intवितरण का उपयोग करके ), आप न्यूनतम अधिकतम सीमाओं को अपनी पसंद के अनुसार बदल सकते हैं, और यह बीज योग्य है।
एपेक्स

@mzabsky मैं संभवत: मुझे रोक नहीं सकता, जब मुझे प्रस्तुत करने के लिए अपने प्रोफेसरों को अपनी परियोजनाओं को शिप करना पड़ा, तो मैंने केवल प्रासंगिक बूस्टर हेडर फ़ाइलों को शामिल किया जिन्हें मैं उपयोग कर रहा था; आपको अपने कोड के साथ पूरे 40mb बूस्ट लाइब्रेरी को पैकेज नहीं करना चाहिए। बेशक आपके मामले में यह कॉपीराइट जैसे अन्य कारणों से संभव नहीं हो सकता है ...
Apxx

@Aphex मेरा प्रोजेक्ट वास्तव में एक वैज्ञानिक सिम्युलेटर या ऐसा कुछ नहीं है जिसे वास्तव में समान वितरण की आवश्यकता है। मैंने 1.5 साल के लिए पुराने जनरेटर का उपयोग बिना किसी मुद्दे के किया, मैंने केवल पक्षपाती वितरण पर ध्यान दिया जब मुझे पहली बार बहुत छोटी रेंज (इस मामले में 3) से संख्या उत्पन्न करने की आवश्यकता थी। गति अभी भी बूस्ट समाधान पर विचार करने के लिए तर्क है। मैं इसके लाइसेंस पर गौर करूंगा कि क्या मैं अपनी परियोजना में कुछ आवश्यक फाइलें जोड़ सकता हूं - मुझे अब "चेकआउट -> F5 -> उपयोग करने के लिए तैयार" पसंद है।
Mat --j Zábský

11
int RandU(int nMin, int nMax)
{
    return nMin + (int)((double)rand() / (RAND_MAX+1) * (nMax-nMin+1));
}

यह (nMax-nMin + 1) पूर्णांकों के लिए 32768 पूर्णांक का मानचित्रण है। मैपिंग काफी अच्छी होगी अगर (nMax-nMin + 1) छोटा हो (आपकी आवश्यकता के अनुसार)। ध्यान दें कि अगर (nMax-nMin + 1) बड़ा है, तो मैपिंग काम नहीं करेगी (उदाहरण के लिए - आप 32768 मानों को 30000 मानों के बराबर संभावना के साथ मैप नहीं कर सकते हैं)। यदि इस तरह की सीमाओं की आवश्यकता होती है - आपको 15-बिट रैंड () के बजाय 32-बिट या 64-बिट यादृच्छिक स्रोत का उपयोग करना चाहिए, या रैंड () परिणामों को अनदेखा करना चाहिए जो आउट-ऑफ-रेंज हैं।


इसकी अलोकप्रियता के बावजूद, यह वह भी है जो मैं अपनी गैर-वैज्ञानिक परियोजनाओं के लिए उपयोग करता हूं। समझने में आसान (आपको गणित की डिग्री की आवश्यकता नहीं है) और पर्याप्त रूप से प्रदर्शन करता है (कभी भी इसका उपयोग करके किसी भी कोड को प्रोफाइल नहीं करना पड़ता था)। :) बड़ी रेंज के मामले में, मुझे लगता है कि हम दो रैंड () मानों को एक साथ स्ट्रिंग कर सकते हैं और काम करने के लिए 30-बिट मान प्राप्त कर सकते हैं (RAND_MAX = 0x7fff, यानी 15 यादृच्छिक बिट्स
मानकर

पूर्णांक अतिप्रवाह चेतावनी से बचने के RAND_MAXलिए परिवर्तन (double) RAND_MAX
एलेक्स

4

यहां एक निष्पक्ष संस्करण है जो संख्याओं को उत्पन्न करता है [low, high]:

int r;
do {
  r = rand();
} while (r < ((unsigned int)(RAND_MAX) + 1) % (high + 1 - low));
return r % (high + 1 - low) + low;

यदि आपकी सीमा यथोचित रूप से छोटी है, तो doलूप में तुलना के दाईं ओर कैश करने का कोई कारण नहीं है ।


IMO, वहाँ प्रस्तुत समाधानों में से कोई भी वास्तव में बहुत सुधार नहीं है। उनका लूप-आधारित समाधान काम करता है, लेकिन काफी अक्षम होने की संभावना है, खासकर ओपी की तरह एक छोटी रेंज के लिए। उसकी वर्दी विचलित समाधान वास्तव में उत्पादन नहीं करता है वर्दी सब पर भटक। अधिकतर यह एकरूपता की कमी को दर्शाता है।
जेरी कॉफिन

@ जेरी: कृपया नया संस्करण देखें।
यिर्मयाह विलकॉक

मैं उस काम के बारे में थोड़ा अनिश्चित हूं जो सही तरीके से काम कर रहा है। यह हो सकता है, लेकिन शुद्धता स्पष्ट नहीं लगती है, कम से कम मेरे लिए।
जेरी कॉफिन

@ जेरी: यहाँ मेरा तर्क है: मान लें कि सीमा [0, h)सादगी के लिए है। कॉलिंग rand()में RAND_MAX + 1संभावित रिटर्न मान हैं; लेने rand() % hगिर (RAND_MAX + 1) / hसे प्रत्येक के लिए उनमें से h, उत्पादन मूल्यों, सिवाय इसके कि (RAND_MAX + 1) / h + 1उनमें से मानों की तुलना में कम कर रहे हैं करने के लिए मैप किया जाता है (RAND_MAX + 1) % h(के माध्यम से पिछले आंशिक चक्र की वजह से hआउटपुट)। इसलिए हम (RAND_MAX + 1) % hनिष्पक्ष वितरण पाने के लिए संभावित आउटपुट को हटा देते हैं।
यिर्मयाह विलकॉक

3

मैं Boost.Random पुस्तकालय की सिफारिश करता हूं , यह सुपर विस्तृत और अच्छी तरह से प्रलेखित है, आपको स्पष्ट रूप से निर्दिष्ट करता है कि आप क्या वितरण चाहते हैं, और गैर-क्रिप्टोग्राफिक परिदृश्यों में वास्तव में एक विशिष्ट सी लाइब्रेरी रैंड कार्यान्वयन को बेहतर बना सकते हैं ।


1

मान और अधिकतम अंतर मान हैं, [और] का अर्थ है इस मान को शामिल करें, (और) का अर्थ है कि यह मान शामिल नहीं है, ऊपर का उपयोग करके c ++ रैंड () का उपयोग करके सही मान प्राप्त करें

संदर्भ: के लिए () [] परिभाषित, यात्रा:

https://en.wikipedia.org/wiki/Interval_(mathematics)

रैंड और श्रंद फंक्शन या RAND_MAX के लिए परिभाषित करें, पर जाएँ:

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

[न्यूनतम अधिकतम]

int randNum = rand() % (max - min + 1) + min

(न्यूनतम अधिकतम]

int randNum = rand() % (max - min) + min + 1

[न्यूनतम अधिकतम)

int randNum = rand() % (max - min) + min

(न्यूनतम अधिकतम)

int randNum = rand() % (max - min - 1) + min + 1

0

इस थ्रेड रिजेक्शन नमूने में पहले से ही चर्चा की गई थी, लेकिन मैं इस तथ्य के आधार पर एक अनुकूलन का सुझाव देना चाहता था rand() % 2^something किसी पूर्वाग्रह का परिचय नहीं देता जैसा कि ऊपर उल्लेख किया गया है।

एल्गोरिथ्म वास्तव में सरल है:

  • अंतराल की लंबाई से अधिक से अधिक 2 की सबसे छोटी शक्ति की गणना करें
  • उस "नए" अंतराल में एक संख्या को यादृच्छिक करें
  • यदि यह मूल अंतराल की लंबाई से कम है तो उस संख्या को वापस करें
    • अन्यथा अस्वीकार करें

यहाँ मेरा नमूना कोड है:

int randInInterval(int min, int max) {
    int intervalLen = max - min + 1;
    //now calculate the smallest power of 2 that is >= than `intervalLen`
    int ceilingPowerOf2 = pow(2, ceil(log2(intervalLen)));

    int randomNumber = rand() % ceilingPowerOf2; //this is "as uniform as rand()"

    if (randomNumber < intervalLen)
        return min + randomNumber;      //ok!
    return randInInterval(min, max);    //reject sample and try again
} 

यह विशेष रूप से छोटे अंतराल के लिए अच्छी तरह से काम करता है, क्योंकि 2 की शक्ति वास्तविक अंतराल की लंबाई के लिए "निकट" होगी, और इसलिए मिसाइलों की संख्या छोटी होगी।

पुनश्च
स्पष्ट रूप से पुनरावृत्ति से बचना अधिक कुशल होगा (लॉग सीलिंग से अधिक की गणना करने की आवश्यकता नहीं है ..) लेकिन मुझे लगा कि यह इस उदाहरण के लिए अधिक पठनीय था।


0

ध्यान दें कि ज्यादातर सुझावों में आपको रैंड () फ़ंक्शन से प्राप्त होने वाले प्रारंभिक यादृच्छिक मूल्य, जो आमतौर पर 0 से रैंड_मैक्स तक होता है, बस बर्बाद हो जाता है। आप इसमें से केवल एक यादृच्छिक संख्या बना रहे हैं, जबकि एक ध्वनि प्रक्रिया है जो आपको अधिक दे सकती है।

मान लें कि आप पूर्णांक रैंडम संख्याओं का [न्यूनतम, अधिकतम] क्षेत्र चाहते हैं। हम [0, अधिकतम-मिनट] से शुरू करते हैं

आधार b = अधिकतम-मिनट + 1 लें

आधार बी में रैंड () से प्राप्त एक संख्या का प्रतिनिधित्व करने से शुरू करें।

इस तरह से आपको मंजिल मिल गई है (लॉग (b, RAND_MAX)) क्योंकि बेस बी में प्रत्येक अंक, संभवतः अंतिम एक को छोड़कर, रेंज में एक यादृच्छिक संख्या का प्रतिनिधित्व करता है [0, अधिकतम-मिनट]।

बेशक [न्यूनतम, अधिकतम] की अंतिम पारी प्रत्येक यादृच्छिक संख्या r + मिनट के लिए सरल है।

int n = NUM_DIGIT-1;
while(n >= 0)
{
    r[n] = res % b;
    res -= r[n];
    res /= b;
    n--;
}

यदि NUM_DIGIT आधार b में अंकों की संख्या है जिसे आप निकाल सकते हैं और वह है

NUM_DIGIT = floor(log(b,RAND_MAX))

इसके बाद उपरोक्त NAND_DIGIT यादृच्छिक संख्याओं को 0 से b-1 में से एक RAND_MAX यादृच्छिक संख्या प्रदान करने वाले b <RAND_MAX को निकालने का एक सरल कार्यान्वयन है।


-1

इसके लिए सूत्र बहुत सरल है, इसलिए इस अभिव्यक्ति का प्रयास करें,

 int num = (int) rand() % (max - min) + min;  
 //Where rand() returns a random number between 0.0 and 1.0

2
संपूर्ण समस्या C / C ++ के रैंड का उपयोग कर रही थी जो रनटाइम द्वारा निर्दिष्ट सीमा में पूर्णांक लौटाता है। जैसा कि इस सूत्र में दर्शाया गया है, [0, RAND_MAX] से [MIN, MAX] तक के यादृच्छिक पूर्णांक की मैपिंग पूरी तरह से सीधी नहीं है, यदि आप उनके सांख्यिकीय गुणों या प्रदर्शन को नष्ट करने से बचना चाहते हैं। यदि आपके पास [0, 1] श्रेणी में युगल हैं, तो मानचित्रण आसान है।
Mat --j Zábský

2
आपका उत्तर गलत है, आपको इसके बजाय मापांक का उपयोग करना चाहिए:int num = (int) rand() % (max - min) + min;
Jaime Ivan Cervantes

-2

यदि मैं गलत नहीं हूँ तो निम्नलिखित अभिव्यक्ति निष्पक्ष होनी चाहिए:

std::floor( ( max - min + 1.0 ) * rand() ) + min;

मैं यहां मान रहा हूं कि रैंड () आपको 0.0 और 1.0 के बीच की सीमा में एक यादृच्छिक मान देता है जिसमें 1.0 शामिल नहीं है और यह कि अधिकतम और न्यूनतम इस शर्त के साथ पूर्णांक हैं कि <अधिकतम।


std::floorरिटर्न double, और हमें यहां पूर्णांक मान की आवश्यकता है। मैं सिर्फ intइस्तेमाल करने के बजाय कास्ट करूंगा std::floor
मुस्लिम
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.