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


548

क्या C में एक यादृच्छिक int संख्या उत्पन्न करने के लिए एक फ़ंक्शन है? या मुझे किसी तीसरे पक्ष के पुस्तकालय का उपयोग करना होगा?


1
रैंड () और PRNG "गुणवत्ता" के बारे में comp.lang.c में लंबा विषय ।
लूसर ड्रोग

जवाबों:


662

नोट : rand()सुरक्षा के लिए उपयोग न करें । यदि आपको क्रिप्टोग्राफिक रूप से सुरक्षित नंबर की आवश्यकता है, तो इसके बजाय यह उत्तर देखें

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

srand(time(NULL));   // Initialization, should only be called once.
int r = rand();      // Returns a pseudo-random integer between 0 and RAND_MAX.

संपादित करें : लिनक्स पर, आप यादृच्छिक और srandom का उपयोग करना पसंद कर सकते हैं ।


194
सादगी के लिए +1, लेकिन यह शायद एक अच्छा विचार है कि सरैंड () पर जोर देना केवल एक बार बुलाया जाना चाहिए । इसके अलावा, एक थ्रेडेड एप्लिकेशन में, आप यह सुनिश्चित करना चाहते हैं कि जनरेटर की स्थिति प्रति थ्रेड संग्रहीत की जाती है, और प्रत्येक थ्रेड के लिए एक बार जनरेटर को बीज दें।
RBerteig

41
@trusktr, इसकी जटिल। यहाँ एक कारण है: time()केवल एक बार प्रति सेकंड बदलता है। यदि आप time()प्रत्येक कॉल के लिए rand(), से बीज देते हैं , तो आपको एक सेकंड के दौरान हर कॉल के लिए समान मूल्य मिलेगा। लेकिन इसका बड़ा कारण यह है कि इस तरह के गुणों rand()और कार्यों के उपयोग के मामले के लिए सबसे अच्छी तरह से जाना जाता है, जहां वे प्रति रन एक बार ठीक होते हैं, और हर एक कॉल पर नहीं। अनुपचारित या अप्रमाणित गुणों के साथ "यादृच्छिकता" के आधार पर परेशानी होती है।
RBerteig

9
एक साधारण रैखिक बधाई देने वाले जनरेटर के लिए @trusktr (जो कि rand()आमतौर पर होता है) के साथ बोने का rand()कम से कम कोई प्रभाव नहीं पड़ेगा, और सबसे खराब रूप से जनरेटर के ज्ञात गुणों को तोड़ देगा। यह एक गहन विषय है। गणित और नुकसान के लिए सबसे अच्छा परिचय के रूप में यादृच्छिक संख्याओं पर नुथ वॉल्यूम 2 अध्याय 3 को पढ़ने के साथ शुरू करें ।
RBerteig

21
एक कलाकार के साथ संकलक चेतावनी से बचें:srand((unsigned int)time(NULL));
जिओमास्टर

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

238

rand()में समारोह <stdlib.h>रिटर्न 0 और के बीच एक छद्म यादृच्छिक पूर्णांक RAND_MAX। आप srand(unsigned int seed)एक बीज सेट करने के लिए उपयोग कर सकते हैं ।

एक अलग श्रेणी प्राप्त करने के लिए %ऑपरेटर के साथ उपयोग करना आम बात है rand()(हालांकि यह ध्यान रखें कि यह कुछ हद तक एकरूपता को फेंक देता है)। उदाहरण के लिए:

/* random int between 0 and 19 */
int r = rand() % 20;

यदि आप वास्तव में एकरूपता की परवाह करते हैं तो आप कुछ इस तरह कर सकते हैं:

/* Returns an integer in the range [0, n).
 *
 * Uses rand(), and so is affected-by/affects the same seed.
 */
int randint(int n) {
  if ((n - 1) == RAND_MAX) {
    return rand();
  } else {
    // Supporting larger values for n would requires an even more
    // elaborate implementation that combines multiple calls to rand()
    assert (n <= RAND_MAX)

    // Chop off all of the values that would cause skew...
    int end = RAND_MAX / n; // truncate skew
    assert (end > 0);
    end *= n;

    // ... and ignore results from rand() that fall above that limit.
    // (Worst case the loop condition should succeed 50% of the time,
    // so we can expect to bail out of this loop pretty quickly.)
    int r;
    while ((r = rand()) >= end);

    return r % n;
  }
}

18
यह एक सामान्य अभ्यास है , लेकिन सही नहीं है। यह और यह देखें ।
लेज़र

35
@ लेज़र: यही कारण है कि मैंने कहा "हालांकि यह ध्यान में रखना कि यह एकरूपता को कुछ हद तक फेंक देता है"।
लॉरेंस गोन्साल्वेस

3
@ अभिमन्यु आर्यन %मापांक ऑपरेटर है। यह आपको एक पूर्णांक विभाजन के शेष हिस्से को देता है, इसलिए x % nहमेशा आपको बीच में एक नंबर देगा ( 0और n - 1जब तक xऔर nदोनों सकारात्मक हैं)। तुम अब भी लगता है कि भ्रमित करते हैं, तो एक प्रोग्राम है जो है लिखने का प्रयास करें i0 से 100 तक गिनती, और बाहर प्रिंट i % nकुछ के लिए nअपने को चुनने के छोटे से 100
लारेंस गोंजाल्विस

