<random> लिनक्स में समान संख्या उत्पन्न करता है, लेकिन विंडोज में नहीं


90

नीचे दिए गए कोड का मतलब अंतराल में पाँच छद्म यादृच्छिक संख्याओं की सूची तैयार करना है [1,100]। मैं बीज default_random_engineके साथ time(0), जिसमें सिस्टम का समय देता है, यूनिक्स समय । जब मैं Microsoft Visual Studio 2013 का उपयोग करके विंडोज 7 पर इस कार्यक्रम को संकलित और चलाता हूं, तो यह अपेक्षित (नीचे देखें) के रूप में काम करता है। जब मैं जी ++ कंपाइलर के साथ आर्क लिनक्स में ऐसा करता हूं, हालांकि, यह अजीब व्यवहार करता है।

लिनक्स में, हर बार 5 नंबर उत्पन्न होंगे। प्रत्येक निष्पादन पर अंतिम 4 संख्याएं भिन्न होंगी (जैसा कि अक्सर होता है), लेकिन पहली संख्या वही रहेगी।

विंडोज और लिनक्स पर 5 निष्पादन से उदाहरण आउटपुट:

      | Windows:       | Linux:        
---------------------------------------
Run 1 | 54,01,91,73,68 | 25,38,40,42,21
Run 2 | 46,24,16,93,82 | 25,78,66,80,81
Run 3 | 86,36,33,63,05 | 25,17,93,17,40
Run 4 | 75,79,66,23,84 | 25,70,95,01,54
Run 5 | 64,36,32,44,85 | 25,09,22,38,13

इस रहस्य को जोड़ते हुए, कि लिनक्स पर एक-एक करके पहली बार समय-समय पर वेतन वृद्धि। उपरोक्त आउटपुट प्राप्त करने के बाद, मैंने लगभग 30 मिनट इंतजार किया और यह पता लगाने की फिर से कोशिश की कि 1 नंबर बदल गया था और अब हमेशा 26 के रूप में उत्पन्न हो रहा था। यह समय-समय पर 1 की वृद्धि करना जारी रखा है और अब 32 पर है। के बदलते मूल्य के साथ time(0)

पहला नंबर शायद ही कभी पूरे रन में बदलता है, और फिर जब ऐसा होता है, तो 1 से बढ़ जाता है?

कोड। यह बड़े करीने से 5 नंबर और सिस्टम टाइम प्रिंट करता है:

#include <iostream>
#include <random>
#include <time.h>

using namespace std;

int main()
{
    const int upper_bound = 100;
    const int lower_bound = 1;

    time_t system_time = time(0);    

    default_random_engine e(system_time);
    uniform_int_distribution<int> u(lower_bound, upper_bound);

    cout << '#' << '\t' << "system time" << endl
         << "-------------------" << endl;

    for (int counter = 1; counter <= 5; counter++)
    {
        int secret = u(e);
        cout << secret << '\t' << system_time << endl;
    }   

    system("pause");
    return 0;
}

3
sizeof(time_t)बनाम क्या है sizeof(default_random_engine::result_type)?
मार्क रंसोम

3
ध्यान दें कि default_random_engineउन दो प्लेटफार्मों पर पूरी तरह से अलग है।
तृकां

1
यह अभी भी यादृच्छिक BTW हो सकता है।
एलेक टील

5
क्या हर प्रोग्रामर एक ऐसे दौर से गुज़रता है जहाँ उन्हें लगता है कि समय एक अच्छा यादृच्छिक संख्या जनरेटर बीज है?
ओल्डफ़ार्ट

6
@ ओल्डफ़ार्ट हाँ, इसे एकेडेमिया कहा जाता है।
केसी

जवाबों:


141

