1-5 से 1-7 तक यादृच्छिक श्रेणी का विस्तार करें


692

एक फ़ंक्शन को देखते हुए जो कि 1 से 5 की सीमा में एक यादृच्छिक पूर्णांक बनाता है, एक फ़ंक्शन लिखें जो 1 से 7 की सीमा में यादृच्छिक पूर्णांक बनाता है।

  1. एक सरल उपाय क्या है?
  2. मेमोरी के उपयोग को कम करने या धीमी सीपीयू पर चलाने के लिए एक प्रभावी उपाय क्या है?

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

एक पासा के साथ 5 में से एक खिलाड़ी को चुनते समय हमें इसी तरह की समस्या थी। हमने पासा पलट दिया, जो अधिकतम स्कोर प्राप्त करता है वह चुना जाता है। एकरूपता हासिल की गई थी, लेकिन समय निरंतरता नहीं :)
यूजेंस्क

यदि मैं यह कहते हुए जवाब दे दूं कि क्या मैं नीचे उतर जाऊंगा, तो समस्या यह नहीं है कि आपको दिए गए फ़ंक्शन का उपयोग करना है और बस एक लिखना है जो 1-7 बेतरतीब ढंग से रिटर्न करता है?
डॉक्टर ब्लू

किस बारे में 7 * rand5() / 5?
कीविज़

@kiwixz, जो "1 और 7 के बीच" का उत्पादन करेगा, लेकिन आपको 3 या 6: {1: 19.96, 2: 20.02, 4: 20.01, 5: 19.99, 7: 20.02} रफ प्रतिशत परीक्षण मैन्युअल रूप से नहीं मिलेंगे। 7 * .2, 7 * .4, 7 * .6, 7 * .8, 7 * 1।
पाइथोनलार्री

जवाबों:


572

यह एडम रोसेनफील्ड के समाधान के बराबर है, लेकिन कुछ पाठकों के लिए थोड़ा अधिक स्पष्ट हो सकता है। यह मानता है कि rand5 () एक ऐसा फंक्शन है जो 5 समावेशी के माध्यम से 1 रेंज में सांख्यिकीय रूप से यादृच्छिक पूर्णांक देता है।

int rand7()
{
    int vals[5][5] = {
        { 1, 2, 3, 4, 5 },
        { 6, 7, 1, 2, 3 },
        { 4, 5, 6, 7, 1 },
        { 2, 3, 4, 5, 6 },
        { 7, 0, 0, 0, 0 }
    };

    int result = 0;
    while (result == 0)
    {
        int i = rand5();
        int j = rand5();
        result = vals[i-1][j-1];
    }
    return result;
}

यह कैसे काम करता है? इसे इस तरह से सोचें: कागज पर इस दोहरे आयाम सरणी को प्रिंट करने की कल्पना करें, इसे डार्ट बोर्ड तक बढ़ाएं और बेतरतीब ढंग से डार्ट्स को फेंक दें। यदि आप एक गैर-शून्य मान से टकराते हैं, तो यह 1 और 7 के बीच सांख्यिकीय रूप से यादृच्छिक मूल्य है, क्योंकि चुनने के लिए गैर-शून्य मानों की समान संख्या है। यदि आप एक शून्य को हिट करते हैं, तो बस डार्ट को तब तक फेंकते रहें जब तक आप एक गैर-शून्य को नहीं मारते। यही कोड काम कर रहा है: i और j इंडेक्स बेतरतीब ढंग से डार्ट बोर्ड पर एक स्थान का चयन करते हैं, और यदि हमें अच्छा परिणाम नहीं मिलता है, तो हम डार्ट्स फेंकते रहते हैं।

जैसे एडम ने कहा, यह सबसे खराब स्थिति में हमेशा के लिए चल सकता है, लेकिन सांख्यिकीय रूप से सबसे खराब मामला कभी नहीं होता है। :)


5
मैं इस समाधान के पीछे के तर्क को समझ गया, लेकिन यह समझ नहीं पाया कि यह समान संभावना में कैसे परिणत होता है? क्या कोई गणित समझा सकता है?
user1071840

6
@ user1071840 - यदि rand5समान है, तो valsग्रिड में प्रत्येक सेल को उठाया जाने की समान संभावना है। ग्रिड में अंतराल [1, 7], और चार शून्य में प्रत्येक पूर्णांक की तीन प्रतियां होती हैं। इसलिए परिणामों की "कच्ची" धारा [1, 7] मानों के समरूप मिश्रण की ओर जाती है, साथ ही कुछ शून्य जो किसी भी व्यक्ति के स्वीकृत मूल्य की तुलना में अधिक बार होते हैं। लेकिन इससे कोई फर्क नहीं पड़ता क्योंकि शून्य को छीन लिया जाता है, [1, 7] मूल्यों का एक समान मिश्रण छोड़कर।
डैनियल इयरविकर

3
इसके साथ समस्या को महसूस करने का शॉर्टकट तरीका: यदि आप केवल एक बार rand5 () कॉल कर रहे हैं, तो आपके पास केवल 5 संभावित परिणाम हैं। वहाँ स्पष्ट रूप से कोई रास्ता नहीं है कि अधिक यादृच्छिकता को जोड़ने के बिना 5 से अधिक संभावित परिणामों में बदल सकता है।
डैनियल ईयरविकर

1
लंबा संस्करण: rand5 () में केवल मान (1, 2, 3, 4, 5) हो सकते हैं। इसलिए rand5 () * 5 में केवल मान (5, 10, 15, 20, 25) हो सकते हैं, जो कि पूर्ण श्रेणी (1 ... 25) के समान नहीं है। यदि यह किया जाता है, तो 4 घटाना इसे (-3 ... 21) बना देगा, लेकिन इस मामले में यह (1, 6, 11, 16, 21) हो जाता है, इसलिए अंतिम बिंदु सही हैं लेकिन चार बड़े छेद हैं: ( 2..5), (7..10), (12..15), (17..21)। अंत में आप mod 7 करते हैं और 1 जोड़ते हैं, (2, 7, 5, 3, 1) देते हैं। इसलिए न तो 4 और न ही 6 कभी होते हैं। लेकिन (शॉर्टकट से ऊपर देखें) हमें पता था कि परिणामी रेंज में केवल 5 नंबर ही हो सकते हैं, इसलिए दो अंतराल होने चाहिए थे।
डैनियल इयरविकर

1
आह, क्योंकि हमारे पास केवल rand5 () है, rand2 नहीं है () :-)
gzak

353

कोई (बिल्कुल सही) समाधान नहीं है जो लगातार समय में चलेगा, क्योंकि 1/7 आधार में एक अनंत दशमलव 5 है। एक सरल समाधान अस्वीकृति नमूने का उपयोग करना होगा, जैसे:


int i;
do
{
  i = 5 * (rand5() - 1) + rand5();  // i is now uniformly random between 1 and 25
} while(i > 21);
// i is now uniformly random between 1 and 21
return i % 7 + 1;  // result is now uniformly random between 1 and 7

यह लूप के 25/21 = 1.19 पुनरावृत्तियों का अपेक्षित रनटाइम है, लेकिन हमेशा के लिए लूपिंग की एक असीम रूप से छोटी संभावना है।


7
-1 की जरूरत नहीं है, अगर> 21 को फ़्लिप किया गया है> 26 बी / सी यह कोई फर्क नहीं पड़ता कि मैं कहाँ से कम है, नक्शे के लिए,
बीसीएस

26
मेरा यह समझाने के कारण कि यह सही क्यों है: कहो कि मैं एक प्रोग्राम लिखना चाहता हूं जो 1 से 25 तक एक समान यादृच्छिक संख्याओं की एक धारा का उत्पादन करता है; उसके लिए मैं सिर्फ 5 * (rand5 () - 1) + rand5 () उत्तर में कोड के रूप में वापस कर दूँगा। अब, अगर मैं 1 और 21 के बीच एक समान यादृच्छिक संख्याओं की एक धारा बनाना चाहता हूं, अगर मैं सिर्फ पहली धारा का उपयोग करता हूं, लेकिन इसे फ़िल्टर करें ताकि [22, 25] में संख्याओं को अस्वीकार कर दिया जाए, तो मैं उस धारा का भी निर्माण कर सकता हूं। अगला, अगर मैं यह स्ट्रीम लेता हूं और इसे फ़िल्टर करता हूं ताकि प्रत्येक तत्व x I आउटपुट x% 7 + 1 के लिए, मेरे पास 1 से 7 तक समान यादृच्छिक संख्याओं की एक स्ट्रीम हो! बहुत आसान है, है ना? : D
पगस

6
और आप सही हैं कि यह इस बात पर उबलता है कि क्या आप अनबाउंड सबसे खराब स्थिति रनटाइम के साथ एक सही वितरण चाहते हैं, या एक बाध्य रनटाइम के साथ अपूर्ण वितरण। यह इस तथ्य का परिणाम है कि सभी शक्तियां 5 से 7 तक विभाज्य नहीं हैं, या समकक्ष यदि आपके पास 5 ^ n समान रूप से संभवत: लंबाई n के अनुक्रम हैं, तो प्रत्येक अनुक्रम को 1 से 7 तक एक संख्या को असाइन करने का कोई तरीका नहीं है, जैसे कि प्रत्येक परिणाम 1..7 समान रूप से संभव है।
एडम रोसेनफील्ड

5
@ जूल्स ओलेऑन: मान लीजिए कि लगातार समय में एक समाधान चल रहा था जिसे सबसे खराब स्थिति में Nकॉल से अधिक नहीं करने की गारंटी दी गई थी rand5()। फिर, कॉल के अनुक्रम के 5 ^ N संभावित परिणाम हैं rand5, जिनमें से प्रत्येक का आउटपुट 1-7 है। इसलिए, यदि आप उन सभी संभावित अनुक्रमों को kजोड़ते हैं, जिनका आउटपुट प्रत्येक 1≤ you you7 है, तो संभावना है कि आउटपुट km / 5 ^ N है, जहाँ m ऐसे अनुक्रमों की संख्या है। तो, एम / 5 ^ एन = 1/7, लेकिन इस ==> विरोधाभास के लिए कोई पूर्णांक समाधान (एन, एम) नहीं हैं।
एडम रोसेनफील्ड

4
@paxdiablo: आप गलत हैं। 5 के अनंत अनुक्रम को बनाने वाले एक सच्चे RNG का अवसर ठीक 0 है, इस तथ्य के समान तर्क का उपयोग करते हुए कि एक सिक्के को अनंत बार फ़्लिप करने की गारंटी है कि लगातार शीर्ष की अनंत संख्या उत्पन्न नहीं की जाती है । इसका अर्थ यह भी है कि इस कोड को हमेशा के लिए लूप करने का मौका ठीक 0 है (हालाँकि इसमें कोई सकारात्मक मौका है कि यह किसी भी मनमानी संख्या के लिए लूप करेगा)।
ब्लूराजा - डैनी पफ्लुगुएफ्ट

153

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

