इसलिए मैंने रैंड नामक एक बात देखी () हार्मफुल माना जाता है और यह सरल std::rand()
प्लस मापांक प्रतिमान पर यादृच्छिक संख्या पीढ़ी के इंजन-वितरण प्रतिमान का उपयोग करने की वकालत करता है ।
हालाँकि, मैं std::rand()
पहली बार असफलताओं को देखना चाहता था इसलिए मैंने एक त्वरित प्रयोग किया:
- असल में, मैं 2 कार्यों लिखा था
getRandNum_Old()
औरgetRandNum_New()
उस का उपयोग कर के बीच 0 और 5 समावेशी एक यादृच्छिक संख्या उत्पन्नstd::rand()
औरstd::mt19937
+std::uniform_int_distribution
क्रमशः। - फिर मैंने "पुराने" तरीके का उपयोग करके 960,000 (6 से विभाज्य) यादृच्छिक संख्याओं को उत्पन्न किया और संख्याओं की आवृत्तियों को 0-5 दर्ज किया। फिर मैंने इन आवृत्तियों के मानक विचलन की गणना की। मैं जिस चीज की तलाश कर रहा हूं, वह मानक विचलन जितना संभव हो उतना कम है क्योंकि वितरण सही मायने में समान होने पर क्या होगा।
- मैंने उस सिमुलेशन को 1000 बार चलाया और प्रत्येक सिमुलेशन के लिए मानक विचलन दर्ज किया। मिलीसेकंड में लगने वाले समय को भी मैंने रिकॉर्ड किया।
- बाद में, मैंने फिर से वही किया लेकिन इस बार रैंडम नंबर्स को "नया" तरीका बनाया।
- अंत में, मैंने पुराने और नए तरीके दोनों के लिए मानक विचलन की सूची के माध्य और मानक विचलन की गणना की और पुराने और नए दोनों तरीके से लिए गए समय की सूची के लिए औसत और मानक विचलन।
यहाँ परिणाम थे:
[OLD WAY]
Spread
mean: 346.554406
std dev: 110.318361
Time Taken (ms)
mean: 6.662910
std dev: 0.366301
[NEW WAY]
Spread
mean: 350.346792
std dev: 110.449190
Time Taken (ms)
mean: 28.053907
std dev: 0.654964
हैरानी की बात है कि दोनों तरीकों के लिए रोल का कुल प्रसार समान था। Ie, std::mt19937
+ std::uniform_int_distribution
साधारण std::rand()
+ से "अधिक समान" नहीं था %
। मैंने जो एक और अवलोकन किया, वह यह था कि नया पुराने तरीके से लगभग 4 गुना धीमा था। कुल मिलाकर, ऐसा लग रहा था कि मैं गुणवत्ता में लगभग कोई लाभ नहीं होने के लिए गति में भारी लागत चुका रहा हूं।
क्या मेरा प्रयोग किसी तरह से दोषपूर्ण है? या std::rand()
वास्तव में वह बुरा नहीं है, और शायद बेहतर भी?
संदर्भ के लिए, यहाँ मैं अपनी संपूर्णता में प्रयुक्त कोड है:
#include <cstdio>
#include <random>
#include <algorithm>
#include <chrono>
int getRandNum_Old() {
static bool init = false;
if (!init) {
std::srand(time(nullptr)); // Seed std::rand
init = true;
}
return std::rand() % 6;
}
int getRandNum_New() {
static bool init = false;
static std::random_device rd;
static std::mt19937 eng;
static std::uniform_int_distribution<int> dist(0,5);
if (!init) {
eng.seed(rd()); // Seed random engine
init = true;
}
return dist(eng);
}
template <typename T>
double mean(T* data, int n) {
double m = 0;
std::for_each(data, data+n, [&](T x){ m += x; });
m /= n;
return m;
}
template <typename T>
double stdDev(T* data, int n) {
double m = mean(data, n);
double sd = 0.0;
std::for_each(data, data+n, [&](T x){ sd += ((x-m) * (x-m)); });
sd /= n;
sd = sqrt(sd);
return sd;
}
int main() {
const int N = 960000; // Number of trials
const int M = 1000; // Number of simulations
const int D = 6; // Num sides on die
/* Do the things the "old" way (blech) */
int freqList_Old[D];
double stdDevList_Old[M];
double timeTakenList_Old[M];
for (int j = 0; j < M; j++) {
auto start = std::chrono::high_resolution_clock::now();
std::fill_n(freqList_Old, D, 0);
for (int i = 0; i < N; i++) {
int roll = getRandNum_Old();
freqList_Old[roll] += 1;
}
stdDevList_Old[j] = stdDev(freqList_Old, D);
auto end = std::chrono::high_resolution_clock::now();
auto dur = std::chrono::duration_cast<std::chrono::microseconds>(end-start);
double timeTaken = dur.count() / 1000.0;
timeTakenList_Old[j] = timeTaken;
}
/* Do the things the cool new way! */
int freqList_New[D];
double stdDevList_New[M];
double timeTakenList_New[M];
for (int j = 0; j < M; j++) {
auto start = std::chrono::high_resolution_clock::now();
std::fill_n(freqList_New, D, 0);
for (int i = 0; i < N; i++) {
int roll = getRandNum_New();
freqList_New[roll] += 1;
}
stdDevList_New[j] = stdDev(freqList_New, D);
auto end = std::chrono::high_resolution_clock::now();
auto dur = std::chrono::duration_cast<std::chrono::microseconds>(end-start);
double timeTaken = dur.count() / 1000.0;
timeTakenList_New[j] = timeTaken;
}
/* Display Results */
printf("[OLD WAY]\n");
printf("Spread\n");
printf(" mean: %.6f\n", mean(stdDevList_Old, M));
printf(" std dev: %.6f\n", stdDev(stdDevList_Old, M));
printf("Time Taken (ms)\n");
printf(" mean: %.6f\n", mean(timeTakenList_Old, M));
printf(" std dev: %.6f\n", stdDev(timeTakenList_Old, M));
printf("\n");
printf("[NEW WAY]\n");
printf("Spread\n");
printf(" mean: %.6f\n", mean(stdDevList_New, M));
printf(" std dev: %.6f\n", stdDev(stdDevList_New, M));
printf("Time Taken (ms)\n");
printf(" mean: %.6f\n", mean(timeTakenList_New, M));
printf(" std dev: %.6f\n", stdDev(timeTakenList_New, M));
}