यहाँ क्या हो रहा है:

  • default_random_enginein libstdc ++ (GCC का मानक पुस्तकालय) minstd_rand0, जो कि एक सरल रैखिक बधाई इंजन है:

    typedef linear_congruential_engine<uint_fast32_t, 16807, 0, 2147483647> minstd_rand0;
  • जिस तरह से यह इंजन यादृच्छिक संख्या उत्पन्न करता है वह x i + 1 = (16807x i + 0) mod 2147483647 है।

  • इसलिए, यदि बीज 1 से भिन्न होते हैं, तो अधिकांश समय पहली उत्पन्न संख्या 16807 से भिन्न होगी।

  • इस जनरेटर की रेंज [1, 2147483646] है। जिस तरह से libstdc ++ uniform_int_distributionकी श्रेणी में यह पूर्णांक के लिए मैप करता है [1, 100] अनिवार्य रूप से यह है: एक संख्या उत्पन्न करना n। यदि संख्या 2147483600 से अधिक नहीं है, तो वापस लौटें (n - 1) / 21474836 + 1; अन्यथा, एक नए नंबर के साथ फिर से प्रयास करें।

    यह देखना आसान होना चाहिए कि अधिकांश मामलों में, nकेवल 16807 से भिन्न होने वाले दो एस इस प्रक्रिया के तहत [1, 100] में समान संख्या प्राप्त करेंगे। वास्तव में, प्रत्येक 21474836/16807 = 1278 सेकंड या 21.3 मिनट के बारे में एक के बाद एक उत्पन्न संख्या बढ़ने की उम्मीद होगी, जो आपकी टिप्पणियों से बहुत अच्छी तरह सहमत है।

MSVC's default_random_engineहै mt19937, जिसमें यह समस्या नहीं है।


36
मुझे आश्चर्य है कि ऐसे भयानक डिफ़ॉल्ट को चुनने के लिए जीसीसी के मानक पुस्तकालय के डेवलपर्स के पास क्या था।
कोडइन्चौस

13
@CodesInChaos मुझे नहीं पता कि यह संबंधित नहीं है, लेकिन MacOS / iOS टूलचैन भी उसी भयानक यादृच्छिक इंजन का उपयोग करते हैं, जिससे rand()% 7 हमेशा 0
लौटता है

7
@ LưuV LnhPhúc फिक्सिंग rand()कुछ हद तक समझ में आता है (यह निराशाजनक विरासत बकवास है)। कुछ नया करने के लिए एक shit-tier PRNG का उपयोग करना अक्षम्य है। मैं भी इसे मानक उल्लंघन मानता हूँ, क्योंकि मानक के लिए "कम से कम स्वीकार्य इंजन व्यवहार के लिए अपेक्षाकृत आकस्मिक, अनुभवहीन और हल्के या हल्के उपयोग की आवश्यकता होती है।" यह कार्यान्वयन प्रदान नहीं करता है क्योंकि यह आपके rand % 7उदाहरण जैसे तुच्छ उपयोग मामलों के लिए भी भयावह रूप से विफल रहता है ।
कोडइन्चोस

2
@CodesInChaos rand()कुछ ठीक-ठीक समझने योग्य क्यों नहीं है? क्या केवल इसलिए कि किसी ने ऐसा करने के लिए नहीं सोचा होगा?
user253751

2
@immibis एपीआई इतना टूट गया है कि आप एक स्वतंत्र प्रतिस्थापन के साथ बेहतर हैं जो सभी मुद्दों को ठीक करता है। 1) एल्गोरिथ्म को बदलना एक ब्रेकिंग परिवर्तन होगा, इसलिए आपको पुराने कार्यक्रमों के लिए अनुकूलता स्विच की आवश्यकता होगी। 2) srandअद्वितीय बीज आसानी से उत्पन्न करने के लिए बहुत छोटा है। 3) यह एक पूर्णांक परिभाषित कार्यान्वयन के साथ एक पूर्णांक लौटाता है, जिसे कॉलर को किसी तरह वांछित सीमा में एक संख्या तक कम करना पड़ता है, जो ठीक से किए जाने पर rand()4 के लिए एक सायन एपीआई के साथ प्रतिस्थापन लिखने की तुलना में अधिक काम होता है ) यह वैश्विक परिवर्तनशील स्थिति का उपयोग करता है
कोडइन्चोस