एक यादृच्छिक चर की एन्ट्रापी एक अच्छी तरह से परिभाषित मात्रा है। एक यादृच्छिक चर के लिए जो समान संभावनाओं (एक समान वितरण) के साथ एन राज्यों पर ले जाता है, एन्ट्रॉपी लॉग 2 एन है। इस प्रकार, rand5()लगभग 2.32193 बिट्स एन्ट्रापी है, और एंट्रोपी के लगभग 2.80735 बिट्स हैं rand7()। यदि हम यादृच्छिकता के हमारे उपयोग को अधिकतम करने की उम्मीद करते हैं, तो हमें प्रत्येक कॉल से सभी 2.32193 बिट्स एन्ट्रापी का उपयोग करने की आवश्यकता है rand5(), और उन्हें प्रत्येक कॉल के लिए आवश्यक 2.80735 बिट्स एन्ट्रापी उत्पन्न करने के लिए लागू करना है rand7()। फिर, मौलिक सीमा यह है कि हम लॉग (7) / लॉग (5) = 1.20906 कॉल rand5()प्रति कॉल से बेहतर कुछ नहीं कर सकते rand7()

साइड नोट्स: इस उत्तर में सभी लॉगरिदम बेस 2 होंगे जब तक कि अन्यथा निर्दिष्ट न किया गया हो। rand5()[0, 4] rand7()श्रेणी में संख्याओं को लौटाने के लिए मान लिया जाएगा , और [0, 6] श्रेणी में संख्याओं को वापस करने के लिए मान लिया जाएगा। क्रमशः [1, 5] और [1, 7] तक की सीमाएँ तुच्छ हैं।

तो हम ऐसा कैसे करें? हम 0 और 1 के बीच एक असीम रूप से सटीक यादृच्छिक वास्तविक संख्या उत्पन्न करते हैं (उस पल के लिए दिखावा करते हैं कि हम वास्तव में ऐसे असीम रूप से सटीक संख्या की गणना कर सकते हैं और संग्रहीत कर सकते हैं - हम इसे बाद में ठीक कर लेंगे)। हम आधार संख्या 5 में इसके अंक उत्पन्न करके ऐसी संख्या उत्पन्न कर सकते हैं: हम यादृच्छिक संख्या 0. a1 a2 a3 ... iको चुनते हैं , जहाँ प्रत्येक अंक को कॉल द्वारा चुना जाता है rand5()। उदाहरण के लिए, यदि हमारे आरएनजी ने iसभी के लिए एक = 1 चुना है i, तो इस तथ्य की अनदेखी करते हुए कि यह बहुत यादृच्छिक नहीं है, जो वास्तविक संख्या 1/5 + 1/5 2 + 1/5 3 + ... = के अनुरूप होगा 1/4 (एक ज्यामितीय श्रृंखला का योग)।

ठीक है, इसलिए हमने 0 और 1 के बीच एक यादृच्छिक वास्तविक संख्या चुन ली है। अब मैं दावा करता हूं कि इस तरह की यादृच्छिक संख्या समान रूप से वितरित की जाती है। सहज रूप से, यह समझना आसान है, क्योंकि प्रत्येक अंक समान रूप से उठाया गया था, और संख्या असीम रूप से सटीक है। हालांकि, इसका एक औपचारिक प्रमाण कुछ हद तक शामिल है, क्योंकि अब हम असतत वितरण के बजाय एक निरंतर वितरण के साथ काम कर रहे हैं, इसलिए हमें यह साबित करने की आवश्यकता है कि हमारी संख्या एक अंतराल में निहित है [ a, b] प्रो की लंबाई के बराबर कि अंतराल, b - a। प्रमाण को पाठक के लिए एक अभ्यास के रूप में छोड़ दिया जाता है =)।

अब जब हमारे पास रेंज [0, 1] से समान रूप से चयनित एक यादृच्छिक संख्या है, तो हमें आउटपुट के समान [0, 6] रेंज में समान रूप से यादृच्छिक संख्याओं की एक श्रृंखला में परिवर्तित करने की आवश्यकता है rand7()। हम इसे कैसे करते हैं? जैसा हमने अभी किया था उसके ठीक उलट - हम इसे आधार 7 में एक असीम रूप से सटीक दशमलव में बदल देते हैं, और फिर प्रत्येक आधार 7 अंक के एक आउटपुट के अनुरूप होगा rand7()

पहले से उदाहरण लेते हुए, यदि हम rand5()1 की अनंत धारा उत्पन्न करते हैं, तो हमारी यादृच्छिक वास्तविक संख्या 1/4 होगी। 1/4 को बेस 7 में बदलने से हमें अनंत दशमलव 0.15151515 मिलता है ..., इसलिए हम आउटपुट 1, 5, 1, 5, 1, 5, आदि का उत्पादन करेंगे।

ठीक है, इसलिए हमारे पास मुख्य विचार है, लेकिन हमारे पास दो समस्याएं हैं: हम वास्तव में असीम रूप से सटीक वास्तविक संख्या की गणना या स्टोर नहीं कर सकते हैं, इसलिए हम इसके केवल एक सीमित हिस्से से कैसे निपटते हैं? दूसरे, हम वास्तव में इसे आधार 7 में कैसे बदलते हैं?

एक तरह से हम 0 और 1 के बीच की संख्या को आधार 7 में बदल सकते हैं:

  1. 7 से गुणा करें
  2. परिणाम का अभिन्न हिस्सा अगला आधार 7 अंक है
  3. केवल आंशिक अंश छोड़कर, अभिन्न अंग को घटाएं
  4. गोटो स्टेप 1

अनंत परिशुद्धता की समस्या से निपटने के लिए, हम एक आंशिक परिणाम की गणना करते हैं, और परिणाम क्या हो सकता है, इस पर हम एक ऊपरी बाध्यता भी रखते हैं। यही है, मान लें कि हमने rand5()दो बार कॉल किया है और यह 1 बार दोनों बार लौटा है। अब तक हमने जो संख्या जनरेट की है, वह 0.11 (बेस 5) है। जो कुछ भी कॉल करने की अनंत श्रृंखला का rand5()उत्पादन करने के लिए, जो यादृच्छिक संख्या हम पैदा कर रहे हैं वह कभी भी 0.12 से बड़ी नहीं होगी: यह हमेशा सच है कि 0.11 11 0.11xyz ... <0.12।

इसलिए, अब तक की वर्तमान संख्या पर नज़र रखना, और अधिकतम मूल्य, जो हम कभी भी ले सकते हैं, हम दोनों संख्याओं को आधार 7 में बदलते हैं। यदि वे पहले kअंकों पर सहमत होते हैं , तो हम सुरक्षित रूप से अगले kअंकों का उत्पादन कर सकते हैं - चाहे जो भी हो आधार 5 अंकों की अनंत धारा है, वे kआधार 7 के प्रतिनिधित्व के अगले अंकों को कभी प्रभावित नहीं करेंगे !

और वह एल्गोरिथ्म है - के अगले आउटपुट को जनरेट करने के लिए rand7(), हम केवल उतने ही अंक उत्पन्न करते हैं जितने की rand5()हमें यह सुनिश्चित करने की आवश्यकता है कि हम यादृच्छिक वास्तविक संख्या के आधार में रूपांतरण में अगले अंक के मूल्य को निश्चित रूप से जानते हैं। 7. यहाँ है पायथन कार्यान्वयन, एक परीक्षण दोहन के साथ:

import random

rand5_calls = 0
def rand5():
    global rand5_calls
    rand5_calls += 1
    return random.randint(0, 4)

def rand7_gen():
    state = 0
    pow5 = 1
    pow7 = 7
    while True:
        if state / pow5 == (state + pow7) / pow5:
            result = state / pow5
            state = (state - result * pow5) * 7
            pow7 *= 7
            yield result
        else:
            state = 5 * state + pow7 * rand5()
            pow5 *= 5

if __name__ == '__main__':
    r7 = rand7_gen()
    N = 10000
    x = list(next(r7) for i in range(N))
    distr = [x.count(i) for i in range(7)]
    expmean = N / 7.0
    expstddev = math.sqrt(N * (1.0/7.0) * (6.0/7.0))

    print '%d TRIALS' % N
    print 'Expected mean: %.1f' % expmean
    print 'Expected standard deviation: %.1f' % expstddev
    print
    print 'DISTRIBUTION:'
    for i in range(7):
        print '%d: %d   (%+.3f stddevs)' % (i, distr[i], (distr[i] - expmean) / expstddev)
    print
    print 'Calls to rand5: %d (average of %f per call to rand7)' % (rand5_calls, float(rand5_calls) / N)

ध्यान दें कि rand7_gen()एक जनरेटर लौटाता है, क्योंकि इसमें आंतरिक संख्या होती है, जो संख्या 7. बेस में परिवर्तित होती है। next(r7)10000 यादृच्छिक संख्याओं का उत्पादन करने के लिए परीक्षण हार्नेस 10000 बार कॉल करता है , और फिर यह उनके वितरण को मापता है। केवल पूर्णांक गणित का उपयोग किया जाता है, इसलिए परिणाम बिल्कुल सही हैं।

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

इसके एक रन में, मैंने rand5()10000 कॉल के लिए 12091 कॉल किए rand7(), न्यूनतम लॉग (7) / लॉग (5) कॉल को प्राप्त करने के लिए औसतन 4 महत्वपूर्ण आंकड़े, और परिणामस्वरूप आउटपुट एक समान था।

इस कोड को ऐसी भाषा में पोर्ट करने के लिए, जिसमें मनमाने ढंग से बड़े पूर्णांकों का निर्माण नहीं होता है, आपको अपने मूल अभिन्न प्रकार के मूल्यों को pow5और pow7अधिकतम मूल्य को कैप करना होगा - यदि वे बहुत बड़े हो जाते हैं, तो रीसेट करें सब कुछ और शुरू। इससे कॉल की औसत संख्या rand5()प्रति कॉल rand7()बहुत कम हो जाएगी, लेकिन उम्मीद है कि यह 32- या 64-बिट पूर्णांक के लिए बहुत अधिक नहीं बढ़नी चाहिए।


7
एक बहुत ही दिलचस्प जवाब के लिए +1। क्या यह संभव होगा, एक निश्चित मूल्य पर रीसेट करने के बजाय, उपयोग किए जाने वाले बिट्स को स्थानांतरित करने के लिए, और अन्य बिट्स को ऊपर ले जाएं, और मूल रूप से केवल उन बिट्स को रखने के लिए जो उपयोग होने जा रहे हैं? या क्या मैं कुछ न कुछ भूल रहा हूं?
क्रिस लूत्ज

1
मुझे 100% यकीन नहीं है, लेकिन मेरा मानना ​​है कि अगर आपने ऐसा किया है, तो आप वितरण को कभी भी थोड़ा तिरछा कर देंगे (हालांकि मुझे संदेह है कि ऐसा तिरछा ट्रायल के बिना औसत दर्जे का होगा)।
एडम रोसेनफील्ड

FTW! मैंने bignums को छोटा बनाने की कोशिश की लेकिन ऐसा नहीं किया जा सकता क्योंकि 5 की किसी भी शक्ति में 7 की शक्ति के समान कारक नहीं हैं! इसके अलावा, उपज कीवर्ड का अच्छा उपयोग करें। बहुत अच्छा किया।
ईयाल

