एक पूरी श्रृंखला में समान रूप से यादृच्छिक संख्या उत्पन्न करें


93

मुझे एक निर्दिष्ट अंतराल के भीतर यादृच्छिक संख्या उत्पन्न करने की आवश्यकता है, [अधिकतम; न्यूनतम]।

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

Currenly मैं इस प्रकार उत्पन्न कर रहा हूं:

for(int i=0; i<6; i++)
{
    DWORD random = rand()%(max-min+1) + min;
}

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

Example
min = 3604607;
max = 7654607;

रैंडम संख्या उत्पन्न:

3631594
3609293
3630000
3628441
3636376
3621404

नीचे दिए गए जवाबों से: ठीक है, RAND_MAX 32767 है। मैं C ++ विंडोज प्लेटफॉर्म पर हूं। क्या एक समान वितरण के साथ यादृच्छिक संख्या उत्पन्न करने के लिए कोई अन्य विधि है?


2
एक डाइस-ओ-मैटिक का निर्माण करें: gamesbyemail.com/News/DiceOMatic
Millard

1
मुझे नहीं पता था कि C ++ की rand()वर्दी थी। आप किस पुस्तकालय का उपयोग कर रहे हैं? cstdlib.hकी rand()नहीं है वर्दी: cplusplus.com/reference/cstdlib/rand
माइक वॉरेन

3
नहीं, रैंड () कुछ समान है (कुछ शुरुआती छोटी गाड़ी कार्यान्वयन को छोड़कर)। क्या समान नहीं है रेंज सीमित करने के लिए मापांक '%' ऑपरेटर का उपयोग कर रहा है। एक उचित समाधान के लिए stackoverflow.com/questions/2999075/… देखें , या यदि आपके पास 'arc4random_uniform' उपलब्ध है तो आप इसे सीधे भी उपयोग कर सकते हैं।
जॉन मेकैम

@ Alien01: क्या आप "जूता" ("रांड एक बुरा विचार क्यों है" आदि के द्वारा स्वीकार किए गए उत्तर को बदलने पर विचार करेंगे)? मेरा उत्तर वास्तव में पुराना है और हर बार मुझे इसके लिए एक उत्थान मिलता है, मुझे ऐसा लगता है कि किसी गलत गलियारे में भाग रहा है।
पीटरचेन

सी ++ 11 में यादृच्छिक के बारे में अच्छा श्वेत पत्र
पिप्सिक P ’

जवाबों:


153

क्यों randएक बुरा विचार है

आपके द्वारा यहां प्राप्त अधिकांश उत्तर randफ़ंक्शन और मापांक ऑपरेटर का उपयोग करते हैं। यह विधि समान रूप से संख्या उत्पन्न नहीं कर सकती है (यह सीमा और मूल्य पर निर्भर करती है RAND_MAX), और इसलिए इसे हतोत्साहित किया जाता है।

सी ++ 11 और एक सीमा से अधिक पीढ़ी

C ++ 11 के साथ कई अन्य विकल्प बढ़ गए हैं। जिनमें से एक सीमा में एक यादृच्छिक संख्या उत्पन्न करने के लिए आपकी आवश्यकताओं को पूरा करता है, बहुत अच्छी तरह से std::uniform_int_distribution:। यहाँ एक उदाहरण है:

const int range_from  = 0;
const int range_to    = 10;
std::random_device                  rand_dev;
std::mt19937                        generator(rand_dev());
std::uniform_int_distribution<int>  distr(range_from, range_to);

std::cout << distr(generator) << '\n';

और यहाँ चल उदाहरण है।

अन्य यादृच्छिक जनरेटर

<random>हैडर Bernoulli, प्वासों और सामान्य सहित वितरण के विभिन्न प्रकार के साथ असंख्य अन्य यादृच्छिक संख्या जनरेटर प्रदान करता है।

मैं एक कंटेनर में फेरबदल कैसे कर सकता हूं?

मानक प्रदान करता है std::shuffle, जिसका उपयोग निम्नानुसार किया जा सकता है:

std::vector<int> vec = {4, 8, 15, 16, 23, 42};