2
@necromancer मैं आगे गया और एक पूरी तरह से समान समाधान जोड़ा।
लॉरेंस गोन्साल्व्स

2
@ आपके द्वारा पोस्ट किया गया दूसरा लिंक वास्तव में अभी भी पूरी तरह से समान नहीं है। डबल और बैक पर कास्टिंग करने से मदद नहीं मिलती। आपके द्वारा पोस्ट किए गए पहले लिंक में एक पूरी तरह से समान समाधान है, हालांकि यह छोटे ऊपरी सीमा के लिए बहुत कुछ लूप करेगा । मैंने इस उत्तर के लिए एक पूरी तरह से समान समाधान जोड़ा है जो कि छोटे ऊपरी सीमा के लिए भी लूप नहीं होना चाहिए।
लॉरेंस गोन्साल्वेस

53

यदि आपको सुरक्षित यादृच्छिक वर्ण या पूर्णांक चाहिए:

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

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

#include "sodium.h"

int foo()
{
    char myString[32];
    uint32_t myInt;

    if (sodium_init() < 0) {
        /* panic! the library couldn't be initialized, it is not safe to use */
        return 1; 
    }


    /* myString will be an array of 32 random bytes, not null-terminated */        
    randombytes_buf(myString, 32);

    /* myInt will be a random number between 0 and 9 */
    myInt = randombytes_uniform(10);
}

randombytes_uniform() क्रिप्टोग्राफिक रूप से सुरक्षित और निष्पक्ष है।


क्या randombytes_buf को बुलाने से पहले libsodium RNG को सीड किया जाना चाहिए?
user2199593

बस sodium_init()कुछ बिंदु पर कॉल करें । RNG के बारे में चिंता न करें, यह कर्नेल का उपयोग करता है।
स्कॉट आर्किसेवस्की

नोट: मैंने इसके लिए हाल के संपादन को मंजूरी दे दी है, sodium_init()हालांकि यह मेरे उदाहरण का जरूरी हिस्सा नहीं है क्योंकि यह एक महत्वपूर्ण विवरण है।
स्कॉट आर्किसेवस्की जू

29

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

इसलिए, हमें रैंडमाइज़र को एक ऐसे मान के साथ बीजना होगा जो हमेशा बदलता रहता है। हम इसे वर्तमान समय के मूल्य () फ़ंक्शन के साथ खिलाकर करते हैं।

अब, जब हम रैंड () कहते हैं, तो हर बार एक नया रैंडम नंबर तैयार किया जाएगा।

#include <stdio.h>

int random_number(int min_num, int max_num);

int main(void)
{
    printf("Min : 1 Max : 40 %d\n", random_number(1,40));
    printf("Min : 100 Max : 1000 %d\n",random_number(100,1000));
    return 0;
}

int random_number(int min_num, int max_num)
{
    int result = 0, low_num = 0, hi_num = 0;

    if (min_num < max_num)
    {
        low_num = min_num;
        hi_num = max_num + 1; // include max_num in output
    } else {
        low_num = max_num + 1; // include max_num in output
        hi_num = min_num;
    }

    srand(time(NULL));
    result = (rand() % (hi_num - low_num)) + low_num;
    return result;
}

12
अच्छा कोड, लेकिन 'srand (समय (NULL));' कॉल करने के लिए एक अच्छा विचार नहीं है। जब लूप के लिए कॉल किया जाता है तो यह विधि समान संख्या उत्पन्न करती है।
RayOldProf

1
कोड से जुड़े सुझाए गए संपादन अक्सर अस्वीकार हो जाते हैं। किसी ने यहां एक टिप्पणी की "एल्गोरिथ्म गलत था। अधिकतम से अधिक संख्या में उत्पादन कर सकता है"। खुद दावे का मूल्यांकन नहीं किया।
मार्टिन स्मिथ

1
@ मर्टिन स्मिथ समस्याएँ: 1) होना चाहिए else{ low_num=max_num; hi_num=min_num+1;2) विफल रहता है जब hi_num - low_num > INT_MAX। 3) दुर्लभ स्थिति में ओमिट्स मान INT_MAX > hi_num - low_num > RAND_MAX
chux -

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

1
मामूली: hi_num = max_num + 1;अतिप्रवाह के खिलाफ सुरक्षा का अभाव है।
chux -

25

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


2
+1: अच्छा लग रहा है, लेकिन मैं सिर्फ एक अनुमान लगाने का खेल बना रहा था। अगर मैं एक व्यावसायिक अनुप्रयोग में एक यादृच्छिक संख्या जनरेटर का उपयोग करने जा रहा हूं तो मैं निश्चित रूप से इसका उपयोग करूंगा।
Kredns

4
Mersenne ट्विस्टर का उपयोग न करें, xoroshiro128 + या PCG की तरह कुछ अच्छा उपयोग करें। (प्रासंगिक लिंक।)
विड्रेक

17

मानक C फ़ंक्शन है rand()। यह त्यागी के लिए कार्ड का सौदा करने के लिए काफी अच्छा है, लेकिन यह भयानक है। संख्याओं की rand()एक छोटी सूची के माध्यम से चक्र के कई कार्यान्वयन , और कम बिट में छोटे चक्र होते हैं। जिस तरह से कुछ प्रोग्राम कॉल rand()भयानक है, और पास करने के लिए एक अच्छे बीज की गणना srand()करना कठिन है।

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

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <openssl/rand.h>