2
बहुत अच्छा! क्या हम बढ़ते राज्य के बिना अतिरिक्त एन्ट्रापी को बरकरार रख सकते हैं? चाल यह ध्यान देने वाली है कि ऊपरी और निचले दोनों सीमाएं हर समय तर्कसंगत संख्या में होती हैं। हम सटीक खोए बिना इनको जोड़, घटा और गुणा कर सकते हैं। यदि हम यह सब बेस -35 में करते हैं, तो हम लगभग वहाँ हैं। शेष (सात से गुणा करके और भिन्नात्मक भाग को बनाए रखने के लिए) व्यायाम के रूप में छोड़ दिया जाता है।
इयान

@ आदम आपको "अपने मूल अभिन्न प्रकार के अधिकतम मूल्य के लिए pow5 और pow7 के मूल्यों को कैप करना चाहिए" का उल्लेख करना चाहिए। मैं आपका मानना ​​है कि यह वितरण को तिरछा करेगा, कम से कम यदि भोलेपन से किया जाता है।
उत्प्रेरक

36

(मैंने एडम रोसेनफेल्ड के जवाब को चुरा लिया है और इसे लगभग 7% तेजी से चलाया है।)

मान लें कि rand5 () समान वितरण के साथ {0,1,2,3,4} में से एक लौटाता है और लक्ष्य समान वितरण के साथ {0,1,2,3,4,5,6} वापस आ जाता है।

int rand7() {
  i = 5 * rand5() + rand5();
  max = 25;
  //i is uniform among {0 ... max-1}
  while(i < max%7) {
    //i is uniform among {0 ... (max%7 - 1)}
    i *= 5;
    i += rand5(); //i is uniform {0 ... (((max%7)*5) - 1)}
    max %= 7;
    max *= 5; //once again, i is uniform among {0 ... max-1}
  }
  return(i%7);
}

हम सबसे बड़े मूल्य का ट्रैक रख रहे हैं जो लूप को वैरिएबल में बना सकता है max। यदि अब तक का परिणाम अधिकतम% 7 और अधिकतम -1 के बीच है, तो परिणाम उस सीमा में समान रूप से विकृत हो जाएगा। यदि नहीं, तो हम शेष का उपयोग करते हैं, जो कि 0 और अधिकतम% 7-1 के बीच यादृच्छिक है, और एक नया नंबर और एक नया अधिकतम बनाने के लिए रैंड () के लिए एक और कॉल। फिर हम फिर से शुरू करते हैं।

संपादित करें: इस समीकरण में rand5 () x को कॉल करने की संख्या की अपेक्षा करें:

x =  2     * 21/25
   + 3     *  4/25 * 14/20
   + 4     *  4/25 *  6/20 * 28/30
   + 5     *  4/25 *  6/20 *  2/30 * 7/10
   + 6     *  4/25 *  6/20 *  2/30 * 3/10 * 14/15
   + (6+x) *  4/25 *  6/20 *  2/30 * 3/10 *  1/15
x = about 2.21 calls to rand5()

2
1,000,000 कोशिशों में सूचीबद्ध परिणाम: 1 = 47216; 2 = 127,444; 3 = 141,407; 4 = 221,453; 5 = 127,479; 6 = 167,536; 7 = 167,465। जैसा कि आप देख सकते हैं, वितरण की कमी के संबंध में कमी है 1. एक
रॉबर्ट के

2
@ दुष्ट पिस्सू: मुझे लगता है कि आप गलत हैं। क्या आप सुनिश्चित हैं कि इनपुट rand5 () आप 1-5 के बजाय 0-4 निर्मित अपनी परीक्षा के लिए उपयोग कर रहे थे, जैसा कि इस समाधान में निर्दिष्ट है?
एडम रोसेनफील्ड

5
समान रूप से वितरित संख्याओं को जोड़ने से समान रूप से वितरित संख्या में परिणाम नहीं होता है। वास्तव में, आपको सामान्य वितरण के लिए एक उचित अनुमान प्राप्त करने के लिए केवल 6 समान रूप से वितरित चर की राशि की आवश्यकता होती है।
मिच गेहूं

2
@ मिचव्हीट - दो समान रूप से वितरित पूर्णांक जोड़ना, वास्तव में, समान रूप से वितरित यादृच्छिक पूर्णांक प्रदान करता है, बशर्ते कि प्रत्येक संभव राशि बिल्कुल एक तरीके से उत्पन्न की जा सकती है। ऐसा ही होता है अभिव्यक्ति में 5 * rand5() + rand5()
टेड हॉप

28

कलन विधि:

7 को 3 बिट्स के अनुक्रम में दर्शाया जा सकता है

रैंड (5) का उपयोग बेतरतीब ढंग से 0 या 1.
के साथ प्रत्येक बिट को भरने के लिए करें: उदाहरण के लिए: रैंड (5) और

यदि परिणाम 1 या 2 है, तो बिट को 0 से भरें
यदि परिणाम 4 या 5 है,
तो 1 को थोड़ा भरें, यदि परिणाम 3 है, तो इसे अनदेखा करें और इसे फिर से करें (अस्वीकृति)

इस तरह से हम 3 बिट्स को 0/1 के साथ रैंडमली भर सकते हैं और इस तरह 1-7 से नंबर प्राप्त कर सकते हैं।

संपादित करें: यह सबसे सरल और सबसे कुशल उत्तर की तरह लगता है, इसलिए यहां इसके लिए कुछ कोड दिए गए हैं:

public static int random_7() {
    int returnValue = 0;
    while (returnValue == 0) {
        for (int i = 1; i <= 3; i++) {
            returnValue = (returnValue << 1) + random_5_output_2();
        }
    }
    return returnValue;
}

private static int random_5_output_2() {
    while (true) {
        int flip = random_5();

        if (flip < 3) {
            return 0;
        }
        else if (flip > 3) {
            return 1;
        }
    }
}

1
हमेशा रुकने की समस्या के बेहोश दर्शक, क्योंकि एक खराब यादृच्छिक संख्या जनरेटर बस कुछ बिंदु पर बहुत सारे थ्रेड उत्पन्न कर सकता है ।
एलेक्स नॉर्थ-कीज़

"यदि परिणाम 1 या 2 है, तो बिट को 0 से भरें यदि परिणाम 4 या 5 है, तो बिट को 1 से भरें" क्या तर्क है जिसके द्वारा 1,2,4,5 को स्वीकार किया गया था और 3 को अस्वीकार कर दिया गया था? क्या आप इसे समझा सकते हैं?
gkns

@gkns कोई तर्क नहीं है, आपके पास 1 और 2 का मतलब 0 बिट और 3 और 4 का मतलब हो सकता है। 1. महत्वपूर्ण बात यह है कि प्रत्येक विकल्प में 50% होने की संभावना है, इस प्रकार गारंटी है कि आपके फ़ंक्शन की यादृच्छिकता है कम से कम मूल रैंड (5) फ़ंक्शन के रूप में यादृच्छिक। इसका एक बढ़िया उपाय है!
मो बेगी

यह न तो सरल है और न ही कुशल है। Random_5 प्रति random_7 प्रति cals की संख्या सबसे अच्छा 3 आमतौर पर अधिक है। इस पृष्ठ पर अन्य समाधान वास्तव में सर्वश्रेष्ठ के करीब हैं जो लगभग 2.2 है।
ईयाल

1
कोई बात नहीं, मैं "जबकि returnValue == 0" भाग याद किया
NicholasFolk

19
int randbit( void )
{
    while( 1 )
    {
        int r = rand5();
        if( r <= 4 ) return(r & 1);
    }
}

int randint( int nbits )
{
    int result = 0;
    while( nbits-- )
    {
        result = (result<<1) | randbit();
    }
    return( result );
}

int rand7( void )
{
    while( 1 )
    {
        int r = randint( 3 ) + 1;
        if( r <= 7 ) return( r );
    }
}

2
एक सही समाधान, रैंड 5 को औसत 30/7 = 4.29 कॉल करना (रैंड 7 पर कॉल)।
एडम रोसेनफील्ड

17
rand7() = (rand5()+rand5()+rand5()+rand5()+rand5()+rand5()+rand5())%7+1

संपादित करें: यह काफी काम नहीं करता है। यह 1000 में लगभग 2 भाग है (एक आदर्श रैंड 5 मानकर)। बाल्टियाँ मिलती हैं:

value   Count  Error%
1       11158  -0.0035
2       11144  -0.0214
3       11144  -0.0214
4       11158  -0.0035
5       11172  +0.0144
6       11177  +0.0208
7       11172  +0.0144

की राशि पर स्विच करके

n   Error%
10  +/- 1e-3,
12  +/- 1e-4,
14  +/- 1e-5,
16  +/- 1e-6,
...
28  +/- 3e-11

लगता है कि हर 2 जोड़े के लिए परिमाण का एक क्रम प्राप्त होता है

BTW: ऊपर दी गई त्रुटियों की तालिका नमूनाकरण के माध्यम से नहीं बल्कि निम्नलिखित पुनरावृत्ति संबंध द्वारा उत्पन्न की गई थी:

p[x,n]नंबर तरीके से कॉल करने के लिए output=xदिया जा सकता nहै rand5

  p[1,1] ... p[5,1] = 1
  p[6,1] ... p[7,1] = 0

  p[1,n] = p[7,n-1] + p[6,n-1] + p[5,n-1] + p[4,n-1] + p[3,n-1]
  p[2,n] = p[1,n-1] + p[7,n-1] + p[6,n-1] + p[5,n-1] + p[4,n-1]
  p[3,n] = p[2,n-1] + p[1,n-1] + p[7,n-1] + p[6,n-1] + p[5,n-1]
  p[4,n] = p[3,n-1] + p[2,n-1] + p[1,n-1] + p[7,n-1] + p[6,n-1]
  p[5,n] = p[4,n-1] + p[3,n-1] + p[2,n-1] + p[1,n-1] + p[7,n-1]
  p[6,n] = p[5,n-1] + p[4,n-1] + p[3,n-1] + p[2,n-1] + p[1,n-1]
  p[7,n] = p[6,n-1] + p[5,n-1] + p[4,n-1] + p[3,n-1] + p[2,n-1]

8
यह एक समान वितरण नहीं है। यह वर्दी के बहुत करीब है, लेकिन पूरी तरह से समान नहीं है।
एडम रोसेनफील्ड

आह! पासा और 7 का। यदि आप कहने जा रहे हैं कि मैं गलत हूं, तो आपको पाठक के लिए एक अभ्यास के रूप में प्रमाण नहीं छोड़ना चाहिए।
बीसीएस

45
यह प्रमाण कि यह एक समान नहीं है: यादृच्छिकता जा सकती है 5 ^ 7 संभावित तरीके हैं, और जैसा कि 5 ^ 7 7 का गुणक नहीं है, यह संभव नहीं है कि सभी 7 राशि समान रूप से होने की संभावना हो। (मूल रूप से, यह 5 से ५ तक अपेक्षाकृत कम प्रधान होता है, या १/ being के आधार ५ में एक समाप्ति दशमलव नहीं होता है।) वास्तव में यह इस बाधा के तहत "सबसे समान" संभव भी नहीं है: प्रत्यक्ष अभिकलन से पता चलता है कि 5 ^ 7 = 78125 रकम, आपके द्वारा 1 से 7 बार मान प्राप्त करने की संख्या {1: 11145, 2: 11120, 3: 11120, 4: 11145, 5: 11190, 6: 11215, 7: 11190} है।
श्रीवत्सआर

