2009-10-24 17 views
7

मैंगैर दोहरा यादृच्छिक संख्या

for (int i = 1, i<100, i++) 
    int i = arc4random() % array count; 

उपयोग कर रहा हूँ, लेकिन मैं दोहराता हर बार हो रही है। मैं श्रेणी से चुने गए int मान को कैसे भर सकता हूं, ताकि जब प्रोग्राम लूप हो तो मुझे कोई डुप्ली नहीं मिलेगी?

+0

देखें http://stackoverflow.com/questions/1608181/unique-random-numbers-in-an-integer-array-in-the-c-programming-language – outis

+1

यदि आप डुप्लीकेट नहीं चाहते हैं तो आप हैं यादृच्छिकता की तलाश नहीं करना http://en.wikipedia.org/wiki/Randomness, लगता है जैसे आप एक यादृच्छिक शफलिंग एल्गोरिदम की तलाश में हैं http://en.wikipedia.org/wiki/Random_permutation – Maggie

+0

धन्यवाद मैगी ने शफलिंग के बारे में त्वरित पढ़ने के बाद मुझे लगता है कि एल्गोरिदम मैं देख रहा हूँ। – Drahc

उत्तर

16

ऐसा लगता है जैसे आप "सत्य" यादृच्छिकता के बजाय एक सेट को शफल करना चाहते हैं। सीधे शब्दों में एक सरणी जहां सभी पदों नंबर मेल एक काउंटर बना सकते हैं और प्रारंभ:

idx = rnd (numNums);  // return value 0 through numNums-1 
val = num[idx];   // get then number at that position. 
num[idx] = val[numNums-1]; // remove it from pool by overwriting with highest 
numNums--;     // and removing the highest position from pool. 
return val;    // give it back to caller. 

यह एक यादृच्छिक मान प्रदान करेंगे:

num[ 0] = 0 
num[ 1] = 1 
: : 
num[99] = 99 
numNums = 100 

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

यह उपयोग की गई संख्याओं की सूची रखने और उस सूची में कोई नहीं मिलने तक लूप जारी रखने की तुलना में यह एक और निर्धारक समाधान है। पूल के छोटे होने के कारण उस प्रकार के एल्गोरिदम का प्रदर्शन घट जाएगा।

स्थिर मूल्यों का उपयोग करते हुए एक सी फ़ंक्शन इस तरह की चाल करना चाहिए। पूल ऊपर या

int i = myRandom (-1); 

(किसी भी संख्या शून्य या अधिक से अधिक आकार को निर्दिष्ट के साथ) पूल से अगले संख्या (किसी भी नकारात्मक संख्या पर्याप्त होगा) प्राप्त करने के लिए सेट करने के लिए

int i = myRandom (200); 

से कॉल करने की। यदि फ़ंक्शन पर्याप्त स्मृति आवंटित नहीं कर सकता है, तो यह 2 वापस आ जाएगा। यदि पूल में कोई संख्या नहीं छोड़ी गई है, तो यह -1 वापस आ जाएगी (जिस बिंदु पर आप पूल की पुन: प्रारंभ कर सकते हैं यदि आप चाहें)।यहाँ एक इकाई परीक्षण मुख्य साथ समारोह है तुम बाहर की कोशिश करने के लिए:

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

#define ERR_NO_NUM -1 
#define ERR_NO_MEM -2 

int myRandom (int size) { 
    int i, n; 
    static int numNums = 0; 
    static int *numArr = NULL; 

    // Initialize with a specific size. 

    if (size >= 0) { 
     if (numArr != NULL) 
      free (numArr); 
     if ((numArr = malloc (sizeof(int) * size)) == NULL) 
      return ERR_NO_MEM; 
     for (i = 0; i < size; i++) 
      numArr[i] = i; 
     numNums = size; 
    } 

    // Error if no numbers left in pool. 

    if (numNums == 0) 
     return ERR_NO_NUM; 

    // Get random number from pool and remove it (rnd in this 
    // case returns a number between 0 and numNums-1 inclusive). 

    n = rand() % numNums; 
    i = numArr[n]; 
    numArr[n] = numArr[numNums-1]; 
    numNums--; 
    if (numNums == 0) { 
     free (numArr); 
     numArr = 0; 
    } 

    return i; 
} 

int main (void) { 
    int i; 

    srand (time (NULL)); 
    i = myRandom (20); 
    while (i >= 0) { 
     printf ("Number = %3d\n", i); 
     i = myRandom (-1); 
    } 
    printf ("Final = %3d\n", i); 
    return 0; 
} 

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

Number = 19 
Number = 10 
Number = 2 
Number = 15 
Number = 0 
Number = 6 
Number = 1 
Number = 3 
Number = 17 
Number = 14 
Number = 12 
Number = 18 
Number = 4 
Number = 9 
Number = 7 
Number = 8 
Number = 16 
Number = 5 
Number = 11 
Number = 13 
Final = -1 

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

और, यदि आप "एकाधिक पूल" संस्करण की तलाश में हैं, तो मैं इसे पूर्णता के लिए यहां शामिल करता हूं।

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

#define ERR_NO_NUM -1 
#define ERR_NO_MEM -2 