/* Random integer in [0, limit) */
unsigned int random_uint(unsigned int limit) {
    union {
        unsigned int i;
        unsigned char c[sizeof(unsigned int)];
    } u;

    do {
        if (!RAND_bytes(u.c, sizeof(u.c))) {
            fprintf(stderr, "Can't get random bytes!\n");
            exit(1);
        }
    } while (u.i < (-limit % limit)); /* u.i < (2**size % limit) */
    return u.i % limit;
}

/* Random double in [0.0, 1.0) */
double random_double() {
    union {
        uint64_t i;
        unsigned char c[sizeof(uint64_t)];
    } u;

    if (!RAND_bytes(u.c, sizeof(u.c))) {
        fprintf(stderr, "Can't get random bytes!\n");
        exit(1);
    }
    /* 53 bits / 2**53 */
    return (u.i >> 11) * (1.0/9007199254740992.0);
}

int main() {
    printf("Dice: %d\n", (int)(random_uint(6) + 1));
    printf("Double: %f\n", random_double());
    return 0;
}

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

पूर्णांक के लिए, हम modulo पूर्वाग्रह से बचना चाहते हैं । मान लीजिए कि हमें कुछ यादृच्छिक 4 अंकीय पूर्णांक मिले हैं rand() % 10000, लेकिन rand()केवल 0 से 32767 पर वापस आ सकते हैं (जैसा कि यह माइक्रोसॉफ्ट विंडोज में है)। प्रत्येक संख्या 0 से 2767 तक प्रत्येक संख्या 2768 से 9999 तक अधिक बार दिखाई देगी। पूर्वाग्रह को दूर करने के लिए, हम पुन: प्रयास कर सकते हैं, rand()जबकि मूल्य 2768 से नीचे है, क्योंकि 30068 मान 2768 से 32767 मानचित्र पर समान रूप से 0 से 10000 मान पर है। 9999।

फ़्लोट्स के लिए, हमें 53 यादृच्छिक बिट्स चाहिए, क्योंकि double53 बिट्स ऑफ प्रिसेंस (यह एक IEEE डबल है) मानते हुए। यदि हम 53 से अधिक बिट्स का उपयोग करते हैं, तो हम गोल पूर्वाग्रह प्राप्त करते हैं। कुछ प्रोग्रामर जैसे कोड लिखते हैं rand() / (double)RAND_MAX, लेकिन rand()केवल 31 बिट्स या विंडोज में केवल 15 बिट्स वापस कर सकते हैं।

ओपनएसएसएल के RAND_bytes()बीज स्वयं, शायद /dev/urandomलिनक्स में पढ़कर । यदि हमें कई यादृच्छिक संख्याओं की आवश्यकता है, तो उन सभी से पढ़ना बहुत धीमा होगा /dev/urandom, क्योंकि उन्हें कर्नेल से कॉपी किया जाना चाहिए। ओपनएसएसएल को एक बीज से अधिक यादृच्छिक संख्या उत्पन्न करने की अनुमति देना तेजी से होता है।

यादृच्छिक संख्याओं के बारे में अधिक जानकारी:

  • Perl का Perl_seed () एक उदाहरण है कि C के लिए बीज की गणना कैसे करें srand()। यह मौजूदा समय, प्रक्रिया आईडी और कुछ संकेत से बिट्स को मिलाता है, अगर यह नहीं पढ़ सकता है /dev/urandom
  • OpenBSD के arc4random_uniform () मॉडुलो पूर्वाग्रह की व्याख्या करता है।
  • जावा एपीआई java.util के लिए। यादृच्छिक यादृच्छिक पूर्णांकों से पूर्वाग्रह को हटाने के लिए एल्गोरिदम का वर्णन करता है, और 53 बिट्स को यादृच्छिक फ़्लोट में पैकिंग करता है।

इस विस्तारित उत्तर के लिए धन्यवाद। ध्यान दें कि इस प्रश्न के 24 वर्तमान उत्तरों में से, आप float/ के साथ सौदा करने के लिए एक अतिरिक्त व्याख्या के साथ एक ही थे double, इसलिए मैंने प्रश्न को स्पष्ट कर दिया है ताकि intइसे बहुत व्यापक बनाने से बचने के लिए संख्याओं से चिपके रहें । वहाँ अन्य सी के साथ विशेष रूप से काम कर सवाल कर रहे हैं float/ doubleयादृच्छिक मान है, तो आप निम्न प्रकार के प्रश्नों का जवाब की अपनी दूसरी छमाही repost करने के लिए चाहते हो सकता है stackoverflow.com/questions/13408990/...
कोयूर

11

यदि आपका सिस्टम arc4randomफ़ंक्शन के परिवार का समर्थन करता है तो मैं मानक randफ़ंक्शन के बजाय उन का उपयोग करने की सिफारिश करूंगा ।

arc4randomपरिवार में शामिल हैं:

uint32_t arc4random(void)
void arc4random_buf(void *buf, size_t bytes)
uint32_t arc4random_uniform(uint32_t limit)
void arc4random_stir(void)
void arc4random_addrandom(unsigned char *dat, int datlen)

