C या C ++ में सामान्य वितरण के बाद मैं आसानी से यादृच्छिक संख्या कैसे उत्पन्न कर सकता हूं?
मुझे बूस्ट का कोई उपयोग नहीं चाहिए।
मुझे पता है कि नुथ लंबाई में इस बारे में बात करता है लेकिन मेरे पास अभी उसकी किताबें नहीं हैं।
C या C ++ में सामान्य वितरण के बाद मैं आसानी से यादृच्छिक संख्या कैसे उत्पन्न कर सकता हूं?
मुझे बूस्ट का कोई उपयोग नहीं चाहिए।
मुझे पता है कि नुथ लंबाई में इस बारे में बात करता है लेकिन मेरे पास अभी उसकी किताबें नहीं हैं।
जवाबों:
एक नियमित RNG से गाऊसी-वितरित संख्याओं को उत्पन्न करने के कई तरीके हैं ।
बॉक्स-मुलर को बदलने आमतौर पर इस्तेमाल किया जाता है। यह एक सामान्य वितरण के साथ मूल्यों को सही ढंग से पैदा करता है। गणित आसान है। आप दो (समान) यादृच्छिक संख्याएँ उत्पन्न करते हैं, और उनके लिए एक सूत्र लागू करने से, आपको दो सामान्य रूप से वितरित यादृच्छिक संख्याएँ मिलती हैं। एक लौटें, और दूसरे को यादृच्छिक संख्या के लिए अगले अनुरोध के लिए सहेजें।
std::normal_distribution
जो गणितीय विवरणों को समझने के बिना आपको क्या कहता है।
C ++ 11 ऑफ़र std::normal_distribution
, जो आज मैं जाना चाहूंगा।
आरोही जटिलता के क्रम में कुछ समाधान इस प्रकार हैं:
0 से 1 तक 12 समान यादृच्छिक संख्याएँ जोड़ें और घटाएं 6. यह सामान्य चर के माध्य और मानक विचलन से मेल खाएगा। एक स्पष्ट दोष यह है कि सीमा - 6 तक सीमित है - एक सच्चे सामान्य वितरण के विपरीत।
बॉक्स-मुलर बदल गया। यह ऊपर सूचीबद्ध है, और इसे लागू करने के लिए अपेक्षाकृत सरल है। यदि आपको बहुत सटीक नमूनों की आवश्यकता है, हालांकि, इस बात से अवगत रहें कि कुछ समान जनरेटर के साथ मिलकर बॉक्स-म्यूलर परिवर्तन एनवे इफेक्ट 1 नामक एक विसंगति से ग्रस्त है ।
सर्वोत्तम परिशुद्धता के लिए, मैं सामान्य रूप से वितरित चर पर पहुंचने के लिए वर्दी ड्राइंग और उलटा संचयी सामान्य वितरण लागू करने का सुझाव देता हूं। यहाँ उलटा संचयी सामान्य वितरण के लिए एक बहुत अच्छा एल्गोरिथ्म है।
1. एचआर नेवे, "मल्टीप्लिकेटिव कंफ्यूजिव स्यूडोरैंडम नंबर जनरेटर्स के साथ बॉक्स-मुलर ट्रांसफॉर्मेशन का उपयोग करने पर" एप्लाइड स्टैटिस्टिक्स, 22, 92-97, 1973
एक त्वरित और आसान तरीका सिर्फ समान रूप से वितरित यादृच्छिक संख्याओं का योग है और उनका औसत लेना है। यह काम क्यों करता है, इसकी पूरी व्याख्या के लिए केंद्रीय सीमा प्रमेय देखें ।
मैंने सामान्य रूप से वितरित यादृच्छिक संख्या बेंचमार्क के लिए C ++ ओपन सोर्स प्रोजेक्ट बनाया ।
यह सहित कई एल्गोरिदम की तुलना करता है
cpp11random
सी ++ 11 का उपयोग करता है std::normal_distribution
के साथ std::minstd_rand
(यह वास्तव में बॉक्स मुलर बजना में बदलना है)।float
IMac Corei5-3330S@2.70GHz, clang 6.1, 64-100 पर एकल-परिशुद्धता ( ) संस्करण के परिणाम :
शुद्धता के लिए, कार्यक्रम माध्य, मानक विचलन, तिरछापन और नमूनों के कर्टोसिस की पुष्टि करता है। यह पाया गया कि 4, 8 या 16 समरूप संख्याओं के साथ CLT विधि में अन्य विधियों की तरह अच्छी कर्टोसिस नहीं है।
Ziggurat एल्गोरिथ्म में दूसरों की तुलना में बेहतर प्रदर्शन है। हालाँकि, यह SIMD समानता के लिए उपयुक्त नहीं है क्योंकि इसमें टेबल लुकअप और शाखाओं की आवश्यकता होती है। SSE2 / AVX निर्देश सेट के साथ बॉक्स-मुलर ziggurat एल्गोरिथ्म के गैर-SIMD संस्करण की तुलना में बहुत तेज (X1.79, x2.99) है।
इसलिए, मैं SIMD अनुदेश सेट के साथ वास्तुकला के लिए बॉक्स-मुलर का उपयोग करने का सुझाव दूंगा, और अन्यथा ज़िगुरैट हो सकता है।
पीएस बेंचमार्क एक समान वितरित LCG PRNG का उपयोग करता है ताकि समान रूप से वितरित यादृच्छिक संख्या उत्पन्न हो सके। तो यह कुछ अनुप्रयोगों के लिए पर्याप्त नहीं हो सकता है। लेकिन प्रदर्शन की तुलना उचित होनी चाहिए क्योंकि सभी कार्यान्वयन समान PRNG का उपयोग करते हैं, इसलिए बेंचमार्क मुख्य रूप से परिवर्तन के प्रदर्शन का परीक्षण करता है।
यहाँ कुछ संदर्भों के आधार पर C ++ उदाहरण दिया गया है। यह त्वरित और गंदा है, आप बेहतर तरीके से आविष्कार नहीं कर रहे हैं और बढ़ावा पुस्तकालय का उपयोग कर रहे हैं।
#include "math.h" // for RAND, and rand
double sampleNormal() {
double u = ((double) rand() / (RAND_MAX)) * 2 - 1;
double v = ((double) rand() / (RAND_MAX)) * 2 - 1;
double r = u * u + v * v;
if (r == 0 || r > 1) return sampleNormal();
double c = sqrt(-2 * log(r) / r);
return u * c;
}
आप परिणामों की जांच करने के लिए एक क्यूक्यू प्लॉट का उपयोग कर सकते हैं और देख सकते हैं कि यह एक वास्तविक सामान्य वितरण का अनुमान लगाता है (रैंक आपके नमूने 1.x। x, रैंक को x की कुल संख्या के अनुपात में बदल दें। कितने नमूने, z- मान प्राप्त करें। और उन्हें प्लॉट करें। ऊपर की ओर सीधी रेखा वांछित परिणाम है)।
का उपयोग करें std::tr1::normal_distribution
।
Std :: tr1 नाम स्थान को बढ़ावा देने का हिस्सा नहीं है। यह नामस्थान है जिसमें C ++ तकनीकी रिपोर्ट 1 से पुस्तकालय के परिवर्धन शामिल हैं और यह Microsoft कंपाइलर्स और gcc के लिए उपलब्ध है, स्वतंत्र रूप से बढ़ावा देने के लिए।
यह है कि आप आधुनिक C ++ कंपाइलर पर नमूने कैसे बनाते हैं।
#include <random>
...
std::mt19937 generator;
double mean = 0.0;
double stddev = 1.0;
std::normal_distribution<double> normal(mean, stddev);
cerr << "Normal: " << normal(generator) << endl;
generator
वास्तव में वरीयता प्राप्त किया जाना चाहिए।
आप जीएसएल का उपयोग कर सकते हैं । इसका उपयोग कैसे करें, यह प्रदर्शित करने के लिए कुछ पूर्ण उदाहरण दिए गए हैं ।
इस पर एक नज़र: http://www.cplusplus.com/reference/random/normal_distribution/ । यह सामान्य वितरण का उत्पादन करने का सबसे सरल तरीका है।
यदि आप C ++ 11 का उपयोग कर रहे हैं, तो आप उपयोग कर सकते हैं std::normal_distribution
:
#include <random>
std::default_random_engine generator;
std::normal_distribution<double> distribution(/*mean=*/0.0, /*stddev=*/1.0);
double randomNumber = distribution(generator);
कई अन्य वितरण हैं जिनका उपयोग आप यादृच्छिक संख्या इंजन के आउटपुट को बदलने के लिए कर सकते हैं।
मैंने http://www.mathworks.com/help/stats/normal-distribution.html में दी गई पीडीएफ की परिभाषा का अनुसरण किया है और इसके लिए आया हूं :
const double DBL_EPS_COMP = 1 - DBL_EPSILON; // DBL_EPSILON is defined in <limits.h>.
inline double RandU() {
return DBL_EPSILON + ((double) rand()/RAND_MAX);
}
inline double RandN2(double mu, double sigma) {
return mu + (rand()%2 ? -1.0 : 1.0)*sigma*pow(-log(DBL_EPS_COMP*RandU()), 0.5);
}
inline double RandN() {
return RandN2(0, 1.0);
}
यह शायद सबसे अच्छा तरीका नहीं है, लेकिन यह काफी सरल है।
rand()
की RANDU
जब से Ln (0) अपरिभाषित है, रिटर्न एक शून्य।
cos(2*pi*rand/RAND_MAX)
, जबकि आप के साथ गुणा करते हैं (rand()%2 ? -1.0 : 1.0)
।
Comp.lang.c पूछे जाने वाले प्रश्न सूची शेयरों आसानी से करने के लिए तीन अलग अलग तरीकों एक गाऊसी वितरण के साथ यादृच्छिक संख्या उत्पन्न करते हैं।
आप इसे देख सकते हैं: http://c-faq.com/lib/gaussian.html
बॉक्स-मुलर कार्यान्वयन:
#include <cstdlib>
#include <cmath>
#include <ctime>
#include <iostream>
using namespace std;
// return a uniformly distributed random number
double RandomGenerator()
{
return ( (double)(rand()) + 1. )/( (double)(RAND_MAX) + 1. );
}
// return a normally distributed random number
double normalRandom()
{
double y1=RandomGenerator();
double y2=RandomGenerator();
return cos(2*3.14*y2)*sqrt(-2.*log(y1));
}
int main(){
double sigma = 82.;
double Mi = 40.;
for(int i=0;i<100;i++){
double x = normalRandom()*sigma+Mi;
cout << " x = " << x << endl;
}
return 0;
}
उलटा संचयी सामान्य वितरण के लिए विभिन्न एल्गोरिदम मौजूद हैं। मात्रात्मक वित्त में सबसे लोकप्रिय http://chasethedevil.github.io/post/monte-carlo--inverse-cumactory-normal-distribution/ पर परीक्षण किया जाता है
मेरी राय में, वहाँ से एल्गोरिथ्म AS241 की तुलना में और उपयोग कुछ ज्यादा प्रोत्साहन नहीं है Wichura : यह मशीन परिशुद्धता, विश्वसनीय और तेजी से होता है। बॉटलनेक्स शायद ही कभी गाऊसी यादृच्छिक संख्या पीढ़ी में हैं।
इसके अलावा, यह दृष्टिकोण की तरह Ziggurat की खामी को दर्शाता है।
यहाँ शीर्ष उत्तर Box-Müller की वकालत करता है, आपको पता होना चाहिए कि इसमें कमियाँ हैं। मैं https://www.sciencedirect.com/science/article/pii/S089571771710005935 :
साहित्य में, बॉक्स-मुलर को कभी-कभी थोड़ा हीन माना जाता है, मुख्यतः दो कारणों से। सबसे पहले, यदि कोई बॉक्स-मुलर विधि को एक खराब रैखिक बधाई जनरेटर से संख्याओं पर लागू करता है, तो रूपांतरित संख्याएं अंतरिक्ष की बेहद खराब कवरेज प्रदान करती हैं। स्पाइरलिंग टेल्स के साथ तब्दील संख्याओं के भूखंड कई किताबों में पाए जा सकते हैं, विशेष रूप से रिप्ले की क्लासिक पुस्तक में, जो संभवत: इस अवलोकन को बनाने वाले पहले थे "
1) रेखीय सहज तरीके से आप गाऊसी यादृच्छिक संख्या उत्पन्न कर सकते हैं मोंटे कार्लो विधि के समान कुछ का उपयोग करके। आप सी में अपने छद्म यादृच्छिक संख्या जनरेटर का उपयोग करके गाऊसी वक्र के चारों ओर एक बॉक्स में एक यादृच्छिक बिंदु उत्पन्न करेंगे। आप गणना कर सकते हैं कि वितरण के समीकरण का उपयोग करके उस बिंदु के अंदर या गाऊसी वितरण के नीचे है या नहीं। यदि वह बिंदु गाऊसी वितरण के अंदर है, तो आपको बिंदु के x मान के रूप में अपना गाऊसी यादृच्छिक संख्या मिल गया है।
यह विधि सही नहीं है क्योंकि तकनीकी रूप से गाऊसी वक्र अनंत की ओर जाता है, और आप एक ऐसा बॉक्स नहीं बना सकते जो अनंतता को x आयाम में ले जाए। लेकिन Guassian वक्र y आयाम में 0 बहुत तेजी से पहुंचता है, इसलिए मुझे इस बारे में चिंता नहीं होगी। C में आपके चर के आकार का अवरोध आपकी सटीकता तक सीमित कारक से अधिक हो सकता है।
2) केंद्रीय सीमा प्रमेय का उपयोग करने का एक और तरीका होगा जिसमें कहा गया है कि जब स्वतंत्र यादृच्छिक चर जोड़े जाते हैं, तो वे एक सामान्य वितरण बनाते हैं। इस प्रमेय को ध्यान में रखते हुए, आप बड़ी मात्रा में स्वतंत्र यादृच्छिक चर जोड़कर एक गाऊसी यादृच्छिक संख्या का अनुमान लगा सकते हैं।
ये विधियां सबसे अधिक व्यावहारिक नहीं हैं, लेकिन यह उम्मीद की जानी चाहिए कि जब आप एक preexisting पुस्तकालय का उपयोग नहीं करना चाहते हैं। ध्यान रखें कि यह उत्तर किसी के पास कम या बिना किसी गणना या सांख्यिकी अनुभव के आ रहा है।
मोंटे कार्लो विधि
ऐसा करने का सबसे सहज तरीका एक मोंटे कार्लो विधि का उपयोग करना होगा। एक उपयुक्त श्रेणी -X, + X लें। एक्स के बड़े मूल्यों के परिणामस्वरूप अधिक सटीक सामान्य वितरण होगा, लेकिन अभिसरण में अधिक समय लगता है। ए। X-b के बीच -X के बीच एक यादृच्छिक संख्या z चुनें । इस बात की प्रायिकता रखें N(z, mean, variance)
कि N कहां गौसियन वितरण है। अन्यथा छोड़ें और चरण (ए) पर वापस जाएं।
कंप्यूटर नियतात्मक उपकरण है। गणना में कोई यादृच्छिकता नहीं है। इसके अलावा सीपीयू में अंकगणित उपकरण पूर्णांक संख्याओं के कुछ परिमित सेट (परिमित क्षेत्र में मूल्यांकन करना) और वास्तविक परिमेय संख्याओं के परिमित समुच्चय का मूल्यांकन कर सकता है। और बिटवाइज ऑपरेशन भी किए। गणित अंक के अनंत संख्या के साथ [0.0, 1.0] जैसे अधिक महान सेटों के साथ एक सौदा करता है।
आप कुछ नियंत्रक के साथ कंप्यूटर के अंदर कुछ तार सुन सकते हैं, लेकिन क्या इसका समान वितरण होगा? मुझे नहीं पता। लेकिन अगर यह माना जाता है कि यह संकेत है, तो बड़ी संख्या में स्वतंत्र यादृच्छिक चर संचित मूल्यों का परिणाम है तो आपको लगभग सामान्य वितरित यादृच्छिक चर प्राप्त होगा (यह प्रायिकता सिद्धांत में साबित हुआ था)
वहाँ मौजूद एल्गोरिदम कहा जाता है - छद्म यादृच्छिक जनरेटर। जैसा कि मैंने महसूस किया कि छद्म यादृच्छिक जनरेटर का उद्देश्य यादृच्छिकता का अनुकरण करना है। और गुडनेस के मानदंड हैं: - अनुभवजन्य वितरण को कुछ अर्थों में (सैद्धांतिक, एकसमान, L2) में रूपांतरित किया जाता है - ऐसे मान जिन्हें आप यादृच्छिक जनरेटर से प्राप्त करते हैं, विचारधारा वाले लगते हैं। बेशक यह 'वास्तविक दृष्टिकोण' से सही नहीं है, लेकिन हम मानते हैं कि यह सच है।
लोकप्रिय विधि में से एक - आप समान वितरण के साथ 12 irv कर सकते हैं .... लेकिन फ़्यूरियर ट्रांसफॉर्मर, टेलर सीरीज़ की मदद से व्युत्पन्न सेंट्रल लिमिट प्रमेय के दौरान ईमानदार होने के लिए, यह आवश्यक है कि n -> + inf धारणाएँ दो बार हों। उदाहरण के लिए सैद्धांतिक रूप से - व्यक्तिगत रूप से मैं यह नहीं समझता कि लोग समान वितरण के साथ 12 irv का योग कैसे करते हैं।
मेरे पास विश्वविद्यालय में संभावना सिद्धांत था। और मेरे लिए पार्टिकलरी सिर्फ एक गणित का सवाल है। विश्वविद्यालय में मैंने निम्नलिखित मॉडल देखा:
double generateUniform(double a, double b)
{
return uniformGen.generateReal(a, b);
}
double generateRelei(double sigma)
{
return sigma * sqrt(-2 * log(1.0 - uniformGen.generateReal(0.0, 1.0 -kEps)));
}
double generateNorm(double m, double sigma)
{
double y2 = generateUniform(0.0, 2 * kPi);
double y1 = generateRelei(1.0);
double x1 = y1 * cos(y2);
return sigma*x1 + m;
}
इस तरह से यह सिर्फ एक उदाहरण था, मुझे लगता है कि इसे लागू करने के अन्य तरीके मौजूद हैं।
यह साबित होता है कि यह सही है, इस पुस्तक में पाया जा सकता है "मॉस्को, बीएमएसटीयू, 2004: XVI प्रोबेबिलिटी थ्योरी, उदाहरण 6.12, p.246-247" कृष्णचेंद अलेक्जेंडर पेट्रोविच आईएसबीएन 5-7038-2485-0
दुर्भाग्य से मुझे इस पुस्तक के अंग्रेजी में अनुवाद के अस्तित्व के बारे में पता नहीं है।