std::random_device random_dev;
std::mt19937       generator(random_dev());

std::shuffle(vec.begin(), vec.end(), generator);

एल्गोरिथ्म एक रेखीय जटिलता के साथ, यादृच्छिक रूप से तत्वों को फिर से व्यवस्थित करेगा।

Boost.Random

एक अन्य विकल्प, यदि आपके पास C ++ 11 + संकलक तक पहुंच नहीं है, तो Boost.Random का उपयोग करना है । इसका इंटरफ़ेस C ++ 11 के समान है।


22
इस उत्तर पर ध्यान दें, क्योंकि यह कहीं अधिक आधुनिक है।
gsamaras

यह सही उत्तर है। धन्यवाद! फिर भी, मैं उस कोड के हर चरण का अधिक गहराई से वर्णन देखना चाहूंगा। उदा एक mt19937प्रकार क्या है ?
अपोलो

@Apollo प्रलेखन का कहना है "मात्सुमोतो और निशिमुरा, 1998 द्वारा 32-बिट मेर्सेन ट्विस्टर"। मैं मान रहा हूँ कि यह छद्म यादृच्छिक संख्या उत्पन्न करने के लिए एक एल्गोरिथ्म है।
जूता

@Shoe, किसी दिए गए श्रृंखला के लिए, यह एक ही क्रम में संख्या, उत्पन्न करता है 1 9 6 2 8 7 1 4 7 7। क्या आप हर बार जब हम प्रोग्राम चलाते हैं, तो इसे रैंडमाइज कैसे करें?

1
@ रिचर्ड क्या विकल्प है?
जूता

59

[संपादित करें] चेतावनी: rand()आँकड़ों, सिमुलेशन, क्रिप्टोग्राफी या किसी भी गंभीर चीज़ के लिए उपयोग न करें ।

यह जल्दी में कोई सामान्य मानव के लिए संख्याओं को यादृच्छिक बनाने के लिए पर्याप्त है , अब और नहीं।

बेहतर विकल्पों के लिए @ जेफरी का उत्तर देखें , या क्रिप्टो-सुरक्षित यादृच्छिक संख्याओं के लिए यह उत्तर देखें


आम तौर पर, उच्च बिट्स कम बिट्स की तुलना में बेहतर वितरण दिखाते हैं, इसलिए सरल उद्देश्यों के लिए रेंज की यादृच्छिक संख्या उत्पन्न करने के लिए अनुशंसित तरीका है:

((double) rand() / (RAND_MAX+1)) * (max-min+1) + min

नोट : सुनिश्चित करें कि RAND_MAX + 1 अतिप्रवाह नहीं है (धन्यवाद डेमी)!

विभाजन अंतराल में एक यादृच्छिक संख्या उत्पन्न करता है [0, 1); आवश्यक सीमा तक इसे "खिंचाव" करें। केवल जब अधिकतम-मिनट + 1 RAND_MAX के करीब हो जाता है, तो आपको मार्क रैंडम द्वारा पोस्ट किए गए "बिग्रेड ()" फ़ंक्शन की आवश्यकता होती है।

यह भी मोडुलो के कारण कुछ स्लाइसिंग समस्याओं से बचा जाता है, जो आपकी संख्या को और भी खराब कर सकता है।


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


4
जब वांछित रेंज RAND_MAX से अधिक न हो तब भी BigRand बेहतर परिणाम दे सकता है। विचार करें कि जब RAND_MAX 32767 है और आप 32767 संभावित मान चाहते हैं - उन 32768 रैंडम संख्याओं में से दो (शून्य सहित) एक ही आउटपुट में मैप करने जा रहे हैं, और दो बार दूसरों की तरह होने की संभावना होगी। शायद ही एक आदर्श यादृच्छिक संपत्ति!
मार्क रैनसम

7
(RAND_MAX + 1) एक बुरा विचार है। यह रोलओवर कर सकता है और आपको एक नकारात्मक मूल्य दे सकता है। ((डबल) RAND_MAX) + 1.0: बेहतर की तरह कुछ करने के लिए
डेमी