arc4random एक यादृच्छिक 32-बिट अहस्ताक्षरित पूर्णांक देता है।

arc4random_bufइसमें यादृच्छिक सामग्री पैरामीटर है buf : void *। सामग्री की मात्रा bytes : size_tपैरामीटर द्वारा निर्धारित की जाती है ।

arc4random_uniformएक यादृच्छिक 32-बिट अहस्ताक्षरित पूर्णांक देता है जो नियम का पालन करता है: 0 <= arc4random_uniform(limit) < limitजहां सीमा भी एक अहस्ताक्षरित 32-बिट पूर्णांक है।

arc4random_stirडेटा पढ़ता है /dev/urandomऔर arc4random_addrandomइसके अतिरिक्त आंतरिक यादृच्छिक संख्या पूल को यादृच्छिक बनाने के लिए डेटा को पास करता है ।

arc4random_addrandomइसके द्वारा arc4random_stirपास किए गए डेटा के अनुसार इसे आंतरिक यादृच्छिक संख्या पूल को पॉप्युलेट करने के लिए उपयोग किया जाता है ।

यदि आपके पास ये फ़ंक्शन नहीं हैं, लेकिन आप यूनिक्स पर हैं, तो आप इस कोड का उपयोग कर सकते हैं:

/* This is C, not C++ */
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h> /* exit */
#include <stdio.h> /* printf */

int urandom_fd = -2;

void urandom_init() {
  urandom_fd = open("/dev/urandom", O_RDONLY);

  if (urandom_fd == -1) {
    int errsv = urandom_fd;
    printf("Error opening [/dev/urandom]: %i\n", errsv);
    exit(1);
  }
}

unsigned long urandom() {
  unsigned long buf_impl;
  unsigned long *buf = &buf_impl;

  if (urandom_fd == -2) {
    urandom_init();
  }

  /* Read 4 bytes, or 32 bits into *buf, which points to buf_impl */
  read(urandom_fd, buf, sizeof(long));
  return buf_impl;
}

urandom_initसमारोह को खोलता /dev/urandomउपकरण, और में फ़ाइल वर्णनकर्ता डालता है urandom_fd

urandomसमारोह मूल रूप से करने के लिए एक फोन के रूप में ही है rand, अधिक सुरक्षित को छोड़कर, और यह एक रिटर्न long(आसानी से अस्थिर)।

हालांकि, /dev/urandomथोड़ा धीमा हो सकता है, इसलिए यह अनुशंसा की जाती है कि आप इसे एक अलग यादृच्छिक संख्या जनरेटर के लिए बीज के रूप में उपयोग करें।

आपके सिस्टम एक नहीं है, तो /dev/urandomहै, लेकिन करता है एक है /dev/randomया इसी तरह की फ़ाइल है, तो आप बस पथ के लिए पारित बदल सकते openमें urandom_init। कॉल और API का उपयोग किया जाता है urandom_initऔर urandom(मुझे विश्वास है) POSIX- आज्ञाकारी है, और इस तरह, सभी POSIX आज्ञाकारी प्रणालियों को नहीं, तो अधिकतम काम करना चाहिए।

नोट: /dev/urandomअगर कोई अपर्याप्त एन्ट्रापी उपलब्ध है, तो एक रीड ब्लॉक नहीं करेगा, इसलिए ऐसी परिस्थितियों में उत्पन्न मूल्य क्रिप्टोग्राफिक रूप से असुरक्षित हो सकते हैं। यदि आप इसके बारे में चिंतित हैं, तो उपयोग करें /dev/random, जो हमेशा अपर्याप्त एन्ट्रापी होने पर अवरुद्ध होगा।

यदि आप किसी अन्य सिस्टम (यानी विंडोज) पर हैं, तो randकुछ आंतरिक विंडोज विशिष्ट प्लेटफ़ॉर्म-निर्भर गैर-पोर्टेबल एपीआई का उपयोग करें या करें ।

समारोह के लिए रैपर urandom, randया arc4randomकॉल:

#define RAND_IMPL /* urandom(see large code block) | rand | arc4random */

int myRandom(int bottom, int top){
    return (RAND_IMPL() % (top - bottom)) + bottom;
}

8

STL C. के लिए मौजूद नहीं है। आपको कॉल करना है randया अभी तक बेहतर है random। ये मानक पुस्तकालय शीर्षक में घोषित किए गए हैं stdlib.hrandPOSIX है, randomएक BSD कल्पना फ़ंक्शन है।

के बीच का अंतर randऔर randomवह यह है कि randomरिटर्न एक बहुत अधिक प्रयोग करने योग्य 32-बिट यादृच्छिक संख्या, और randएक 16-बिट संख्या दिखाता है आम तौर पर। बीएसडी मैनपेज बताते हैं कि निचले हिस्से randचक्रीय और अनुमानित हैं, इसलिए randछोटी संख्या के लिए संभावित रूप से बेकार है।


3
@ नील - चूंकि सभी जवाब अब तक एसटीएल का उल्लेख करते हैं, इसलिए मुझे संदेह है कि आवश्यक संदर्भ को हटाने के लिए प्रश्न को त्वरित रूप से संपादित किया गया था।
माइकल बूर

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