@ श्रीवत्सआर तो क्या हुआ अगर सात बार रैंड 5 () की राशि लेने के बजाय, हमने इसे 5 * 7 लिया - क्या वह काम नहीं करेगा? 35 ^ 7% 7 = 35 ^ 5% 7 = 0.
18

4
@ क्रिश्चियनअंटनसेन: आप कितनी बार rand5 () करते हैं, तो आपको एक समान वितरण नहीं मिलेगा। यदि आप इसे N बार करते हैं, तो 5 ^ N संभव आउटपुट हैं, जो 7. से विभाज्य नहीं है (यदि आप इसे 35 बार करते हैं, तो 5 ^ 35 हैं, 35 ^ 7 नहीं हैं।) आप करीब और करीब पहुंच जाएंगे। आपके द्वारा उपयोग की जाने वाली कॉल की बड़ी संख्या (और यह किसी भी संख्या में हो सकती है, 7 से विभाज्य नहीं होनी चाहिए), लेकिन IMHO बहुत अधिक संख्या में कॉल का उपयोग करने के बजाय रैंड () में, आप संभवतया उपयोग कर सकते हैं शीर्ष उत्तरों में एल्गोरिथ्म, जो सटीक समान वितरण देता है और जिसकी अपेक्षित संख्या रैंड () के लिए छोटी है।
श्रीवत्सआर

15
int ans = 0;
while (ans == 0) 
{
     for (int i=0; i<3; i++) 
     {
          while ((r = rand5()) == 3){};
          ans += (r < 3) >> i
     }
}

2
एक सही समाधान, रैंड 5 को औसत 30/7 = 4.29 कॉल करना (रैंड 7 पर कॉल)।
एडम रोसेनफील्ड

3
एल्गोरिथ्म को काम करने के लिए छोड़ दिया जाना चाहिए :ans += (r < 3) << i
ऊनी

13

निम्नलिखित {1, 2, 3, 4, 5, 6, 7} पर एक समान वितरण का उत्पादन करता है, एक यादृच्छिक संख्या जनरेटर का उपयोग करके {1, 2, 3, 4, 5} पर एक समान वितरण का उत्पादन करता है। कोड गड़बड़ है, लेकिन तर्क स्पष्ट है।

public static int random_7(Random rg) {
    int returnValue = 0;
    while (returnValue == 0) {
        for (int i = 1; i <= 3; i++) {
            returnValue = (returnValue << 1) + SimulateFairCoin(rg);
        }
    }
    return returnValue;
}

private static int SimulateFairCoin(Random rg) {
    while (true) {
        int flipOne = random_5_mod_2(rg);
        int flipTwo = random_5_mod_2(rg);

        if (flipOne == 0 && flipTwo == 1) {
            return 0;
        }
        else if (flipOne == 1 && flipTwo == 0) {
            return 1;
        }
    }
}

private static int random_5_mod_2(Random rg) {
    return random_5(rg) % 2;
}

private static int random_5(Random rg) {
    return rg.Next(5) + 1;
}    

2
एक सही समाधान (जो आपको वक्र के आगे रखता है), हालांकि बहुत कुशल नहीं है। यह औसतन 25/6 = 4.17 कॉल को random_5_mod_2 प्रति मेला सिक्का फ्लिप करता है, कुल मिलाकर 100/7 = 14.3 कॉल random_5 () प्रति कॉल random_7 () के लिए।
एडम रोसेनफील्ड

दूसरों पर इस समाधान का लाभ यह है कि किसी भी अन्य समान रूप से वितरित सीमा का उत्पादन करने के लिए इसे आसानी से विस्तारित किया जा सकता है। बस बेतरतीब ढंग से प्रत्येक बिट का चयन करें, अमान्य मानों पर फिर से रोलिंग करें (जैसे हमारे मौजूदा समाधान में 0 मान जो 8 नंबर का उत्पादन करता है)।
डेनमैन मैन 16'11

1
संभव अनंत छोरों, आदि
robermorales

1
@robermorales: अत्यधिक संभावना नहीं है।
जेसन

13
int rand7() {
    int value = rand5()
              + rand5() * 2
              + rand5() * 3
              + rand5() * 4
              + rand5() * 5
              + rand5() * 6;
    return value%7;
}

चुने हुए समाधान के विपरीत, एल्गोरिथ्म निरंतर समय में चलेगा। यह हालांकि चुना समाधान के औसत रन समय की तुलना में rand5 के लिए 2 और कॉल करता है।

ध्यान दें कि यह जनरेटर सही नहीं है (संख्या 0 में किसी अन्य संख्या की तुलना में 0.0064% अधिक मौका है), लेकिन अधिकांश व्यावहारिक उद्देश्यों के लिए निरंतर समय की गारंटी शायद इस अशुद्धि को पछाड़ देती है।

व्याख्या

यह समाधान इस तथ्य से लिया गया है कि संख्या 15,624 7 से विभाज्य है और इस प्रकार यदि हम बेतरतीब ढंग से और समान रूप से 0 से 15,624 तक संख्या उत्पन्न करते हैं और फिर mod 7 लेते हैं तो हम एक निकट-समान रैंड 7 जनरेटर प्राप्त कर सकते हैं। 0 से 15,624 तक की संख्याओं को समान रूप से 6 बार रोल करके और उन्हें आधार संख्या 5 के अंकों को बनाने के लिए उपयोग करके उत्पन्न किया जा सकता है:

rand5 * 5^5 + rand5 * 5^4 + rand5 * 5^3 + rand5 * 5^2 + rand5 * 5 + rand5

मॉड 7 के गुण हालांकि हमें समीकरण को थोड़ा सरल बनाने की अनुमति देते हैं:

5^5 = 3 mod 7
5^4 = 2 mod 7
5^3 = 6 mod 7
5^2 = 4 mod 7
5^1 = 5 mod 7

इसलिए

rand5 * 5^5 + rand5 * 5^4 + rand5 * 5^3 + rand5 * 5^2 + rand5 * 5 + rand5

हो जाता है

rand5 * 3 + rand5 * 2 + rand5 * 6 + rand5 * 4 + rand5 * 5 + rand5

सिद्धांत

संख्या 15,624 को यादृच्छिक रूप से नहीं चुना गया था, लेकिन त्वचा की छोटी प्रमेय का उपयोग करके खोज की जा सकती है, जिसमें कहा गया है कि यदि p एक अभाज्य है तो

a^(p-1) = 1 mod p

तो यह हमें देता है,

(5^6)-1 = 0 mod 7

(5 ^ 6) -1 के बराबर है

4 * 5^5 + 4 * 5^4 + 4 * 5^3 + 4 * 5^2 + 4 * 5 + 4

यह आधार 5 फॉर्म में एक संख्या है और इस प्रकार हम देख सकते हैं कि किसी भी यादृच्छिक संख्या जनरेटर से किसी अन्य यादृच्छिक संख्या जनरेटर पर जाने के लिए इस पद्धति का उपयोग किया जा सकता है। हालांकि प्रतिपादक पी -1 का उपयोग करते समय 0 की ओर एक छोटा पूर्वाग्रह हमेशा पेश किया जाता है।

इस दृष्टिकोण को सामान्य बनाने के लिए और अधिक सटीक होने के लिए हमारे पास एक फ़ंक्शन हो सकता है:

def getRandomconverted(frm, to):
    s = 0
    for i in range(to):
        s += getRandomUniform(frm)*frm**i
    mx = 0
    for i in range(to):
        mx = (to-1)*frm**i 
    mx = int(mx/to)*to # maximum value till which we can take mod
    if s < mx:
        return s%to
    else:
        return getRandomconverted(frm, to)

1
यह जनरेटर सटीक है, लेकिन पूरी तरह से समान नहीं है। इसे देखने के लिए, इस तथ्य पर विचार करें कि एक समान जनरेटर [0,15624] में 15625 संभावित परिणाम हैं, जो 7. से विभाज्य नहीं है। यह संख्या 0 (जिसमें 2233/15625 मौका है, और अन्य सिर्फ एक पूर्वाग्रह का परिचय देता है) 2232/15625)। सब के बाद, पहली नज़र में फ़र्मेट की छोटी प्रमेय का उपयोग करना सही लग सकता है, यह कहता है कि (5 ^ 6)% 7 = 1, और नहीं (5 ^ 6)% 7 = 0। उत्तरार्द्ध स्पष्ट रूप से किसी भी घातांक के लिए असंभव है क्योंकि 5 और 7 दोनों प्रमुख संख्याएं हैं। मुझे लगता है कि यह अभी भी एक स्वीकार्य समाधान है, और मैंने इसे प्रतिबिंबित करने के लिए आपकी पोस्ट को संपादित किया है।
एविएटर

12

क्या होमवर्क की समस्याओं को यहां अनुमति दी गई है?

यह फ़ंक्शन 0 और 6 के बीच की संख्या उत्पन्न करने के लिए "बेस 5" गणित को क्रूड करता है।

function rnd7() {
    do {
        r1 = rnd5() - 1;
        do {
            r2=rnd5() - 1;
        } while (r2 > 1);
        result = r2 * 5 + r1;
    } while (result > 6);
    return result + 1;
}

3
एक सही समाधान (जो आपको वक्र के आगे रखता है), हालांकि बहुत कुशल नहीं है। यह प्रत्येक कॉल के लिए rnd5 () के लिए औसत 5 कॉल करता है।
एडम रोसेनफील्ड

कुछ और स्पष्टीकरण की जरूरत है pls
बैरी

1
@ बैरी - सबसे पहले, आप सिर्फ दो यादृच्छिक संख्याओं को एक साथ नहीं जोड़ सकते हैं, आपको एक रैखिक समाधान नहीं मिलता है (पासा की एक जोड़ी पर विचार करें)। अब "बेस 5" पर विचार करें: 00, 01, 02, 03, 04, 10, 11. आधार 5 में 0-6। इसलिए, हमें बस आधार संख्या के 2 अंक उत्पन्न करने की आवश्यकता है, और उन्हें तब तक जोड़ना होगा जब तक हम एक है कि सीमा के भीतर है। यही r2 * 5 + r1 करता है। R2> 1 लूप है क्योंकि हम कभी भी उच्च अंक नहीं चाहेंगे> 1.
हार्टुंग डिके

यह समाधान एक समान वितरण उत्पन्न नहीं करता है। संख्या 1 और 7 को केवल एक तरीके से उत्पन्न किया जा सकता है, लेकिन 6 के माध्यम से 2 प्रत्येक में दो तरीकों से उत्पन्न किया जा सकता है: संख्या 1 के बराबर r1 और r2 के बराबर 0 या r1 के समान संख्या शून्य से 2 और r2 के बराबर। 1. इस प्रकार 2 6 के माध्यम से औसतन दो बार लौटाया जाएगा जैसा कि 1 या 7.
टेड हॉप

12

यदि हम सबसे कुशल उत्तर देने की कोशिश करने के अतिरिक्त अवरोध पर विचार करते हैं, जो कि 1-5 से Iलंबाई के समान रूप से वितरित पूर्णांक के इनपुट स्ट्रीम को दिए गए हैं, तो सबसे लंबी लंबाई के सापेक्ष 1-7 से समान रूप से वितरित पूर्णांकों की mएक धारा का उत्पादन करता है O। करने के लिए mकहते हैं, L(m)