3
@peterchen: मुझे लगता है कि आप गलत समझ रहे थे कि डेमी क्या कह रहा था। उसका यह मतलब था: ( rand() / ((double)RAND_MAX+1)) * (max-min+1) + min केवल रूपांतरण को डबल करने और समस्या से बचने के लिए आगे बढ़ें।
मूकिंग डक

3
इसके अलावा, यह सीमा में नीचे के 32767 मूल्यों से वितरण को समान रूप से समान रूप से 32767 मानों में वितरित करता है, और शेष 4017233 मूल्यों को इस एल्गोरिथम द्वारा कभी नहीं चुना जाएगा।
मूइंग डक

1
दिया गया उत्तर 1 से बंद है। सही समीकरण है: (((डबल) रैंड) (/ (RAND_MAX + 1.0)) * (अधिकतम-मिनट) + मिनट "अधिकतम-मिनट + 1" का उपयोग% न * करते समय किया जाता है। । आप देखेंगे कि जब आप मिनट = 0, अधिकतम = 1 क्यों करते हैं। पीटरसन या @ पीटर-मोर्टेंसन इसमें संशोधन कर सकते थे।
davepc

17

मैं 2015 में कला की स्थिति के संक्षिप्त अवलोकन के साथ एंग्री शूज़ और पियरचेन के उत्कृष्ट उत्तरों को पूरक करना चाहता हूं:

कुछ अच्छे विकल्प

randutils

randutilsपुस्तकालय (प्रस्तुति) एक दिलचस्प नवीनता, एक सरल अंतरफलक और (घोषित) मजबूत यादृच्छिक क्षमताओं करता है। इसके नुकसान यह है कि यह आपकी परियोजना पर निर्भरता को जोड़ता है और नए होने के नाते, इसका बड़े पैमाने पर परीक्षण नहीं किया गया है। वैसे भी, (MIT लाइसेंस) और हेडर-फ्री होने के नाते, मुझे लगता है कि यह एक कोशिश के लायक है।

न्यूनतम नमूना: एक डाई रोल

#include <iostream>
#include "randutils.hpp"
int main() {
    randutils::mt19937_rng rng;
    std::cout << rng.uniform(1,6) << "\n";
}

यहां तक ​​कि अगर कोई पुस्तकालय में दिलचस्पी नहीं रखता है, तो वेबसाइट ( http://www.pcg-random.org/ ) सामान्य रूप से यादृच्छिक संख्या पीढ़ी के विषय और विशेष रूप से C ++ पुस्तकालय के बारे में कई दिलचस्प लेख प्रदान करती है।

Boost.Random

Boost.Random (प्रलेखन) पुस्तकालय जो प्रेरित है C++11's <random>, जिनके साथ शेयरों में ज्यादा इंटरफ़ेस की। जबकि सैद्धांतिक रूप से भी एक बाहरी निर्भरता है, Boostअब तक "अर्ध-मानक" पुस्तकालय की स्थिति है, और इसके Randomमॉड्यूल को अच्छी गुणवत्ता वाली यादृच्छिक संख्या पीढ़ी के लिए शास्त्रीय विकल्प माना जा सकता है। यह C++11समाधान के संबंध में दो फायदे पेश करता है:

  • यह अधिक पोर्टेबल है, बस C ++ 03 के लिए संकलक समर्थन की आवश्यकता है
  • इसकी random_deviceपेशकश करने के लिए उपयोग करता है प्रणाली विशेष तरीकों अच्छी गुणवत्ता के बोने

एकमात्र छोटा दोष यह है कि मॉड्यूल की पेशकश random_deviceहेडर-केवल नहीं है, किसी को संकलन और लिंक करना है boost_random

न्यूनतम नमूना: एक डाई रोल

#include <iostream>
#include <boost/random.hpp>
#include <boost/nondet_random.hpp>

int main() {
    boost::random::random_device                  rand_dev;
    boost::random::mt19937                        generator(rand_dev());
    boost::random::uniform_int_distribution<>     distr(1, 6);

    std::cout << distr(generator) << '\n';
}

जबकि न्यूनतम नमूना अपना काम अच्छी तरह से करता है, वास्तविक कार्यक्रमों को सुधार की एक जोड़ी का उपयोग करना चाहिए:

  • बनाने के mt19937एक thread_local: जनरेटर काफी मोटा है (> 2 KB) और बेहतर ढेर पर आवंटित नहीं किया गया है
  • mt19937एक से अधिक पूर्णांक के साथ बीज : मर्सिएन ट्विस्टर के पास एक बड़ा राज्य है और इस संकलन के दौरान अधिक एन्ट्रापी का लाभ ले सकता है

कुछ नहीं तो अच्छा विकल्प

C ++ 11 पुस्तकालय

सबसे मुहावरेदार समाधान होते हुए भी, <random>लाइब्रेरी बुनियादी जरूरतों के लिए भी अपने इंटरफेस की जटिलता के बदले में बहुत कुछ नहीं देती है। इसका दोष यह है std::random_device: मानक अपने आउटपुट (जब तक entropy()रिटर्न के रूप में 0) के लिए किसी भी न्यूनतम गुणवत्ता को अनिवार्य नहीं करता है और 2015 तक, मिनग डब्ल्यू (सबसे अधिक उपयोग नहीं किया गया कंपाइलर, लेकिन शायद ही एक गूढ़ विकल्प) 4न्यूनतम नमूने पर प्रिंट करेगा ।

न्यूनतम नमूना: एक डाई रोल

#include <iostream>
#include <random>
int main() {
    std::random_device                  rand_dev;
    std::mt19937                        generator(rand_dev());
    std::uniform_int_distribution<int>  distr(1, 6);

    std::cout << distr(generator) << '\n';
}

यदि कार्यान्वयन सड़ा हुआ नहीं है, तो यह समाधान बूस्ट के बराबर होना चाहिए, और वही सुझाव लागू होते हैं।

गोडोट का समाधान

न्यूनतम नमूना: एक डाई रोल

#include <iostream>
#include <random>

int main() {
    std::cout << std::randint(1,6);
}

यह एक सरल, प्रभावी और साफ समाधान है। केवल दोष, संकलन में कुछ समय लगेगा - लगभग दो साल, C ++ 17 को समय पर जारी किया गया है और प्रायोगिक randintफ़ंक्शन को नए मानक में अनुमोदित किया गया है। शायद उस समय तक भी बोने की गुणवत्ता की गारंटी में सुधार होगा।

बदतर-है-बेहतर समाधान

न्यूनतम नमूना: एक डाई रोल

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

int main() {
    std::srand(std::time(nullptr));
    std::cout << (std::rand() % 6 + 1);
}

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

लेखांकन ट्रोल समाधान

न्यूनतम नमूना: एक डाई रोल

#include <iostream>

int main() {
    std::cout << 9;   // http://dilbert.com/strip/2001-10-25
}

जबकि 9 एक नियमित डाई रोल के लिए कुछ असामान्य परिणाम है, किसी को इस समाधान में अच्छे गुणों के उत्कृष्ट संयोजन की प्रशंसा करनी होगी, जो सबसे तेज, सबसे सरल, सबसे कैश-फ्रेंडली और सबसे पोर्टेबल होने का प्रबंधन करता है। 9 को 4 के साथ प्रतिस्थापित करने से किसी भी प्रकार के डंगऑन और ड्रेगन के लिए एक सही जनरेटर हो जाता है, जबकि अभी भी प्रतीक-युक्त मूल्यों 1, 2 और 3 से बचा जाता है। केवल एक छोटा दोष यह है कि, दिलबर्ट के अकाउंटिंग ट्रॉल्स के बुरे स्वभाव के कारण, यह कार्यक्रम वास्तव में अपरिभाषित व्यवहार करता है।


randutilsपुस्तकालय अब पीसीजी कहा जाता है।
tay10r

11

यदि RAND_MAX32767 है, तो आप बिट्स की संख्या को आसानी से दोगुना कर सकते हैं।

int BigRand()
{
    assert(INT_MAX/(RAND_MAX+1) > RAND_MAX);
    return rand() * (RAND_MAX+1) + rand();
}

मुझे नहीं लगता कि यह काम करता है। छद्म यादृच्छिक संख्या जनरेटर आमतौर पर नियतात्मक होते हैं। उदाहरण के लिए, यदि पहला randकॉल रिटर्न 0x1234और दूसरा 0x5678, तो आपको मिलता है 0x12345678। वह एकमात्र संख्या है जिसे आप प्राप्त कर सकते हैं जो इसके साथ शुरू होती है 0x1234, क्योंकि अगला नंबर हमेशा रहेगा 0x5678। आपको 32-बिट परिणाम मिलते हैं, लेकिन आपके पास केवल 32768 संभावित नंबर हैं।
user694733

@ user694733 एक अच्छा यादृच्छिक संख्या जनरेटर एक अवधि है जो कि उत्पन्न होने वाले आउटपुट की संख्या से अधिक है, इसलिए 0x1234 का हमेशा 0x5678 द्वारा पालन नहीं किया जाएगा।
मार्क रैनसम

9

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

uniform_int आपको जो चाहिए वो करना चाहिए।


मैंने यूनिफ़िन_इंट पर कुछ काम किया है एक मार्सिन ट्विस्टर के साथ और दुर्भाग्यवश कुछ श्रेणियों के लिए जो यूनिफॉर्म_इंट द्वारा लौटाए गए मान के समान नहीं हैं, जैसा कि मुझे उम्मीद थी। उदाहरण के लिए वर्दी_ंट <> (0, 3) 0 से अधिक 1 या 2 का उत्पादन करने के लिए जाता है
ScaryAardvark

@ScaryAardvark uniform_intतब के बुरे कार्यान्वयन की तरह लगता है । एक निष्पक्ष आउटपुट उत्पन्न करना काफी आसान है, यहाँ कई प्रश्न हैं जो विधि का प्रदर्शन करते हैं।
मार्क रैनसम

@ मर्क रंसोम। हाँ, मैं पूरी तरह से सहमत हूँ।
ScaryAardvark

8

यदि आप यादृच्छिकता के बारे में चिंतित हैं और गति के बारे में नहीं, तो आपको एक सुरक्षित यादृच्छिक संख्या पीढ़ी विधि का उपयोग करना चाहिए। ऐसा करने के कई तरीके हैं ... ओपनएसएसएल के रैंडम नंबर जेनरेटर का उपयोग करने के लिए सबसे आसान है ।

आप एन्क्रिप्शन एल्गोरिथ्म (जैसे एईएस ) का उपयोग करके अपना खुद का भी लिख सकते हैं । एक बीज और एक IV उठाकर और फिर एन्क्रिप्शन फ़ंक्शन के आउटपुट को फिर से एन्क्रिप्ट करना। ओपनएसएसएल का उपयोग करना आसान है, लेकिन कम मर्दाना है।


मैं किसी भी तीसरे पक्ष के पुस्तकालय का उपयोग नहीं कर सकता? मैं केवल C ++ तक ही सीमित हूं।
औरन्ध

फिर मर्दाना मार्ग पर जाएं, एईएस या कुछ अन्य एन्क्रिप्शन एल्गोरिदम को लागू करें।
सोपबॉक्स

2
RC4 कोड के लिए तुच्छ है, और सभी व्यावहारिक उद्देश्यों के लिए पर्याप्त यादृच्छिक (WEP को छोड़कर, लेकिन यह पूरी तरह से RC4 की गलती नहीं है)। मेरा मतलब है, यह अविश्वसनीय रूप से तुच्छ कोड है। जैसे, 20 लाइन या ऐसा। विकिपीडिया प्रविष्टि में छद्म कोड है।
स्टीव जेसोप

4
आप तृतीय पक्ष कोड का उपयोग क्यों नहीं कर सकते हैं? यदि यह एक होमवर्क प्रश्न है, तो आपको ऐसा कहना चाहिए, क्योंकि कई लोग इस मामले में पूर्ण समाधान प्रदान करने के बजाय सहायक संकेत देंगे। यदि यह एक होमवर्क नहीं है, तो उस आदमी को लात मारें जो "कोई 3 पार्टी कोड नहीं" कहता है, क्योंकि वह एक मूर्ख है।
DevSolar

OpenSSL रैंड () फ़ंक्शन डॉक्स के लिए अधिक सीधा लिंक: खुलता है। http://sl.org/docs/crypto/rand.html#
DevSolar

5

आपको RAND_MAXअपने विशेष संकलक / पर्यावरण के लिए देखना चाहिए । मुझे लगता है कि अगर आप rand()यादृच्छिक 16-बिट संख्या का उत्पादन कर रहे हैं तो आप इन परिणामों को देखेंगे । (आपको लगता है कि यह एक 32-बिट संख्या होगी)।

मैं वादा नहीं कर सकता यह जवाब है, लेकिन कृपया अपने मूल्य RAND_MAXऔर अपने पर्यावरण पर थोड़ा और विस्तार पोस्ट करें ।


3

जांचें कि RAND_MAXआपके सिस्टम में क्या है - मैं अनुमान लगा रहा हूं कि यह केवल 16 बिट्स है, और आपकी सीमा इसके लिए बहुत बड़ी है।

इससे आगे इस चर्चा को देखें: सी रैंड () फ़ंक्शन का उपयोग कर (या नहीं) का उपयोग करके वांछित श्रेणी के भीतर रैंडम इंटेगर जनरेट करना और नोट्स ।


ठीक है RAND_MAX 32767 है। मैं C ++ विंडोज प्लेटफॉर्म पर हूं। क्या यूनिफॉर्म वितरण के साथ यादृच्छिक संख्या उत्पन्न करने के लिए कोई अन्य तरीका है?
आनंद

2

यह कोड नहीं है, लेकिन यह तर्क आपकी मदद कर सकता है।

static double rnd(void)
{
   return (1.0 / (RAND_MAX + 1.0) * ((double)(rand())) );
}

static void InitBetterRnd(unsigned int seed)
{
    register int i;
    srand( seed );
    for( i = 0; i < POOLSIZE; i++){
        pool[i] = rnd();
    }
}

 // This function returns a number between 0 and 1
 static double rnd0_1(void)
 {
    static int i = POOLSIZE-1;
    double r;

    i = (int)(POOLSIZE*pool[i]);
    r = pool[i];
    pool[i] = rnd();
    return (r);
}

2

यदि आप चाहते हैं कि संख्याएँ समान रूप से सीमा पर वितरित की जाएं, तो आपको अपनी सीमा को कई समान खंडों में तोड़ना चाहिए जो अंकों की आवश्यकता का प्रतिनिधित्व करते हैं। फिर प्रत्येक अनुभाग के लिए न्यूनतम / अधिकतम के साथ एक यादृच्छिक संख्या प्राप्त करें।

एक और नोट के रूप में, आपको शायद उपयोग नहीं करना चाहिए rand()क्योंकि यह वास्तव में यादृच्छिक संख्या उत्पन्न करने में बहुत अच्छा नहीं है। मुझे नहीं पता कि आप किस प्लेटफ़ॉर्म पर चल रहे हैं, लेकिन एक बेहतर कार्य है जिसे आप पसंद कर सकते हैं random()


1

यह [low, high)फ़्लैट का उपयोग किए बिना सीमा पर एक समान वितरण प्रदान करना चाहिए , जब तक कि समग्र रेंज RAND_MAX से कम न हो।

uint32_t rand_range_low(uint32_t low, uint32_t high)
{
    uint32_t val;
    // only for 0 < range <= RAND_MAX
    assert(low < high);
    assert(high - low <= RAND_MAX);

    uint32_t range = high-low;
    uint32_t scale = RAND_MAX/range;
    do {
        val = rand();
    } while (val >= scale * range); // since scale is truncated, pick a new val until it's lower than scale*range
    return val/scale + low;
}

और RAND_MAX से अधिक मूल्यों के लिए आप ऐसा कुछ चाहते हैं

uint32_t rand_range(uint32_t low, uint32_t high)
{
    assert(high>low);
    uint32_t val;
    uint32_t range = high-low;
    if (range < RAND_MAX)
        return rand_range_low(low, high);
    uint32_t scale = range/RAND_MAX;
    do {
        val = rand() + rand_range(0, scale) * RAND_MAX; // scale the initial range in RAND_MAX steps, then add an offset to get a uniform interval
    } while (val >= range);
    return val + low;
}

यह मोटे तौर पर कैसे std :: वर्दी_int_distribution बातें करता है।


0

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

लेकिन ध्यान रखें कि यादृच्छिकता एक समान नहीं है।

संपादित करें: मैंने स्पष्ट करने के लिए "छोटा नमूना" जोड़ा।


"समान रूप से वितरित" का एक अच्छी तरह से परिभाषित अर्थ है, और मानक यादृच्छिक जनरेटर आमतौर पर करीब आते हैं।
पीटरचेन

हां, आप सही हैं, यादृच्छिक संख्या जनरेटर को आउटपुट का उत्पादन करना चाहिए जो समय के साथ आम तौर पर इसके वितरण में समान है। मुझे लगता है कि मेरी बात यह है कि उदाहरणों की एक छोटी संख्या से अधिक (उदाहरण में दिखाया गया है) आउटपुट हमेशा समान नहीं होगा।
Kluge

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

1
विधेयक, यह ऐसी किसी भी बात का संकेत नहीं है। छोटे नमूने ज्यादातर अर्थहीन होते हैं, लेकिन अगर आरएनजी को एक समान माना जाता है और आउटपुट एक समान है, तो यह एक गैर-समान छोटे नमूने की तुलना में क्यों खराब है?
डैन डायर

2
किसी भी तरह से महत्वपूर्ण वितरण गैर-यादृच्छिकता को इंगित करता है: मुझे लगता है कि बिल का अर्थ है कि 6 समान रूप से-प्रायोजित परिणाम भी संदिग्ध होंगे। ओपी में, 6 मान 32k / 4M, या वांछित सीमा के <1% की सीमा में हैं। इस पर झूठे सकारात्मक होने की संभावना पर बहस करने के लिए बहुत छोटा है।
1:17 पर स्टीव जेसोप

0

1 और 10 के बीच संख्या के लिए आदमी 3 रैंड द्वारा दिया गया समाधान है:

j = 1 + (int) (10.0 * (rand() / (RAND_MAX + 1.0)));

आपके मामले में, यह होगा:

j = min + (int) ((max-min+1) * (rand() / (RAND_MAX + 1.0)));

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


1
यह केवल वितरण को और अधिक प्रकट करने के लिए पुनर्व्यवस्थित करता है , लेकिन यह वास्तव में बड़ी श्रेणियों (जैसे ओपी के मामले) के लिए भी नहीं है
मूइंग डक

0

@उपाय ((double) rand() / (RAND_MAX+1)) * (max-min+1) + min

चेतावनी : स्ट्रेचिंग और संभावित सटीक त्रुटियों के कारण मत भूलना (भले ही RAND_MAX काफी बड़ा था), आप केवल समान रूप से "डिब्बे" वितरित करने में सक्षम होंगे और [मिनट, अधिकतम] में सभी नंबर नहीं।


@ समाधान: बिग्रेड

चेतावनी : ध्यान दें कि यह बिट्स को दोगुना करता है, लेकिन फिर भी सामान्य रूप से आपकी सीमा में सभी संख्याओं को उत्पन्न करने में सक्षम नहीं होगा, अर्थात, यह जरूरी नहीं है कि BigRand () अपनी सीमा के बीच सभी संख्याओं को उत्पन्न करेगा।


जानकारी : आपका दृष्टिकोण (मोडुलो) "ठीक" है जब तक कि रैंड () की सीमा आपकी अंतराल सीमा से अधिक हो जाती है और रैंड () "वर्दी" है। सबसे पहले अधिकतम मिनट की संख्या के लिए त्रुटि 1 / (RAND_MAX +1) है।

इसके अलावा, मैं C ++ 11 में नए यादृच्छिक पैकेज ई पर स्विच करने का सुझाव देता हूं , जो रैंड () की तुलना में कार्यान्वयन की बेहतर और अधिक किस्में प्रदान करता है।


0

यह वह उपाय है जो मैं लेकर आया हूं:

#include "<stdlib.h>"

int32_t RandomRange(int32_t min, int32_t max) {
    return (rand() * (max - min + 1) / (RAND_MAX + 1)) + min;
}

यह एक बाल्टी समाधान है, वैचारिक रूप से उपयोग किए जाने वाले समाधान के समान है rand() / RAND_MAX जो 0-1 के बीच एक अस्थायी बिंदु सीमा प्राप्त करने के लिए करते हैं और फिर एक बाल्टी में गोल करते हैं। हालांकि, यह विशुद्ध रूप से पूर्णांक गणित का उपयोग करता है, और निकटतम बकेट को मान को गोल करने के लिए पूर्णांक विभाजन फर्श का लाभ उठाता है।

यह कुछ धारणाएँ बनाता है। सबसे पहले, यह मानता है कि RAND_MAX * (max - min + 1)हमेशा एक के भीतर फिट होगा int32_t। यदि RAND_MAX32767 और 32 बिट इंट गणना का उपयोग किया जाता है, तो आपके पास अधिकतम सीमा 32767 हो सकती है। यदि आपके कार्यान्वयन में बहुत बड़ा RAND_MAX है, तो आप int64_tगणना के लिए एक बड़े पूर्णांक (जैसे ) का उपयोग करके इसे दूर कर सकते हैं । दूसरे, यदि int64_tउपयोग किया जाता है, लेकिन RAND_MAXअभी भी 32767 है, तो अधिक से अधिक रेंज में RAND_MAXआपको संभावित आउटपुट नंबरों में "छेद" मिलना शुरू हो जाएगा। स्केलिंग से प्राप्त किसी भी समाधान के साथ यह संभवतः सबसे बड़ा मुद्दा है rand()

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


-1

बेशक, निम्न कोड आपको यादृच्छिक संख्या नहीं देगा लेकिन छद्म यादृच्छिक संख्या। निम्नलिखित कोड का उपयोग करें

#define QUICK_RAND(m,n) m + ( std::rand() % ( (n) - (m) + 1 ) )

उदाहरण के लिए:

int myRand = QUICK_RAND(10, 20);

आपको कॉल करना होगा

srand(time(0));  // Initialize random number generator.

अन्यथा संख्या यादृच्छिक के पास नहीं होगी।


1
सवाल एक समान वितरण के लिए पूछ रहा है। यह प्रस्तावित समाधान एक समान वितरण का उत्पादन नहीं करेगा। स्टैंडर्ड सी ++ लाइब्रेरी में छद्म यादृच्छिक संख्या पीढ़ी के लिए सुविधाएं हैं । यदि अनुरोध किया जाए तो वे समान वितरण प्रदान करते हैं।
IInspectable

-3

मुझे यह सिर्फ इंटरनेट पर मिला। यह काम करना चाहिए:

DWORD random = ((min) + rand()/(RAND_MAX + 1.0) * ((max) - (min) + 1));

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

यह मेरे लिए सबसे अच्छा काम करता है ... मैं इस सूत्र के साथ बेहतर वितरित यादृच्छिक संख्याओं को प्राप्त करने में सक्षम हूं ..
अनंद

4
यदि आपकी सीमा RAND_MAX से अधिक है, तो परिणाम समान नहीं हो सकते हैं । यही है, रेंज में ऐसे मान हैं जो आपके फ़ंक्शन को कॉल करने में कितनी बार कोई प्रतिनिधित्व नहीं करेंगे।
dmckee --- पूर्व-मध्यस्थ ने बिल्ली का बच्चा

4
इसके अलावा, अगर अधिकतम और मिनट दोनों अहस्ताक्षरित int हैं, और न्यूनतम 0 है, और अधिकतम MAX_UINT है, तो ((अधिकतम) - (न्यूनतम) +1) 0 होगा, और परिणाम हमेशा 0 होगा। गणित के इस प्रकार कर अतिप्रवाह के लिए बाहर देखो! जैसा कि dmckee द्वारा उल्लेख किया गया है, यह गंतव्य सीमा पर वितरण को बढ़ाता है, लेकिन RAND_MAX के अद्वितीय मानों से अधिक की गारंटी नहीं देता है।
19
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.