@ क्रिस, यदि आप यादृच्छिक संख्या के आकार को जानते हैं, लेकिन अगर रनटाइम के दौरान यादृच्छिक संख्या का आवश्यक आकार बदल जाता है (जैसे कि गतिशील सरणी को फेरबदल करना) तो ऐसे कैवेट के आसपास काम करना मुश्किल होगा।
ड्रीमलैक्स

मैं यहाँ कोई यादृच्छिक-कार्य नहीं ढूँढ सकता :-(
kasia.b

@ उस लिंक में kasia.b है, extern int rand(void);और है extern void srand(unsigned int);
रस्तजेडी

7

इसहाक पर एक नजर है (Indirection, Shift, Accumulate, Add, and Count) । समान रूप से वितरित और इसकी औसत चक्र लंबाई 2 ^ 8295 है।


2
ISAAC अपनी गति के कारण एक दिलचस्प RNG है लेकिन अभी तक इस पर गंभीर क्रिप्टोग्राफिक ध्यान नहीं दिया गया है।
user2398029

4

अपनी पसंद के दो नंबरों के बीच यादृच्छिक संख्या प्राप्त करने का यह एक अच्छा तरीका है।

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

    #define randnum(min, max) \
        ((rand() % (int)(((max) + 1) - (min))) + (min))

int main()
{
    srand(time(NULL));

    printf("%d\n", randnum(1, 70));
}

पहली बार आउटपुट: 39

दूसरी बार आउटपुट: 61

तीसरी बार आउटपुट: 65

आप randnumजो भी संख्या चुनते हैं उसके बाद आप मान बदल सकते हैं, और यह उन दो नंबरों के बीच आपके लिए एक यादृच्छिक संख्या उत्पन्न करेगा।


4

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


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

16
अगर यह बहुत महत्वपूर्ण है कि आपका नंबर वास्तव में यादृच्छिक हो, तो आपको रैंड () फ़ंक्शन का उपयोग नहीं करना चाहिए।
tylerl

1
रैंड से मान बिल्कुल भी "यादृच्छिक" नहीं हैं चाहे आप बीज सेट करें या नहीं। एक ज्ञात बीज को देखते हुए अनुक्रम पूर्वानुमेय है। "सही मायने में" यादृच्छिक संख्या पीढ़ी मुश्किल है। रैंड के साथ कोई एन्ट्रापी शामिल नहीं है।
ड्रीमलैक्स

2
बेशक वे - जनरेटर पुस्तकालय के लिए आप के लिए वरीयता प्राप्त है (शायद शून्य करने के लिए, लेकिन यह एक वैध बीज है)।

4
आह, लेकिन यादृच्छिक संख्याओं का उपयोग करने वाले किसी भी प्रोग्राम को डीबग करने के लिए ज्ञात एल्गोरिदम / ज्ञात बीज आवश्यक है। सिमुलेशन रन के साथ उपयोग किए गए बीज को लॉग करना असामान्य नहीं है ताकि इसे अधिक विस्तृत विश्लेषण के लिए फिर से बनाया जा सके। सरंड () को नहीं बुलाना, श्रंद (1) को बुलाने के बराबर है।
RBerteig

4

एफडब्ल्यूआईडब्ल्यू, जवाब है कि हां, एक stdlib.hफ़ंक्शन कहा जाता है rand; यह फ़ंक्शन मुख्य रूप से गति और वितरण के लिए ट्यून किया गया है, अप्रत्याशित के लिए नहीं। विभिन्न भाषाओं और रूपरेखाओं के लिए लगभग सभी अंतर्निहित यादृच्छिक फ़ंक्शन इस फ़ंक्शन का डिफ़ॉल्ट रूप से उपयोग करते हैं। "क्रिप्टोग्राफ़िक" यादृच्छिक संख्या जनरेटर भी हैं जो बहुत कम अनुमानित हैं, लेकिन बहुत धीमी गति से चलते हैं। इनका उपयोग किसी भी प्रकार के सुरक्षा से संबंधित एप्लिकेशन में किया जाना चाहिए।


4

यह उम्मीद है कि सिर्फ उपयोग करने की तुलना में थोड़ा अधिक यादृच्छिक है srand(time(NULL))

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

int main(int argc, char **argv)
{
    srand((unsigned int)**main + (unsigned int)&argc + (unsigned int)time(NULL));
    srand(rand());

    for (int i = 0; i < 10; i++)
        printf("%d\n", rand());
}

1
यदि इस कार्यक्रम को 1 सेकंड के भीतर कई बार निष्पादित किया जाता है, तो सरंड (रैंड ()) जोड़ने से अनुक्रम की यादृच्छिकता में वृद्धि नहीं होती है। समय (NULL) अभी भी उनमें से प्रत्येक के लिए समान मान लौटाएगा, पहला रैंड () उसी लंबे समय तक लौटेगा, और दूसरा कॉल srand () उसी मान के साथ होगा, जिसके परिणामस्वरूप अभी भी समान यादृच्छिक अनुक्रम होगा। Argc के पते का उपयोग मदद कर सकता है, केवल अगर यह गारंटी दी जाती है कि यह पता कार्यक्रम के प्रत्येक निष्पादन पर अलग होगा, जो हमेशा सच नहीं होता है।
theferrit32

3

खैर, एसटीएल सी ++ है, सी नहीं, इसलिए मुझे नहीं पता कि आप क्या चाहते हैं। यदि आप C चाहते हैं, तो, कार्य rand()और srand()कार्य हैं:

int rand(void);

void srand(unsigned seed);

ये दोनों एएनएसआई सी का हिस्सा हैं। random()समारोह भी है :

long random(void);

लेकिन जहाँ तक मैं बता सकता हूँ, random()मानक ANSI C. नहीं है। एक तृतीय-पक्ष पुस्तकालय एक बुरा विचार नहीं हो सकता है, लेकिन यह सब इस बात पर निर्भर करता है कि किसी संख्या का यादृच्छिक होना जो आपको वास्तव में उत्पन्न करने की आवश्यकता है।


3

C 9 और 50 के बीच यादृच्छिक संख्या उत्पन्न करने का कार्यक्रम

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

int main()
{
    srand(time(NULL));
    int lowerLimit = 10, upperLimit = 50;
    int r =  lowerLimit + rand() % (upperLimit - lowerLimit);
    printf("%d", r);
}

सामान्य तौर पर हम लोअरलिमिट और अपरलिमिट -1 के बीच एक यादृच्छिक संख्या उत्पन्न कर सकते हैं

लोअर लिलिमिट समावेशी है या r L कहें [लोवलीम, अपरलीम)


@ यह वही है जो मैंने स्पष्ट रूप से 9 और 50 के बीटा 9 और 50 का उल्लेख किया है।
शिवम के। ठक्कर

2
आपके मॉडुलो ऑपरेशन ने पूर्वाग्रह का परिचय दिया।
jww

2

rand() यादृच्छिक संख्या उत्पन्न करने के लिए सबसे सुविधाजनक तरीका है।

आप random.org जैसी किसी भी ऑनलाइन सेवा से रैंडम नंबर भी पकड़ सकते हैं।


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

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

void main() 
{
    int visited[100];
    int randValue, a, b, vindex = 0;

    randValue = (rand() % 100) + 1;

    while (vindex < 100) {
        for (b = 0; b < vindex; b++) {
            if (visited[b] == randValue) {
                randValue = (rand() % 100) + 1;
                b = 0;
            }
        }

        visited[vindex++] = randValue;
    }

    for (a = 0; a < 100; a++)
        printf("%d ", visited[a]);
}

तब चर @ b4hand के साथ शीर्ष पर परिभाषित करें
मुहम्मद सादिक

जिस समय मैंने यह टिप्पणी की, मेरे पास सार्वभौमिक संपादन अनुमति नहीं थी, और आमतौर पर कोड परिवर्तन जो वास्तविक उत्तर को बदल देते थे अस्वीकार कर दिया जाएगा। यदि आप अपने उत्तर को ठीक करने की परवाह नहीं करते हैं, तो मैं कर सकता हूँ।
b4hand

यदि आपका इरादा अनूठे मूल्यों के यादृच्छिक क्रमांकन का उत्पादन करना था, तो इस कोड में अभी भी एक बग है। यह दो बार 84 मूल्य का उत्पादन करता है और 48 मूल्य का उत्पादन नहीं करता है। इसके अलावा, यह यादृच्छिक संख्या जनरेटर को बीज नहीं देता है इसलिए अनुक्रम प्रत्येक निष्पादन पर समान है।
b4hand

1
इस कोड में वेरिएबल्स a और b को परिभाषित किया गया है .. यह त्रुटि मुक्त है .. इसमें सिंटैक्स और तार्किक त्रुटि भी नहीं है।
मुहम्मद सादिक

गलत। जैसा कि मैंने उल्लेख किया है कि मैंने पहले ही उत्पादन की पुष्टि कर दी है।
b4hand


1

आधुनिक x86_64 CPU पर आप हार्डवेयर रैंडम नंबर जनरेटर का उपयोग कर सकते हैं _rdrand64_step()

उदाहरण कोड:

#include <immintrin.h>

uint64_t randVal;
if(!_rdrand64_step(&randVal)) {
  // Report an error here: random number generation has failed!
}
// If no error occured, randVal contains a random 64-bit number

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

//generate number in range [min,max)
int random(int min, int max){
    int number = min + rand() % (max - min);
    return number; 
}

//Driver code
int main(){
    srand(time(NULL));
    for(int i = 1; i <= 10; i++){
        printf("%d\t", random(10, 100));
    }
    return 0;
}

0

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

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

int main(int argc, char *argv[])
{
    int i;
    int dice[6];

    for (i = 0; i < 6; i++) 
      dice[i] = 0;
    srand(time(NULL));

    const int TOTAL = 10000000;
    for (i = 0; i < TOTAL; i++)
      dice[(rand() % 6)] += 1;

    double pers = 0.0, tpers = 0.0;
    for (i = 0; i < 6; i++) {
      pers = (dice[i] * 100.0) / TOTAL;
      printf("\t%1d  %5.2f%%\n", dice[i], pers);
      tpers += pers;
    }
    printf("\ttotal:  %6.2f%%\n", tpers);
}

और यहाँ इसका उत्पादन है:

 $ gcc -o t3 t3.c
 $ ./t3 
        1666598  16.67%     
        1668630  16.69%
        1667682  16.68%
        1666049  16.66%
        1665948  16.66%
        1665093  16.65%
        total:  100.00%
 $ ./t3     
        1667634  16.68%
        1665914  16.66%
        1665542  16.66%
        1667828  16.68%
        1663649  16.64%
        1669433  16.69%
        total:  100.00%

मुझे नहीं पता कि आपको अपने रैंडम नंबरों के लिए कितनी वर्दी की जरूरत है, लेकिन ऊपर से ज्यादातर जरूरतों के लिए एक समान प्रतीत होता है।

संपादित करें: PRNG को किसी बेहतर चीज़ से शुरू करना एक अच्छा विचार होगा time(NULL)


रैंड () अन्य यादृच्छिकता परीक्षणों को विफल कर सकता है, जैसे कि डेथर्ड परीक्षण । रैंड () प्लेटफ़ॉर्म से प्लेटफ़ॉर्म तक भिन्न होता है; जीएनयू / लिनक्स से रैंड () मूल्य बीएसडी या विंडोज के मूल्यों से बेहतर हो सकते हैं।
जॉर्ज कोहलर

यह यादृच्छिकता के लिए परीक्षण करने का एक वैध तरीका नहीं है।
विड्राक

उद्देश्य और खतरे / जोखिम मॉडल पर निर्भर करता है। क्रिप्टोग्राफिक रूप से मजबूत RNG के लिए - निश्चित रूप से, RDRAND (या RDSEED) का उपयोग करें। एक साधारण पासा फेंकने वाले (कैसिनो-स्तर पर नहीं) के लिए IMHO उपरोक्त को पर्याप्त होना चाहिए। कीवर्ड " काफी अच्छा " है।
माउस

0

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

srand(time(NULL))

हालाँकि, चूंकि:

  • रैंड उत्पन्न करेगा वही छद्म यादृच्छिक अनुक्रम सरंड में एक ही बीज देगा (देखें man srand);
  • जैसा कि पहले ही कहा गया है, समय फ़ंक्शन दूसरे से केवल दूसरा बदलता है: यदि आपका एप्लिकेशन एक ही सेकंड में कई बार चलाया जाता है, timeतो हर बार समान मान लौटाएगा।

मेरे कार्यक्रम ने संख्याओं का एक ही क्रम उत्पन्न किया। इस समस्या को हल करने के लिए आप 3 चीजें कर सकते हैं:

  1. कुछ अन्य जानकारी के साथ रन टाइम मिक्स आउटपुट (मेरे आवेदन में, आउटपुट नाम):

    srand(time(NULL) | getHashOfString(outputName))

    मैंने अपने हैश फंक्शन के रूप में djb2 ​​का उपयोग किया ।

  2. समय संकल्प बढ़ाएं। मेरे मंच पर clock_gettimeउपलब्ध था, इसलिए मैं इसका उपयोग करता हूं:

    #include<time.h>
    struct timespec nanos;
    clock_gettime(CLOCK_MONOTONIC, &nanos)
    srand(nanos.tv_nsec);
  3. दोनों विधियों का एक साथ उपयोग करें:

    #include<time.h>
    struct timespec nanos;
    clock_gettime(CLOCK_MONOTONIC, &nanos)
    srand(nanos.tv_nsec | getHashOfString(outputName));

विकल्प 3 आपको सुनिश्चित करता है (जहां तक ​​मुझे पता है) सबसे अच्छा बीज यादृच्छिकता है, लेकिन यह केवल बहुत तेज़ एप्लिकेशन पर अंतर पैदा कर सकता है। मेरी राय में विकल्प 2 एक सुरक्षित शर्त है।


इन अनुमानों के साथ भी, क्रिप्टोग्राफ़िक डेटा के लिए रैंड () पर भरोसा न करें।
domenukk

rand()क्रिप्टोग्राफिक डेटा के लिए उपयोग नहीं किया जाना चाहिए, मैं सहमत हूं। कम से कम मेरे लिए, मेरे एप्लिकेशन में क्रिप्टोग्राफ़िक डेटा शामिल नहीं था, इसलिए मेरे लिए यह दी गई विधि ठीक थी।
कोल्डार

0

rand()यहां सभी लोगों के सुझाव के बावजूद , आप rand()तब तक उपयोग नहीं करना चाहते जब तक आपको करना न हो! रैंडम नंबर जो rand()पैदा करते हैं वे अक्सर बहुत खराब होते हैं। लिनक्स मैन पेज से उद्धृत करने के लिए:

लिनक्स सी लाइब्रेरी में rand()और इसके संस्करण srand()समान यादृच्छिक संख्या जनरेटर का उपयोग करते हैं random(3)और srandom(3)इसलिए, निचले क्रम के बिट्स उच्च-क्रम बिट्स के समान यादृच्छिक होना चाहिए। हालांकि, पुराने रैंड () कार्यान्वयन पर, और विभिन्न प्रणालियों पर वर्तमान कार्यान्वयन पर, कम-ऑर्डर बिट्स उच्च-क्रम बिट्स की तुलना में बहुत कम यादृच्छिक हैं । अच्छे यादृच्छिकता की आवश्यकता होने पर पोर्टेबल होने के उद्देश्य से इस फ़ंक्शन का उपयोग न करें। ( उपयोग करें random(3) )

पोर्टेबिलिटी के बारे में, random()पोसिक्स मानक द्वारा भी कुछ समय के लिए परिभाषित किया गया है। rand()पुराना है, यह पहले से ही POSIX.1 कल्पना (IEEE Std 1003.1-1988) में random()पहले से ही दिखाई दिया था , जबकि पहली POSIX.1-2001 (IEEE Std 1003.1-2001) में दिखाई दिया, फिर भी वर्तमान POSIX मानक पहले से POSIX.1-2008 है। (IEEE Std 1003.1-2008), जिसे एक साल पहले ही अपडेट मिला था (IEEE Std 1003.1-2008, 2016 संस्करण)। तो मैं विचार करूंगाrandom() बहुत पोर्टेबल होना ।

POSIX.1-2001 ने भी कार्य lrand48()और mrand48()कार्य शुरू किए , यहां देखें :

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

और बहुत अच्छा छद्म यादृच्छिक स्रोत वह arc4random()फ़ंक्शन है जो कई प्रणालियों पर उपलब्ध है। किसी भी आधिकारिक मानक का हिस्सा नहीं, 1997 के आसपास बीएसडी में दिखाई दिया, लेकिन आप इसे लिनक्स और मैकओएस / आईओएस जैसी प्रणालियों पर पा सकते हैं।


random()विंडोज पर मौजूद नहीं है।
ब्योर्न लिंडक्विस्ट

@ BjörnLindqvist विंडोज भी POSIX सिस्टम नहीं है; यह बाजार पर बहुत ही एकमात्र प्रणाली है जो कम से कम आधार POSIX APIs का समर्थन नहीं करता है (जो कि iOS जैसे सिस्टम को भी बंद कर देता है)। विंडोज केवल समर्थन कर रहा है rand()क्योंकि यह भी सी मानक द्वारा आवश्यक है। किसी और चीज के लिए, आपको विंडोज के लिए एक विशेष समाधान की आवश्यकता है, हमेशा की तरह। #ifdef _WIN32वह वाक्यांश है जिसे आप क्रॉस-प्लेटफ़ॉर्म कोड में सबसे अधिक बार देखेंगे जो विंडोज के साथ-साथ समर्थन करना चाहता है आमतौर पर एक समाधान है जो सभी प्रणालियों के साथ काम करता है और एक जो केवल विंडोज के लिए आवश्यक है।
मिकी

0

लिनक्स सी अनुप्रयोगों के लिए:

यह ऊपर दिए गए उत्तर से मेरा पुन: कोडित कोड है जो मेरी सी कोड प्रथाओं का अनुसरण करता है और किसी भी आकार का एक यादृच्छिक बफर (उचित रिटर्न कोड आदि के साथ) देता है। urandom_open()अपने कार्यक्रम की शुरुआत में एक बार कॉल करना सुनिश्चित करें ।

int gUrandomFd = -1;

int urandom_open(void)
{
    if (gUrandomFd == -1) {
        gUrandomFd = open("/dev/urandom", O_RDONLY);
    }

    if (gUrandomFd == -1) {
        fprintf(stderr, "Error opening /dev/urandom: errno [%d], strerrer [%s]\n",
                  errno, strerror(errno));
        return -1;
    } else {
        return 0;
    }
}


void urandom_close(void)
{
    close(gUrandomFd);
    gUrandomFd = -1;
}


//
// This link essentially validates the merits of /dev/urandom:
// http://sockpuppet.org/blog/2014/02/25/safely-generate-random-numbers/
//
int getRandomBuffer(uint8_t *buf, int size)
{
    int ret = 0; // Return value

    if (gUrandomFd == -1) {
        fprintf(stderr, "Urandom (/dev/urandom) file not open\n");
        return -1;
    }

    ret = read(gUrandomFd, buf, size);

    if (ret != size) {
        fprintf(stderr, "Only read [%d] bytes, expected [%d]\n",
                 ret, size);
        return -1;
    } else {
        return 0;
    }
}

-2

मेरा न्यूनतर समाधान सीमा में यादृच्छिक संख्याओं के लिए काम करना चाहिए [min, max)srand(time(NULL))फ़ंक्शन को लागू करने से पहले उपयोग करें ।

int range_rand(int min_num, int max_num) {
    if (min_num >= max_num) {
        fprintf(stderr, "min_num is greater or equal than max_num!\n"); 
    }
    return min_num + (rand() % (max_num - min_num));
} 

-3

यह कोशिश करो, मैंने इसे पहले से संदर्भित कुछ अवधारणाओं से एक साथ रखा:

/*    
Uses the srand() function to seed the random number generator based on time value,
then returns an integer in the range 1 to max. Call this with random(n) where n is an integer, and you get an integer as a return value.
 */

int random(int max) {
    srand((unsigned) time(NULL));
    return (rand() % max) + 1;
}

16
यह कोड अच्छा नहीं है। कॉलिंग srand()हर बार जब आप कॉल करना चाहते हैं rand()एक भयानक विचार है। चूंकि time()आमतौर पर इस फ़ंक्शन को कॉल करने वाले सेकंड में एक मान तेजी से लौटता है, वही "यादृच्छिक" मान लौटाएगा।
ब्लास्टफर्नेस

3
यह फ़ंक्शन यूनिक्स के random()फ़ंक्शन के साथ भ्रमित हो जाएगा ।
जॉर्ज कोहलर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.