इसका विश्लेषण करने का सबसे सरल तरीका Oक्रमशः धाराओं I और 5-ary और 7-ary संख्याओं का इलाज करना है। यह धारा लेने के मुख्य उत्तर के विचार a1, a2, a3,... -> a1+5*a2+5^2*a3+..और इसी तरह धारा के लिए प्राप्त किया जाता है O

फिर अगर हम लंबाई के इनपुट स्ट्रीम का एक भाग लेते हैं, m choose n s.t. 5^m-7^n=cजहां c>0संभव के रूप में छोटा है। तो फिर वहाँ से एक समान नक्शा पूर्णांकों के लिए लंबाई मीटर के इनपुट स्ट्रीम से है 1करने के लिए 5^mऔर एक अन्य वर्दी 1 से नक्शा पूर्णांकों से 7^nलंबाई के उत्पादन धारा को n हम जब मैप किया पूर्णांक इनपुट धारा से कुछ मामलों कम करने के लिए हो सकता है, जहां से अधिक है 7^n

तो यह L(m)चारों ओर के लिए एक मूल्य देता है m (log5/log7)जो लगभग है .82m

उपरोक्त विश्लेषण के साथ कठिनाई समीकरण है 5^m-7^n=cजो आसान वास्तव में हल करने के लिए नहीं है और इस मामले में जहां से वर्दी मूल्य 1के लिए 5^mअधिक है 7^nऔर हम दक्षता खो देते हैं।

सवाल यह है कि मी (log5 / log7) के सर्वोत्तम संभव मूल्य के करीब कैसे प्राप्त किया जा सकता है। उदाहरण के लिए जब यह संख्या एक पूर्णांक के करीब पहुंचती है तो क्या हम आउटपुट मानों की इस सटीक अभिन्न संख्या को प्राप्त करने का कोई तरीका खोज सकते हैं?

तो 5^m-7^n=cफिर इनपुट धारा से हम प्रभावी रूप से एक समान यादृच्छिक संख्या उत्पन्न 0करने के लिए (5^m)-1और अधिक से अधिक किसी भी मान का उपयोग नहीं करते 7^n। हालांकि इन मूल्यों को बचाया जा सकता है और फिर से उपयोग किया जा सकता है। वे प्रभावी रूप से 1 से संख्याओं का एक समान अनुक्रम उत्पन्न करते हैं 5^m-7^n। तो हम फिर इनका उपयोग करने की कोशिश कर सकते हैं और इन्हें 7-एरी नंबर में बदल सकते हैं ताकि हम और अधिक आउटपुट मान बना सकें।

यदि हम आकार के एक समान इनपुट से प्राप्त पूर्णांकों T7(X)के आउटपुट अनुक्रम की औसत लंबाई होने देते हैं , और यह मान random(1-7)लेते हैं ।X5^m=7^n0+7^n1+7^n2+...+7^nr+s, s<7

तब T7(5^m)=n0x7^n0/5^m + ((5^m-7^n0)/5^m) T7(5^m-7^n0)चूंकि हमारे पास प्रायिकता के साथ लंबाई का कोई क्रम नहीं है 7 ^ n0 / 5 ^ मी लंबाई के अवशिष्ट के 5^m-7^n0साथ (5^m-7^n0)/5^m)

यदि हम केवल प्रतिस्थापन करते रहें तो हम प्राप्त करते हैं:

T7(5^m) = n0x7^n0/5^m + n1x7^n1/5^m + ... + nrx7^nr/5^m  = (n0x7^n0 + n1x7^n1 + ... + nrx7^nr)/5^m

इसलिये

L(m)=T7(5^m)=(n0x7^n0 + n1x7^n1 + ... + nrx7^nr)/(7^n0+7^n1+7^n2+...+7^nr+s)

इसे लगाने का दूसरा तरीका है:

