2016-11-08 80 views
1

我已经被告知rand()mod n产生有偏见的结果,所以我试着让这段代码去检查它。它会生成从1到ls数字,并按照出现次数排序。我在做这些随机数字有什么问题?

#include <iostream> 
#include <random> 

using namespace std; 

struct vec_struct{ 
    int num; 
    int count; 
    double ratio; 
}; 

void num_sort(vec_struct v[], int n){ 
    for (int i = 0; i < n-1; i++){ 
     for (int k = 0; k < n-1-i; k++){ 
      if (v[k].num > v[k+1].num) swap(v[k], v[k+1]); 
     } 
    } 
} 

void count_sort(vec_struct v[], int n){ 
    for (int i = 0; i < n-1; i++){ 
     for (int k = 0; k < n-1-i; k++){ 
      if (v[k].count < v[k+1].count) swap(v[k], v[k+1]); 
     } 
    } 
} 

int main(){ 

    srand(time(0)); 

    random_device rnd; 

    int s, l, b, c = 1; 

    cout << "How many numbers to generate? "; 
    cin >> s; 

    cout << "Generate " << s << " numbers ranging from 1 to? "; 
    cin >> l; 

    cout << "Use rand or mt19937? [1/2] "; 
    cin >> b; 

    vec_struct * vec = new vec_struct[s]; 

    mt19937 engine(rnd()); 
    uniform_int_distribution <int> dist(1, l); 

    if (b == 1){ 
     for (int i = 0; i < s; i++){ 
      vec[i].num = (rand() % l) + 1; 
     } 
    } else if (b == 2){ 
     for (int i = 0; i < s; i++){ 
      vec[i].num = dist(engine); 
     } 
    } 
    num_sort(vec, s); 

    for (int i = 0, j = 0; i < s; i++){ 
     if (vec[i].num == vec[i+1].num){ 
      c++; 
     } else { 
      vec[j].num = vec[i].num; 
      vec[j].count = c; 
      vec[j].ratio = ((double)c/s)*100; 
      j++; 
      c = 1; 
     } 
    } 
    count_sort(vec, l); 

    if (l >= 20){ 

     cout << endl << "Showing the 10 most common numbers" << endl; 
     for (int i = 0; i < 10; i++){ 
      cout << vec[i].num << "\t" << vec[i].count << "\t" << vec[i].ratio << "%" << endl; 
     } 

     cout << endl << "Showing the 10 least common numbers" << endl; 
     for (int i = l-10; i < l; i++){ 
      cout << vec[i].num << "\t" << vec[i].count << "\t" << vec[i].ratio << "%" << endl; 
     } 
    } else { 

     for (int i = 0; i < l; i++){ 
      cout << vec[i].num << "\t" << vec[i].count << "\t" << vec[i].ratio << "%" << endl; 
     } 
    } 
} 

运行此代码后,我可以从RAND()现货预期偏差:

$ ./rnd_test 
How many numbers to generate? 10000 
Generate 10000 numbers ranging from 1 to? 50 
Use rand or mt19937? [1/2] 1 

Showing the 10 most common numbers 
17 230 2.3% 
32 227 2.27% 
26 225 2.25% 
25 222 2.22% 
3 221 2.21% 
10 220 2.2% 
35 218 2.18% 
5 217 2.17% 
13 215 2.15% 
12 213 2.13% 

Showing the 10 least common numbers 
40 187 1.87% 
7 186 1.86% 
39 185 1.85% 
42 184 1.84% 
43 184 1.84% 
34 182 1.82% 
21 175 1.75% 
22 175 1.75% 
18 173 1.73% 
44 164 1.64% 

胡佛我得到几乎与mt19937uniform_int_distribution相同的结果!这里有什么问题?不应该是统一的,或者测试是无用的?

+0

尝试采取高阶位代替。那些通常分布更好。即'(rand_num - rand_num%n)>> log2(n)' – StoryTeller

+1

你被告知谁?在什么平台和什么运行时间?通常没有关于rand()分布和质量的保证 –

+0

@OlegBogdanov他与'uniform_int_distribution'和'mt19937'比较 – Danh

回答

1

不,它不应该是完全一致的。因此上述不是任何错误的证据。

它们是随机的,因此它应该是相当一致的,但不完全一样。

特别是你会希望每个数字出现大约10000/50 = 200次 - 粗略地说,sqrt(200)的标准偏差约为14--而对于50个数字,你会期望大约有2个标准差的差异 - 这是+ -/28。

使用模RAND_MAX引起的偏差小于该值;所以你需要更多的样本来检测偏差。

-1

据我可以从 http://www.cplusplus.com/reference/random/mersenne_twister_engine/ mt19937告诉将从相同的偏置遭受兰特()

偏置是由于兰特()在一定范围内[0-MAX_RAND],产生一个无符号的整数,当你把它做小的数字略微更有可能的模量(除非你的除数是MAX_RAND的整数除数)

考虑:

Range [0-74]: 
0 % 50 = 0 
40 % 50 = 40 
50 % 50 = 0 
74 % 50 = 24 
(numbers less than 25 occur twice) 
+0

直接使用twister_engine会遇到类似的问题,但通过uniform_int_distribution间接使用它可以避免这个问题。 (而且我没有让你失望。) –

0

你必须使用更多的样本进行这样的随机数的测试。我用你的代码试了50000,结果是:

要生成多少个数字? 50000

生成范围从1到?的50000个数字。 50

使用rand还是mt19937? [1/2] 2

显示的10倍最常见的数字

36 1054 2.108%

14 1051 2.102%

11 1048 2.096%

27 1045 2.09%

2 1044 2.088%

33 1035 2.07%

21 1034 2.068%

48 1034 2.068%

34 1030 2。06%

39 1030 2.06%

显示的10个最不常见的数字

47 966 1.932%

16 961 1.922%

38 960 1.92%

28 959 1.918%

8 958 1.916%

10 958 1.916%

30 958 1.916%

32 958 1.916%

18 953 1.906%

23 953 1.906%