int myRandom (int size, int *ppPool[]) { 
    int i, n; 

    // Initialize with a specific size. 

    if (size >= 0) { 
     if (*ppPool != NULL) 
      free (*ppPool); 
     if ((*ppPool = malloc (sizeof(int) * (size + 1))) == NULL) 
      return ERR_NO_MEM; 
     (*ppPool)[0] = size; 
     for (i = 0; i < size; i++) { 
      (*ppPool)[i+1] = i; 
     } 
    } 

    // Error if no numbers left in pool. 

    if (*ppPool == NULL) 
     return ERR_NO_NUM; 

    // Get random number from pool and remove it (rnd in this 
    // case returns a number between 0 and numNums-1 inclusive). 

    n = rand() % (*ppPool)[0]; 
    i = (*ppPool)[n+1]; 
    (*ppPool)[n+1] = (*ppPool)[(*ppPool)[0]]; 
    (*ppPool)[0]--; 
    if ((*ppPool)[0] == 0) { 
     free (*ppPool); 
     *ppPool = NULL; 
    } 

    return i; 
} 

int main (void) { 
    int i; 
    int *pPool; 

    srand (time (NULL)); 
    pPool = NULL; 
    i = myRandom (20, &pPool); 
    while (i >= 0) { 
     printf ("Number = %3d\n", i); 
     i = myRandom (-1, &pPool); 
    } 
    printf ("Final = %3d\n", i); 
    return 0; 
} 

आप संशोधित main() से देख सकते हैं, तो आपको पहले NULL के लिए एक int सूचक आरंभ करने के लिए तो myRandom() कार्य करने के लिए अपने पते के पारित की जरूरत है। यह प्रत्येक ग्राहक (कोड में स्थान) को अपना स्वयं का पूल रखने की अनुमति देता है जिसे स्वचालित रूप से आवंटित और मुक्त किया जाता है, हालांकि यदि आप चाहें तो पूल अभी भी साझा कर सकते हैं।

+0

असल में मैंने पहले ही मेम हैंडलिंग के साथ समस्या होने का सोचा था जब मैं 200+ संख्याओं को यादृच्छिक बनाने जा रहा हूं। एक प्रश्न हालांकि, अगर मैं छवि को कॉल करने के लिए नंबर का उपयोग कर रहा हूं, तो मैं उपरोक्त कोड को कैसे कार्यान्वित कर सकता हूं। एनएसएसटींग * छविनाम = [एनएसएसटींग स्ट्रिंगविथफॉर्मैट: @ "% d.png, i]; धन्यवाद। – Drahc

+0

@Drahc, 200 संख्याएं बहुत कुछ नहीं है।मैं आपको एक शुरुआत देने के लिए एक सी समारोह जोड़ दूंगा। – paxdiablo

+0

लॉल्ज़। और यहां मैं एमएम खपत की चिंता कर रहा हूँ। प्रोग्रामिंग में वास्तव में युवा आपकी मदद के लिए धन्यवाद। – Drahc

0

आपको पहले से उपयोग की गई संख्याओं का ट्रैक रखने की आवश्यकता है (उदाहरण के लिए, एक सरणी में)। एक यादृच्छिक संख्या प्राप्त करें, और इसे पहले से ही इस्तेमाल कर दिया गया है तो इसे छोड़ दें।

+2

शफलिंग एक अधिक कुशल एल्गोरिदम है और आवश्यकताओं को फिट करता है: http://c-faq.com/lib/shuffle। एचटीएमएल – outis

0

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

यह यादृच्छिक को कंप्यूटर के आउटपुट को शफल करके सुझाव देता है।

पहले उपयोग की गई संख्याओं को छोड़कर कृत्रिम रूप से क्रम को बढ़ाया जा सकता है, लेकिन आंकड़ों की लागत पर जो यादृच्छिकता की छाप देते हैं।

0

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

0

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

1

आप काउंटर एन्क्रिप्ट करने के लिए Format-Preserving Encryption का उपयोग कर सकते हैं। आपका काउंटर सिर्फ 0 ऊपर से चला जाता है, और एन्क्रिप्शन आपकी पसंद की एक कुंजी का उपयोग करता है ताकि इसे जो भी रेडिक्स और चौड़ाई चाहिए, उसके प्रतीत होता है।

ब्लॉक सिफर के पास सामान्य रूप से एक निश्चित ब्लॉक आकार होता है उदा। 64 या 128 बिट्स। लेकिन प्रारूप-संरक्षण एन्क्रिप्शन आपको एईएस जैसे मानक सिफर लेने और एक छोटी-चौड़ाई वाली सिफर बनाने की अनुमति देता है, जो भी आप चाहते हैं कि रेडिक्स और चौड़ाई (जैसे रेडिक्स 2, चौड़ाई 16), एक एल्गोरिदम के साथ जो अभी भी क्रिप्टोग्राफिक रूप से मजबूत है।

यह कभी भी टकराव नहीं होने की गारंटी है (क्योंकि क्रिप्टोग्राफिक एल्गोरिदम 1: 1 मैपिंग बनाते हैं)। यह भी परिवर्तनीय (2-तरफा मैपिंग) है, इसलिए आप परिणामी संख्या ले सकते हैं और आपके द्वारा शुरू किए गए काउंटर वैल्यू पर वापस आ सकते हैं।

AES-FFX इसे प्राप्त करने के लिए एक प्रस्तावित मानक विधि है। मैंने कुछ मूल पायथन कोड के साथ प्रयोग किया है जो एईएस-एफएफएक्स विचार पर आधारित है, हालांकि पूरी तरह अनुरूप नहीं है - see Python code here। यह उदाहरण दे सकता है एक काउंटर को एक यादृच्छिक दिखने वाले 7-अंकों का दशमलव नंबर, या 16-बिट संख्या पर एन्क्रिप्ट करें।

संबंधित मुद्दे