If 5^m has 7-ary representation `a0+a1*7 + a2*7^2 + a3*7^3+...+ar*7^r
Then L(m) = (a1*7 + 2a2*7^2 + 3a3*7^3+...+rar*7^r)/(a0+a1*7 + a2*7^2 + a3*7^3+...+ar*7^r)

सबसे अच्छा संभव मामला मेरा मूल है जहां ऊपर 5^m=7^n+s, जहां s<7

फिर T7(5^m) = nx(7^n)/(7^n+s) = n+o(1) = m (Log5/Log7)+o(1)पहले की तरह।

सबसे खराब स्थिति यह है कि जब हम केवल k और st 5 ^ m = kx7 + s पा सकते हैं।

Then T7(5^m) = 1x(k.7)/(k.7+s) = 1+o(1)

अन्य मामले कहीं न कहीं इनबेटिव हैं। यह देखना दिलचस्प होगा कि हम बहुत बड़े मीटर के लिए कितना अच्छा कर सकते हैं, यानी त्रुटि शब्द को हम कितना अच्छा कर सकते हैं:

T7(5^m) = m (Log5/Log7)+e(m)

यह e(m) = o(1)सामान्य रूप से प्राप्त करना असंभव लगता है लेकिन उम्मीद है कि हम साबित कर सकते हैं e(m)=o(m)

पूरी बात तब 5^mके विभिन्न मूल्यों के लिए 7-एरी अंकों के वितरण पर टिकी हुई है m

मुझे यकीन है कि वहाँ बहुत सी थ्योरी है जो इसे कवर करती है मुझे कुछ बिंदु पर एक नज़र और रिपोर्ट हो सकती है।


+2 (अगर मैं कर सकता था) - यह एकमात्र अच्छा जवाब था (केवल पर्याप्त रूप से विरोध किया गया)। आपको दूसरा सबसे अच्छा उत्तर मिला है जो 32 बिट पूर्णांक में फिट होगा।
रेक्स केर

10

यहां एडम के जवाब का कार्यशील पायथन कार्यान्वयन है ।

import random

def rand5():
    return random.randint(1, 5)

def rand7():
    while True:
        r = 5 * (rand5() - 1) + rand5()
        #r is now uniformly random between 1 and 25
        if (r <= 21):
            break
    #result is now uniformly random between 1 and 7
    return r % 7 + 1

मैं उन एल्गोरिदम को फेंकना पसंद करता हूं जिन्हें मैं पायथन में देख रहा हूं, इसलिए मैं उनके साथ खेल सकता हूं, सोचा कि मैं इसे इस उम्मीद में यहां पोस्ट करूंगा कि यह किसी के लिए उपयोगी है, ऐसा नहीं है कि इसे एक साथ फेंकने में लंबा समय लगा।


नहीं, यह मेरे उत्तर से काफी भिन्न है। आप 21 बार लूप कर रहे हैं और पहले 20 पुनरावृत्तियों के परिणामों को छोड़ रहे हैं। आप इनपुट के रूप में एक रैंड 4 () और एक रैंड 5 () का उपयोग कर रहे हैं, जो स्पष्ट रूप से केवल रैंड 5 () का उपयोग करने के नियमों को तोड़ता है। अंत में, आप एक गैर-समान वितरण का उत्पादन करते हैं।
एडम रोसेनफील्ड

उसके लिए माफ़ करना। जब मैं इस प्रश्न को देखता था तो मैं बहुत थक जाता था, इतना थक जाता था कि मैं आपके एल्गोरिथ्म को पूरी तरह से गलत कर देता था। मैंने वास्तव में इसे पायथन में फेंक दिया क्योंकि मैं समझ नहीं पाया कि आप 21 बार क्यों लूप कर रहे थे। अब बहुत अधिक समझ में आता है। मैंने एक यादृच्छिक के रूप में random.randint (1, 4) बात की थी, लेकिन मुझे लगता है कि आप सही हैं, यह प्रश्न की भावना के खिलाफ है। मैंने कोड ठीक कर दिया है।
जेम्स मैकमोहन

@robermorales - जैसा कि एडम रोसेनफेल्ड ने अपने उत्तर में समझाया है , हर समाधान जो [1, 7] पर एक समान समान वितरण देता है, उसमें कुछ प्रकार के स्वीकार-अस्वीकार लूप शामिल होंगे जो संभावित रूप से अनंत हैं। (हालांकि, अगर rand5()एक सभ्य PRNG है, तो लूप अनंत नहीं होगा क्योंकि अंततः 5*(rand5() - 1) + rand5()निश्चित रूप से <= 21 होगा।)
टेड हॉप

10

यह सरल क्यों नहीं है?

int random7() {
  return random5() + (random5() % 3);
}

इस समाधान में 1 और 7 प्राप्त करने की संभावना मॉडुलो के कारण कम है, हालांकि, यदि आप बस एक त्वरित और पठनीय समाधान चाहते हैं, तो यह रास्ता तय करना है।


13
यह एक समान वितरण का उत्पादन नहीं करता है। यह संभावनाओं को 2-6, 4/25, 5/25, 5/25, 5/25, 3/25, 1/25 के साथ 0-6 की संख्या पैदा करता है, जैसा कि सभी 25 संभावित परिणामों की गणना करके सत्यापित किया जा सकता है।
एडम रोसेनफील्ड

8

यह मानकर कि रैंड (n) का अर्थ है " 0 से n-1 तक एक समान वितरण में यादृच्छिक पूर्णांक ", यहाँ पायथन के रैंडिंट का उपयोग करके एक कोड नमूना है, जिसका प्रभाव है। यह केवल रंडिन (5) , और स्थिरांक का उपयोग करता है, रैंडिंट (7) के प्रभाव का उत्पादन करने के लिए । थोड़ा मूर्खतापूर्ण, वास्तव में

from random import randint
sum = 7
while sum >= 7:
    first = randint(0,5)   
    toadd = 9999
    while toadd>1:
        toadd = randint(0,5)
    if toadd:
        sum = first+5
    else:
        sum = first

assert 7>sum>=0 
print sum

1
@robermorales क्योंकि पायथन के पास नहीं है do ... while। यह हो सकता है 1337, या 12345, या किसी भी संख्या> 1.
tckmn

8

एडम रोसेनफील्ड के सही उत्तर के पीछे का आधार है:

  • x = 5 ^ n (उसके मामले में: n = 2)
  • [1, x] श्रेणी के भीतर नंबर y प्राप्त करने के लिए n rand5 कॉल में हेरफेर करें
  • z = ((int) (x / 7)) * 7
  • यदि y> z, फिर से प्रयास करें। और वापसी y% 7 + 1

जब n 2 के बराबर होता है, तो आपके पास 4 फेंक-दूर संभावनाएं हैं: y = {22, 23, 24, 25}। यदि आप n बराबर 6 का उपयोग करते हैं, तो आपके पास केवल 1 थ्रो-दूर है: y = {15625}।

5 ^ 6 = 15625
7 * 2232 = 15624

आप rand5 को अधिक बार कॉल करते हैं। हालांकि, आपके पास थ्रो-दूर मूल्य (या अनंत लूप) प्राप्त करने की बहुत कम संभावना है। अगर वहाँ y के लिए कोई संभव फेंक दूर मूल्य पाने के लिए एक रास्ता है, मैं इसे अभी तक नहीं मिला है।


1
फेंकने के मूल्यों के बिना कोई मामला नहीं है - अगर कोई फेंकवा नहीं था, तो 5 ^ n और 7 ^ m का एक कारक होगा। लेकिन वे (शक्तियां) primes की हैं, इसलिए वे नहीं करते हैं।
रेक्स केर

8

यहाँ मेरा जवाब है:

static struct rand_buffer {
  unsigned v, count;
} buf2, buf3;

void push (struct rand_buffer *buf, unsigned n, unsigned v)
{
  buf->v = buf->v * n + v;
  ++buf->count;
}

#define PUSH(n, v)  push (&buf##n, n, v)

int rand16 (void)
{
  int v = buf2.v & 0xf;
  buf2.v >>= 4;
  buf2.count -= 4;
  return v;
}

int rand9 (void)
{
  int v = buf3.v % 9;
  buf3.v /= 9;
  buf3.count -= 2;
  return v;
}

int rand7 (void)
{
  if (buf3.count >= 2) {
    int v = rand9 ();

    if (v < 7)
      return v % 7 + 1;

    PUSH (2, v - 7);
  }

  for (;;) {
    if (buf2.count >= 4) {
      int v = rand16 ();

      if (v < 14) {
        PUSH (2, v / 7);
        return v % 7 + 1;
      }

      PUSH (2, v - 14);
    }

    // Get a number between 0 & 25
    int v = 5 * (rand5 () - 1) + rand5 () - 1;

    if (v < 21) {
      PUSH (3, v / 7);
      return v % 7 + 1;
    }

    v -= 21;
    PUSH (2, v & 1);
    PUSH (2, v >> 1);
  }
}

यह दूसरों की तुलना में थोड़ा अधिक जटिल है, लेकिन मेरा मानना ​​है कि यह रैंड 5 पर कॉल को कम करता है। अन्य समाधानों की तरह, इसमें एक छोटी संभावना है कि यह लंबे समय तक लूप कर सकता है।


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

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


6

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

$num = 0;
$possibilities = 1;

sub rand7
{
  while( $possibilities < 7 )
  {
    $num = $num * 5 + int(rand(5));
    $possibilities *= 5;
  }
  my $result = $num % 7;
  $num = int( $num / 7 );
  $possibilities /= 7;
  return $result;
}

आपका वितरण समान नहीं है, कम से कम पहली कॉल पर। वास्तव में, $possibilitiesलूप से बाहर निकलने और लौटने के लिए हमेशा 25 से बढ़े हैं। तो, आपका पहला परिणाम है [0-124] % 7, जो समान रूप से वितरित नहीं किया गया है क्योंकि 125 % 7 != 0(यह 6 है, वास्तव में)।
बरनार्ड पौलूस

6

मुझे 1 से शुरू होने वाली पर्वतमाला पसंद नहीं है, इसलिए मैं 0 से शुरू करूँगा :-)

unsigned rand5()
{
    return rand() % 5;
}

unsigned rand7()
{
    int r;

    do
    {
        r =         rand5();
        r = r * 5 + rand5();
        r = r * 5 + rand5();
        r = r * 5 + rand5();
        r = r * 5 + rand5();
        r = r * 5 + rand5();
    } while (r > 15623);

    return r / 2232;
}

यह एक विजेता है। यह समान संभावना वाले सभी 7 परिणामों का उत्पादन करता है। from collections import defaultdict def r7(n): if not n: yield [] else: for i in range(1, 6): for j in r7(n-1): yield [i] + j def test_r7(): d = defaultdict(int) for x in r7(6): s = (((((((((x[5] * 5) + x[4]) * 5) + x[3]) * 5) + x[2]) * 5) + x[1]) * 5) + x[0] if s <= 15623: d[s % 7] += 1 print d
११:३४ पर हुग्डब्रोर्न

5

वहां आप जाते हैं, समान वितरण और शून्य rand5 कॉल।

def rand7:
    seed += 1
    if seed >= 7:
        seed = 0
    yield seed

बीज को पहले से सेट करने की आवश्यकता है।


5

मुझे पता है कि इसका उत्तर दिया गया है, लेकिन क्या यह ठीक काम करता है, लेकिन मैं आपको यह नहीं बता सकता कि क्या यह एक पूर्वाग्रह है। मेरा 'परीक्षण' बताता है कि यह कम से कम, उचित है।

शायद एडम रोसेनफील्ड टिप्पणी करने के लिए पर्याप्त होगा?

मेरा (भोला?) विचार यह है:

Rand5 संचित करें जब तक कि एक रैंड 7 बनाने के लिए पर्याप्त यादृच्छिक बिट्स न हों। यह अधिकतम 2 रैंड 5 है। रैंड 7 नंबर प्राप्त करने के लिए मैं संचित मूल्य मॉड 7 का उपयोग करता हूं।

संचायक अतिप्रवाह से बचने के लिए, और चूंकि संचायक mod ​​7 है तो मैं संचायक के mod 7 को लेता हूं:

(5a + rand5) % 7 = (k*7 + (5a%7) + rand5) % 7 = ( (5a%7) + rand5) % 7

रैंड 7 () फ़ंक्शन निम्नानुसार है:

(मैं रैंड 5 की रेंज 0-4 और रैंड 7 इसी तरह 0-6 है।)

int rand7(){
  static int    a=0;
  static int    e=0;
  int       r;
  a = a * 5 + rand5();
  e = e + 5;        // added 5/7ths of a rand7 number
  if ( e<7 ){
    a = a * 5 + rand5();
    e = e + 5;  // another 5/7ths
  }
  r = a % 7;
  e = e - 7;        // removed a rand7 number
  a = a % 7;
  return r;
}

संपादित करें: 100 मिलियन परीक्षणों के लिए परिणाम जोड़े गए।

'रियल' रैंड फ़ंक्शन 5 या 7 मॉड

rand5: avg = 1.999802 0: 20003944 1: 19999889 2: 20003690 3: 19996938 4: 19995539 rand7: avg = 3.000111 0: 14282851 1: 14282879 2: 14284554 3: 14288546 4: 14292388 5: 14282388 6: 142836 6

मेरी रांड and

औसत ठीक दिखता है और संख्या वितरण भी ठीक दिखता है।

randt: avg = 3.000080 0: 14288793 1: 14280135 2: 14287848 3: 14285277 4: 14286341 5: 14278663 6: 14292943


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

क्या अनुक्रमिक सहसंबंध इनमें से कई समाधानों पर लागू होगा?
दार्शनिकोर्न

क्या अनुक्रमिक सहसंबंध इनमें से कई समाधानों पर लागू होगा? मुझे यह प्रयास किए हुए कुछ समय हो गया है और मुझे लगा कि मैंने इसे समझाया है। इसे देखते हुए, ऐसा लगता है कि मैं rand5 से एक पूल में यादृच्छिक बिट्स जमा कर रहा हूं, यह सुनिश्चित करना पर्याप्त है कि एक रैंड 7 नंबर बनाने के लिए पर्याप्त वापस लेने से पहले जमा हो गया है और यह सुनिश्चित करना कि मैं अपने संचायक को ओवरफ्लो नहीं करता हूं।
फिल्कोब्बरन

4

ऊपर सुरुचिपूर्ण एल्गोरिदम का उल्लेख किया गया है, लेकिन यहां पहुंचने का एक तरीका है, हालांकि यह गोल चक्कर हो सकता है। मैं मान 0 से उत्पन्न मान रहा हूँ।

R2 = यादृच्छिक संख्या जनरेटर 2 से कम मान दे रहा है (नमूना स्थान = {0, 1})
R8 = यादृच्छिक संख्या जनरेटर 8 से कम मान दे रहा है (नमूना स्थान = {0, 1, 2, 3, 4, 5, 6, 7 })

R2 से R8 उत्पन्न करने के लिए, आप R2 को तीन बार चलाएंगे, और 3 अंक के साथ बाइनरी नंबर के रूप में सभी 3 रन के संयुक्त परिणाम का उपयोग करेंगे। जब R2 को तीन बार दौड़ाया जाता है तो यहां मानों की सीमा होती है:

० ० ० -> ०


1 1 1 -> 7

अब R8 से R7 जेनरेट करने के लिए, हम बस R7 को फिर से चलाते हैं अगर यह 7 वापस आता है:

int R7() {
  do {
    x = R8();
  } while (x > 6)
  return x;
}

राउंडअबाउट समाधान आर 5 से आर 2 उत्पन्न करना है (जैसे हमने आर 7 को आर 7 से उत्पन्न किया है), फिर आर 8 से आर 8 और फिर आर 7 से आर 7।


दूसरों की संख्या की तरह, यह दृष्टिकोण आर 7 कॉल के अनुसार एक मनमाने ढंग से लंबे समय तक ले सकता है, क्योंकि आप आर 8 से सेवन्स की लंबी स्ट्रिंग प्राप्त कर सकते हैं।
एलेक्स नॉर्थ-कीज़

4

यहां एक समाधान है जो पूरी तरह से पूर्णांक के भीतर फिट बैठता है और लगभग 4% इष्टतम के भीतर है (अर्थात {0..6} में हर एक के लिए {0..4} में 1.26 यादृच्छिक संख्याओं का उपयोग करता है)। स्काला में कोड, लेकिन गणित किसी भी भाषा में यथोचित रूप से स्पष्ट होना चाहिए: आप इस तथ्य का लाभ उठाते हैं कि 7 ^ 9 + 7 ^ 8 5 ^ 11 के बहुत करीब है। तो आप बेस 5 में 11 अंकों की संख्या चुनते हैं, और फिर इसे आधार 7 में 9 अंकों की संख्या के रूप में व्याख्या करते हैं यदि यह सीमा में है (9 आधार 7 संख्या दे रहा है), या 8 अंकों की संख्या के रूप में यदि यह 9 अंकों की संख्या से अधिक है, आदि। ।:

abstract class RNG {
  def apply(): Int
}

class Random5 extends RNG {
  val rng = new scala.util.Random
  var count = 0
  def apply() = { count += 1 ; rng.nextInt(5) }
}

class FiveSevener(five: RNG) {
  val sevens = new Array[Int](9)
  var nsevens = 0
  val to9 = 40353607;
  val to8 = 5764801;
  val to7 = 823543;
  def loadSevens(value: Int, count: Int) {
    nsevens = 0;
    var remaining = value;
    while (nsevens < count) {
      sevens(nsevens) = remaining % 7
      remaining /= 7
      nsevens += 1
    }
  }
  def loadSevens {
    var fivepow11 = 0;
    var i=0
    while (i<11) { i+=1 ; fivepow11 = five() + fivepow11*5 }
    if (fivepow11 < to9) { loadSevens(fivepow11 , 9) ; return }
    fivepow11 -= to9
    if (fivepow11 < to8) { loadSevens(fivepow11 , 8) ; return }
    fivepow11 -= to8
    if (fivepow11 < 3*to7) loadSevens(fivepow11 % to7 , 7)
    else loadSevens
  }
  def apply() = {
    if (nsevens==0) loadSevens
    nsevens -= 1
    sevens(nsevens)
  }
}

यदि आप दुभाषिया (वास्तव में REPL) में एक परीक्षण चिपकाते हैं, तो आपको मिलता है:

scala> val five = new Random5
five: Random5 = Random5@e9c592

scala> val seven = new FiveSevener(five)
seven: FiveSevener = FiveSevener@143c423

scala> val counts = new Array[Int](7)
counts: Array[Int] = Array(0, 0, 0, 0, 0, 0, 0)

scala> var i=0 ; while (i < 100000000) { counts( seven() ) += 1 ; i += 1 }
i: Int = 100000000

scala> counts
res0: Array[Int] = Array(14280662, 14293012, 14281286, 14284836, 14287188,
14289332, 14283684)

scala> five.count
res1: Int = 125902876

यह वितरण अच्छा और सपाट है (प्रत्येक बिन में 10 ^ 8 के 1/7 के 10k के अनुसार, लगभग-गौसियन वितरण से अपेक्षित)।


3

एक रोलिंग कुल का उपयोग करके , आप दोनों कर सकते हैं

  • एक समान वितरण बनाए रखें; तथा
  • यादृच्छिक क्रम में किसी भी तत्व का त्याग नहीं करना है।

ये दोनों समस्याएं सरलीकृत rand(5)+rand(5)...समाधान के साथ एक मुद्दा है । निम्नलिखित पायथन कोड दिखाता है कि इसे कैसे लागू किया जाए (इसका अधिकांश वितरण साबित हो रहा है)।

import random
x = []
for i in range (0,7):
    x.append (0)
t = 0
tt = 0
for i in range (0,700000):
    ########################################
    #####            qq.py             #####
    r = int (random.random () * 5)
    t = (t + r) % 7
    ########################################
    #####       qq_notsogood.py        #####
    #r = 20
    #while r > 6:
        #r =     int (random.random () * 5)
        #r = r + int (random.random () * 5)
    #t = r
    ########################################
    x[t] = x[t] + 1
    tt = tt + 1
high = x[0]
low = x[0]
for i in range (0,7):
    print "%d: %7d %.5f" % (i, x[i], 100.0 * x[i] / tt)
    if x[i] < low:
        low = x[i]
    if x[i] > high:
        high = x[i]
diff = high - low
print "Variation = %d (%.5f%%)" % (diff, 100.0 * diff / tt)

और यह आउटपुट परिणाम दिखाता है:

pax$ python qq.py
0:   99908 14.27257
1:  100029 14.28986
2:  100327 14.33243
3:  100395 14.34214
4:   99104 14.15771
5:   99829 14.26129
6:  100408 14.34400
Variation = 1304 (0.18629%)

pax$ python qq.py
0:   99547 14.22100
1:  100229 14.31843
2:  100078 14.29686
3:   99451 14.20729
4:  100284 14.32629
5:  100038 14.29114
6:  100373 14.33900
Variation = 922 (0.13171%)

pax$ python qq.py
0:  100481 14.35443
1:   99188 14.16971
2:  100284 14.32629
3:  100222 14.31743
4:   99960 14.28000
5:   99426 14.20371
6:  100439 14.34843
Variation = 1293 (0.18471%)

एक सरलीकृत rand(5)+rand(5), उन मामलों को अनदेखा करता है, जहां यह 6 से अधिक रिटर्न देता है, 18% की एक विशिष्ट विविधता है, जो ऊपर दिखाए गए विधि से 100 गुना अधिक है:

pax$ python qq_notsogood.py
0:   31756 4.53657
1:   63304 9.04343
2:   95507 13.64386
3:  127825 18.26071
4:  158851 22.69300
5:  127567 18.22386
6:   95190 13.59857
Variation = 127095 (18.15643%)

pax$ python qq_notsogood.py
0:   31792 4.54171
1:   63637 9.09100
2:   95641 13.66300
3:  127627 18.23243
4:  158751 22.67871
5:  126782 18.11171
6:   95770 13.68143
Variation = 126959 (18.13700%)

pax$ python qq_notsogood.py
0:   31955 4.56500
1:   63485 9.06929
2:   94849 13.54986
3:  127737 18.24814
4:  159687 22.81243
5:  127391 18.19871
6:   94896 13.55657
Variation = 127732 (18.24743%)

और, निक्सुज की सलाह पर, मैंने स्क्रिप्ट को साफ कर दिया है ताकि आप केवल rand7...सामान निकाल सकें और उपयोग कर सकें :

import random

# rand5() returns 0 through 4 inclusive.

def rand5():
    return int (random.random () * 5)

# rand7() generator returns 0 through 6 inclusive (using rand5()).

def rand7():
    rand7ret = 0
    while True:
        rand7ret = (rand7ret + rand5()) % 7
        yield rand7ret

# Number of test runs.

count = 700000

# Work out distribution.

distrib = [0,0,0,0,0,0,0]
rgen =rand7()
for i in range (0,count):
    r = rgen.next()
    distrib[r] = distrib[r] + 1

# Print distributions and calculate variation.

high = distrib[0]
low = distrib[0]
for i in range (0,7):
    print "%d: %7d %.5f" % (i, distrib[i], 100.0 * distrib[i] / count)
    if distrib[i] < low:
        low = distrib[i]
    if distrib[i] > high:
        high = distrib[i]
diff = high - low
print "Variation = %d (%.5f%%)" % (diff, 100.0 * diff / count)

2
Err, मुझे लगता है कि rephrase। यह देखते हुए कि अनुक्रम में किसी बिंदु पर एक विशेष एक्स का उत्पादन किया गया था, अनुक्रम में अगले नंबर के लिए केवल 7 में से 5 नंबर का उत्पादन किया जा सकता है। एक सच्चे आरएनजी में सभी नमूने एक दूसरे से स्वतंत्र होंगे, लेकिन इस मामले में वे स्पष्ट रूप से नहीं हैं।
एडम रोसेनफील्ड

3
यह सच है कि मूल प्रश्न निर्दिष्ट नहीं करता है कि इनपुट और आउटपुट फ़ंक्शंस स्वतंत्र और पहचान-वितरित (आईआईडी) नमूने का उत्पादन करते हैं, लेकिन मुझे लगता है कि यह एक उचित उम्मीद है कि यदि इनपुट रैंड 5 () आईआईडी है, तो आउटपुट रैंड 7 () iid भी होना चाहिए। यदि आपको नहीं लगता कि यह उचित है, तो अपने गैर-आईआईडी आरएनजी का उपयोग करके मज़े करें।
एडम रोसेनफील्ड 19

1
तो, विश्वविद्यालय में गणितज्ञों से क्या शब्द है?
एडम रोसेनफील्ड

1
यह समाधान स्पष्ट रूप से टूट गया है। यह स्पष्ट है कि आपको rand7 पर कॉल करने के लिए एक से अधिक बार rand5 (औसतन) कॉल करने की आवश्यकता है और यह समाधान नहीं करता है। इसलिए परिणाम यादृच्छिक के किसी भी समझदार परिभाषा से यादृच्छिक नहीं हो सकते।
क्रिस सॉटर

1
@Pax आपके फ़ंक्शन के प्रत्येक पुनरावृत्ति पर, यह केवल पांच अलग-अलग मानों में से एक को वापस कर सकता है (श्रेणी 0-6 में यद्यपि)। बहुत पहले पुनरावृत्ति केवल 0-4 की संख्या में वापस आ सकती है। तो, यह स्पष्ट होना चाहिए कि जब तक आपके फ़ंक्शन का एक समान वितरण हो सकता है, तब नमूने स्वतंत्र नहीं होते हैं अर्थात वे सहसंबद्ध होते हैं जो कि आप एक यादृच्छिक संख्या जनरेटर में कुछ नहीं चाहते हैं।
क्रिस सॉटर

3

यह जवाब Rand5 फ़ंक्शन से सबसे अधिक एंट्रोपी संभव प्राप्त करने में एक प्रयोग है। टी इसलिए कुछ अस्पष्ट है और लगभग निश्चित रूप से अन्य कार्यान्वयन की तुलना में बहुत धीमी है।

0-4 से समान वितरण और जिसके परिणामस्वरूप 0-6 से समान वितरण मानते हैं:

public class SevenFromFive
{
  public SevenFromFive()
  {
    // this outputs a uniform ditribution but for some reason including it 
    // screws up the output distribution
    // open question Why?
    this.fifth = new ProbabilityCondensor(5, b => {});
    this.eigth = new ProbabilityCondensor(8, AddEntropy);
  } 

  private static Random r = new Random();
  private static uint Rand5()
  {
    return (uint)r.Next(0,5);
  }

  private class ProbabilityCondensor
  {
    private readonly int samples;
    private int counter;
    private int store;
    private readonly Action<bool> output;

    public ProbabilityCondensor(int chanceOfTrueReciprocal,
      Action<bool> output)
    {
      this.output = output;
      this.samples = chanceOfTrueReciprocal - 1;  
    }

    public void Add(bool bit)
    {
      this.counter++;
      if (bit)
        this.store++;   
      if (counter == samples)
      {
        bool? e;
        if (store == 0)
          e = false;
        else if (store == 1)
          e = true;
        else
          e = null;// discard for now       
        counter = 0;
        store = 0;
        if (e.HasValue)
          output(e.Value);
      }
    }
  }

  ulong buffer = 0;
  const ulong Mask = 7UL;
  int bitsAvail = 0;
  private readonly ProbabilityCondensor fifth;
  private readonly ProbabilityCondensor eigth;

  private void AddEntropy(bool bit)
  {
    buffer <<= 1;
    if (bit)
      buffer |= 1;      
    bitsAvail++;
  }

  private void AddTwoBitsEntropy(uint u)
  {
    buffer <<= 2;
    buffer |= (u & 3UL);    
    bitsAvail += 2;
  }

  public uint Rand7()
  {
    uint selection;   
    do
    {
      while (bitsAvail < 3)
      {
        var x = Rand5();
        if (x < 4)
        {
          // put the two low order bits straight in
          AddTwoBitsEntropy(x);
          fifth.Add(false);
        }
        else
        { 
          fifth.Add(true);
        }
      }
      // read 3 bits
      selection = (uint)((buffer & Mask));
      bitsAvail -= 3;     
      buffer >>= 3;
      if (selection == 7)
        eigth.Add(true);
      else
        eigth.Add(false);
    }
    while (selection == 7);   
    return selection;
  }
}

Rand5 पर प्रति कॉल में जोड़े गए बिट्स की संख्या वर्तमान में 4/5 * 2 है इसलिए 1.6। यदि 1/5 प्रायिकता मान शामिल है जो 0.05 से बढ़ता है तो 1.65 है, लेकिन उस कोड में टिप्पणी देखें जहां मुझे इसे अक्षम करना पड़ा है।

Rand7 = 3 + 1/8 * (3 + 1/8 * (3 + 1/8 *) (...
यह 3 + 3/8 + 3/64 + 3/512 है ... के लिए कॉल द्वारा खपत बिट्स लगभग 3.42

सेवियों से जानकारी निकालकर मैं 0.018 के बारे में 1/8 * 1/7 बिट प्रति कॉल पुनः प्राप्त करता हूं

यह प्रति कॉल शुद्ध खपत 3.4 बिट्स देता है जिसका अर्थ है कि प्रत्येक Rand7 के लिए Rand5 के लिए अनुपात 2.125 कॉल है। इष्टतम 2.1 होना चाहिए।

मुझे लगता है कि जब तक Rand5 पर कॉल की लागत बेहद महंगी नहीं होगी (जब एंट्रॉपी के किसी बाहरी स्रोत को कॉल करते हैं) तो यह दृष्टिकोण अन्य लोगों की तुलना में काफी धीमा है।


कुछ सरल त्रुटियों से हटकर आपका समाधान सही प्रतीत होता है: "if (count> 1)" होना चाहिए "if (count <= 1)", और "i ++" जो शीघ्र ही घटित होता है उसके बाद घुंघराले ब्रेस के अंदर होना चाहिए जो इसे पूर्ववर्ती करता है। मुझे यकीन नहीं है कि बिटसैट () सही है या नहीं, लेकिन यह कुछ हद तक अप्रासंगिक है।
एडम रोसेनफील्ड

कुल मिलाकर, हालांकि, आपका कार्य समझना बहुत मुश्किल है। यह अधिक जटिलता की कीमत पर, अन्यथा की तुलना में एंट्रोपी का थोड़ा बेहतर उपयोग करता है। पहली कॉल पर 35 यादृच्छिक बिट्स के साथ बफर को भरने का कोई कारण नहीं है, जब 3 पर्याप्त होगा।
एडम रोसेनफील्ड

मैंने <= धन्यवाद सही किया, i ++ वास्तव में हालांकि होना चाहिए। यह शून्य और 1 मामले पर होना चाहिए (बफर में क्रमशः 1 या शून्य जोड़ते हुए)। यह बिल्कुल ऐसा नहीं है जो मैं उपयोग करने का सुझाव दूंगा, यह बहुत जटिल है। मुझे बस दिलचस्पी थी कि मैं समस्या में निहित सैद्धांतिक एन्ट्रापी सीमाओं के कितने करीब पहुंच सकता हूं ... प्रतिक्रिया के लिए धन्यवाद। विडंबना यह है कि पहली कॉल पर बफ़र को भरना सरल लिखना आसान था :)
ShuggyCoUk

मैंने इसे आसानी से समझने की कोशिश की (गति की लागत पर) लेकिन इसे भी सही कर दिया। यह अभी तक इष्टतम नहीं है, किसी कारण से 1/5 बिट्स मुद्दों का कारण बनते हैं, भले ही वे गणना में समान हों।
शुग्गीकोउक

3

, php में

function rand1to7() {
    do {
        $output_value = 0;
        for ($i = 0; $i < 28; $i++) {
            $output_value += rand1to5();
        }
    while ($output_value != 140);
    $output_value -= 12;
    return floor($output_value / 16);
}

लूप्स 16 और 127 के बीच एक यादृच्छिक संख्या का उत्पादन करने के लिए, 1 और 7.9375 के बीच एक फ्लोट बनाने के लिए सोलह से विभाजित करता है, फिर 1 और 7. के बीच एक अंतर प्राप्त करने के लिए नीचे राउंड करता है यदि मैं गलत नहीं हूं, तो 16/112 प्राप्त होने की संभावना है 7 परिणामों में से कोई एक।


हालांकि बिना सशर्त लूप का उपयोग करने के लिए संभवत: इसी तरह का एक आसान उत्तर है, और फर्श के बजाय मोडुलो। मैं अभी संख्या की कमी नहीं कर सकता।
dqhendricks 15


3

मुझे लगता है कि मेरे पास चार उत्तर हैं, दो सटीक समाधान दे रहे हैं जैसे @ अदम रोसेनफील्ड लेकिन अनंत लूप समस्या के बिना, और अन्य दो लगभग पूर्ण समाधान के साथ लेकिन पहले एक की तुलना में तेजी से कार्यान्वयन।

सर्वोत्तम सटीक समाधान के लिए 7 कॉल की आवश्यकता होती है rand5, लेकिन समझने के लिए आगे बढ़ने देता है।

विधि 1 - सटीक

एडम के जवाब की ताकत यह है कि यह एक समान वितरण प्रदान करता है, और बहुत अधिक संभावना (21/25) है कि रैंड 5 () को केवल दो कॉल की आवश्यकता होगी। हालांकि, सबसे खराब स्थिति अनंत लूप है।

नीचे दिया गया पहला समाधान भी एक समान वर्दी वितरण देता है, लेकिन इसके लिए कुल 42 कॉल की आवश्यकता होती है rand5। कोई अनंत छोर नहीं।

यहाँ एक आर कार्यान्वयन है:

rand5 <- function() sample(1:5,1)

rand7 <- function()  (sum(sapply(0:6, function(i) i + rand5() + rand5()*2 + rand5()*3 + rand5()*4 + rand5()*5 + rand5()*6)) %% 7) + 1

R से परिचित नहीं लोगों के लिए, यहाँ एक सरलीकृत संस्करण है:

rand7 = function(){
  r = 0 
  for(i in 0:6){
    r = r + i + rand5() + rand5()*2 + rand5()*3 + rand5()*4 + rand5()*5 + rand5()*6
  }
  return r %% 7 + 1
}

के वितरण को rand5संरक्षित किया जाएगा। यदि हम गणित करते हैं, तो लूप के 7 पुनरावृत्तियों में से प्रत्येक में 5 ^ 6 संभावित संयोजन होते हैं, इस प्रकार कुल संयोजनों की संख्या होती है (7 * 5^6) %% 7 = 0। इस प्रकार हम 7 के बराबर समूहों में उत्पन्न यादृच्छिक संख्याओं को विभाजित कर सकते हैं। इस पर अधिक चर्चा के लिए विधि दो देखें।

यहां सभी संभावित संयोजन दिए गए हैं:

table(apply(expand.grid(c(outer(1:5,0:6,"+")),(1:5)*2,(1:5)*3,(1:5)*4,(1:5)*5,(1:5)*6),1,sum) %% 7 + 1)

    1     2     3     4     5     6     7 
15625 15625 15625 15625 15625 15625 15625 

मुझे लगता है कि आदम की विधि बहुत तेजी से चलेगी यह दिखाने के लिए सीधे आगे है। rand5एडम के समाधान में 42 या अधिक कॉल होने की संभावना बहुत कम है ( (4/25)^21 ~ 10^(-17))।

विधि 2 - सटीक नहीं

अब दूसरी विधि, जो लगभग समान है, लेकिन इसके लिए 6 कॉल की आवश्यकता होती है rand5:

rand7 <- function() (sum(sapply(1:6,function(i) i*rand5())) %% 7) + 1

यहाँ एक सरलीकृत संस्करण है:

rand7 = function(){
  r = 0 
  for(i in 1:6){
    r = r + i*rand5()
  }
  return r %% 7 + 1
}

यह अनिवार्य रूप से विधि 1 का एक पुनरावृत्ति है। यदि हम सभी संभावित संयोजनों को उत्पन्न करते हैं, तो यहां परिणाम हैं:

table(apply(expand.grid(1:5,(1:5)*2,(1:5)*3,(1:5)*4,(1:5)*5,(1:5)*6),1,sum) %% 7 + 1)

   1    2    3    4    5    6    7 
2233 2232 2232 2232 2232 2232 2232

5^6 = 15625परीक्षणों में एक बार और एक संख्या दिखाई देगी ।

अब, विधि 1 में, 1 से 6 जोड़कर, हम क्रमिक संख्या 2233 को क्रमिक बिंदु पर ले जाते हैं। इस प्रकार कुल संयोजनों की संख्या मेल खाएगी। यह काम करता है क्योंकि 5 ^ 6 %% 7 = 1, और फिर हम 7 उचित भिन्नताएं करते हैं, इसलिए (7 * 5 ^ 6 %% 7 = 1)।

विधि 3 - सटीक

यदि विधि 1 और 2 के तर्क को समझा जाता है, तो विधि 3 का अनुसरण होता है, और इसके लिए केवल 7 कॉल की आवश्यकता होती है rand5। इस बिंदु पर, मुझे लगता है कि यह सटीक समाधान के लिए आवश्यक कॉल की न्यूनतम संख्या है।

यहाँ एक आर कार्यान्वयन है:

rand5 <- function() sample(1:5,1)

rand7 <- function()  (sum(sapply(1:7, function(i) i * rand5())) %% 7) + 1

R से परिचित नहीं लोगों के लिए, यहाँ एक सरलीकृत संस्करण है:

rand7 = function(){
  r = 0 
  for(i in 1:7){
    r = r + i * rand5()
  }
  return r %% 7 + 1
}

के वितरण को rand5संरक्षित किया जाएगा। यदि हम गणित करते हैं, तो लूप के 7 पुनरावृत्तियों में से प्रत्येक में 5 संभावित परिणाम हैं, इस प्रकार कुल संयोजनों की संख्या है (7 * 5) %% 7 = 0। इस प्रकार हम 7 के बराबर समूहों में उत्पन्न यादृच्छिक संख्याओं को विभाजित कर सकते हैं। इस पर अधिक चर्चा के लिए विधि एक और दो देखें।

यहां सभी संभावित संयोजन दिए गए हैं:

table(apply(expand.grid(0:6,(1:5)),1,sum) %% 7 + 1)

1 2 3 4 5 6 7  
5 5 5 5 5 5 5 

मुझे लगता है कि यह दिखाना आगे सीधे है कि एडम की विधि अभी भी तेजी से चलेगी। rand5एडम के समाधान में 7 या अधिक कॉल होने की संभावना अभी भी छोटी है ( (4/25)^3 ~ 0.004)।

विधि 4 - सटीक नहीं

यह दूसरी विधि का मामूली बदलाव है। यह लगभग समान है, लेकिन इसके लिए 7 कॉल की आवश्यकता होती है rand5, जो कि विधि 2 के लिए एक अतिरिक्त है:

rand7 <- function() (rand5() + sum(sapply(1:6,function(i) i*rand5())) %% 7) + 1

यहाँ एक सरलीकृत संस्करण है:

rand7 = function(){
  r = 0 
  for(i in 1:6){
    r = r + i*rand5()
  }
  return (r+rand5()) %% 7 + 1
}

यदि हम सभी संभावित संयोजनों को उत्पन्न करते हैं, तो परिणामी मायने रखता है:

table(apply(expand.grid(1:5,(1:5)*2,(1:5)*3,(1:5)*4,(1:5)*5,(1:5)*6,1:5),1,sum) %% 7 + 1)

    1     2     3     4     5     6     7 
11160 11161 11161 11161 11161 11161 11160

5^7 = 78125ट्रायल में एक बार दो नंबर कम दिखाई देंगे । अधिकांश उद्देश्यों के लिए, मैं उसी के साथ रह सकता हूं।


1
मैं R से परिचित नहीं हूं, लेकिन जब तक मुझे गलतफहमी नहीं है कि ये कैसे काम करते हैं, तो विधि 1 सटीक नहीं है। इसमें (5 ^ 6) ^ 7 = 5 ^ 42 संभावित परिणाम हैं, नहीं (5 ^ 6) * 7; 5 ^ 42 से विभाज्य नहीं है। 7. इसी तरह विधि 3 सटीक नहीं है। इसमें 5 ^ 7 संभावित परिणाम हैं, न कि 5 * 7। (विधि 3 के साथ अंतिम लूप पुनरावृत्ति का i=7भी कोई प्रभाव नहीं है, क्योंकि जोड़ने 7*rand5()से मॉड 7 rका मूल्य नहीं बदलता है r।)
एडम रोसेनफील्ड

2

जिस फ़ंक्शन की आपको आवश्यकता है वह rand1_7 () है , मैंने rand1_5 () लिखा है ताकि आप इसे परीक्षण कर सकें और इसे प्लॉट कर सकें।

import numpy
def rand1_5():
    return numpy.random.randint(5)+1

def rand1_7():
    q = 0
    for i in xrange(7):  q+= rand1_5()
    return q%7 + 1
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.