30

std::default_random_engineकार्यान्वयन परिभाषित किया गया है। उपयोग std::mt19937या std::mt19937_64इसके बजाय।

इसके अलावा std::timeऔर ctimeफ़ंक्शन बहुत सटीक नहीं हैं, <chrono>इसके बजाय हेडर में परिभाषित प्रकारों का उपयोग करें :

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

int main()
{
    const int upper_bound = 100;
    const int lower_bound = 1;

    auto t = std::chrono::high_resolution_clock::now().time_since_epoch().count();

    std::mt19937 e;
    e.seed(static_cast<unsigned int>(t)); //Seed engine with timed value.
    std::uniform_int_distribution<int> u(lower_bound, upper_bound);

    std::cout << '#' << '\t' << "system time" << std::endl
    << "-------------------" << std::endl;

    for (int counter = 1; counter <= 5; counter++)
    {
        int secret = u(e);

        std::cout << secret << '\t' << t << std::endl;
    }   

    system("pause");
    return 0;
}

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

15
मैं std::random_deviceआपके यादृच्छिक जनरेटर को बोने के लिए वर्तमान_ समय के बजाय उपयोग करने का सुझाव दूंगा। रैंडम के बारे में किसी भी उदाहरण को देखें।
अलेक्जेंडर फुलर

5
यदि आप नहीं चाहते हैं कि कोई आपके बीज का अनुमान लगाए (और इसलिए आपके अनुक्रम को पुन: उत्पन्न करें) कम सटीकता अधिक यादृच्छिकता के समान नहीं है। आइए चरम पर जाएं: अपने बीज को अगले दिन (या वर्ष?) -> अनुमान लगाना आसान है। फेमटोसेकंड परिशुद्धता का उपयोग करें -> करने के लिए अनुमान लगाने के बहुत सारे ...
linac

2
@ केमिकलगाइनर ctime1 सेकंड का है। std::chronoकार्यान्वयन की ग्रैन्युलैरिटी उपयोगकर्ता-परिभाषित है, डिफ़ॉल्ट करने के लिए std::high_resolution_clock(विज़ुअल स्टूडियो में इसके लिए एक टाइपेडिफ है std::steady_clock), नैनोसेकंड लेकिन बहुत छोटा माप चुन सकता है, इसलिए, बहुत अधिक सटीक।
केसी

2
@linac यदि आप क्रिप्टोग्राफिक गुण चाहते थे तो आप उपयुक्त प्रिंग (इस उत्तर में उपयोग नहीं किया गया) का उपयोग करेंगे। और निश्चित रूप से समय-आधारित बीज भी सवाल से बाहर है, कोई फर्क नहीं पड़ता वादा किया सटीकता।
Cululhu

-2

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

विंडोज यादृच्छिक संख्या बीज माउस, कीबोर्ड, नेटवर्क और दिन के समय के संग्रह से प्राप्त होता है। यह दोहराने योग्य नहीं है। लेकिन यह नमक मूल्य एक ज्ञात बीज पर रीसेट किया जा सकता है, जैसा कि ऊपर बताया गया है, एक प्रयोग के डिजाइन में शामिल है।

अरे हाँ, लिनक्स में दो यादृच्छिक संख्या जनरेटर हैं। एक, डिफ़ॉल्ट मॉडुलो 32 बिट्स है, और दूसरा मोडुलो 64 बिट्स है। आपकी पसंद आपके परीक्षण या वास्तविक उपयोग के लिए उपभोग की गई सटीकता की जरूरतों और गणना समय पर निर्भर करती है।


5
मुझे यकीन नहीं है कि आप बीज पीढ़ी एल्गोरिदम के बारे में क्यों बात कर रहे हैं। ओपी स्पष्ट रूप से बीज के रूप में सिस्टम समय का उपयोग करता है। इसके अलावा, आप कुछ संदर्भ जोड़ सकते हैंcollection of mouse, keyboard, network and time of day numbers
डिफ़ॉल्ट लोकेल
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.