Почему цифры 1, 2 и 3 появляются так часто, используя функцию C rand()?
Я пытаюсь создать несколько случайных чисел (не обязательно одну цифру), например
29106
7438
5646
4487
9374
28671
92
13941
25226
10076
а затем подсчитайте количество цифр, которое я получаю:
count[0] = 3 Percentage = 6.82
count[1] = 5 Percentage = 11.36
count[2] = 6 Percentage = 13.64
count[3] = 3 Percentage = 6.82
count[4] = 6 Percentage = 13.64
count[5] = 2 Percentage = 4.55
count[6] = 7 Percentage = 15.91
count[7] = 5 Percentage = 11.36
count[8] = 3 Percentage = 6.82
count[9] = 4 Percentage = 9.09
Это код, который я использую:
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
int main() {
int i;
srand(time(NULL));
FILE* fp = fopen("random.txt", "w");
// for(i = 0; i < 10; i++)
for(i = 0; i < 1000000; i++)
fprintf(fp, "%d\n", rand());
fclose(fp);
int dummy;
long count[10] = {0,0,0,0,0,0,0,0,0,0};
fp = fopen("random.txt", "r");
while(!feof(fp)) {
fscanf(fp, "%1d", &dummy);
count[dummy]++;
}
fclose(fp);
long sum = 0;
for(i = 0; i < 10; i++)
sum += count[i];
for(i = 0; i < 10; i++)
printf("count[%d] = %7ld Percentage = %5.2f\n",
i, count[i], ((float)(100 * count[i])/sum));
}
Если я создаю большое количество случайных чисел (1000000), это результат:
count[0] = 387432 Percentage = 8.31
count[1] = 728339 Percentage = 15.63
count[2] = 720880 Percentage = 15.47
count[3] = 475982 Percentage = 10.21
count[4] = 392678 Percentage = 8.43
count[5] = 392683 Percentage = 8.43
count[6] = 392456 Percentage = 8.42
count[7] = 391599 Percentage = 8.40
count[8] = 388795 Percentage = 8.34
count[9] = 389501 Percentage = 8.36
Обратите внимание, что у 1, 2 и 3 слишком много ударов. Я попытался запустить это несколько раз и каждый раз, когда получаю очень похожие результаты.
Я пытаюсь понять, что может привести к тому, что 1, 2 и 3 появятся гораздо чаще, чем любая другая цифра.
Взяв намек на то, что указал Мэтт Стонер и Паскаль Куок,
Я изменил код, чтобы использовать
for(i = 0; i < 1000000; i++)
fprintf(fp, "%04d\n", rand() % 10000);
// pretty prints 0
// generates numbers in range 0000 to 9999
и это то, что я получаю (аналогичные результаты при нескольких прогонах):
count[0] = 422947 Percentage = 10.57
count[1] = 423222 Percentage = 10.58
count[2] = 414699 Percentage = 10.37
count[3] = 391604 Percentage = 9.79
count[4] = 392640 Percentage = 9.82
count[5] = 392928 Percentage = 9.82
count[6] = 392737 Percentage = 9.82
count[7] = 392634 Percentage = 9.82
count[8] = 388238 Percentage = 9.71
count[9] = 388352 Percentage = 9.71
Что может быть причиной того, что предпочтение отдается 0, 1 и 2?
Спасибо всем. Использование
int rand2(){
int num = rand();
return (num > 30000? rand2():num);
}
fprintf(fp, "%04d\n", rand2() % 10000);
Я получаю
count[0] = 399629 Percentage = 9.99
count[1] = 399897 Percentage = 10.00
count[2] = 400162 Percentage = 10.00
count[3] = 400412 Percentage = 10.01
count[4] = 399863 Percentage = 10.00
count[5] = 400756 Percentage = 10.02
count[6] = 399980 Percentage = 10.00
count[7] = 400055 Percentage = 10.00
count[8] = 399143 Percentage = 9.98
count[9] = 400104 Percentage = 10.00
Ответы
Ответ 1
rand()
генерирует значение от 0
до RAND_MAX
. RAND_MAX
установлен на INT_MAX
на большинстве платформ, которые могут быть 32767
или 2147483647
.
В приведенном выше примере показано, что RAND_MAX
- 32767
. Это приведет к необычно высокой частоте 1
, 2
и 3
для самой значащей цифры для значений от 10000
до 32767
. Вы можете заметить, что в меньшей степени значения с точностью до 6
и 7
также будут немного благоприятными.
Ответ 2
Относительно отредактированного вопроса
Это потому, что цифры все равно неравномерно распределены, даже если вы % 10000
. Предположим, что RAND_MAX == 32767
, а rand()
совершенно однородно.
На каждые 10 000 номеров, считанных с 0, все цифры будут отображаться равномерно (4000 каждый). Однако 32 767 не делится на 10 000 человек. Таким образом, эти 2768 номеров будут обеспечивать большее количество ведущих 0, 1 и 2 до конечного счета.
Точный вклад этих 2776 номеров:
digits count
0 1857
1 1857
2 1625
3 857
4 857
5 857
6 855
7 815
8 746
9 746
добавив 12 000 для начальных 30 000 номеров в счетчик, затем разделите их на общее количество цифр (4 и раз 32 768), чтобы дать вам ожидаемое распределение:
number probability (%)
0 10.5721
1 10.5721
2 10.3951
3 9.80911
4 9.80911
5 9.80911
6 9.80759
7 9.77707
8 9.72443
9 9.72443
который близок к тому, что вы получаете.
Если вы хотите по-настоящему равномерное распределение цифр, вам нужно отклонить эти 2,768 номеров:
int rand_4digits() {
const int RAND_MAX_4_DIGITS = RAND_MAX - RAND_MAX % 10000;
int res;
do {
res = rand();
} while (res >= RAND_MAX_4_DIGITS);
return res % 10000;
}
Ответ 3
Похож на закон Бенфорда - см. http://en.wikipedia.org/wiki/Benford%27s_law или, альтернативно, не очень хороший RNG.
Ответ 4
Это потому, что вы генерируете числа между 0
и RAND_MAX
. Сгенерированные числа равномерно распределены (т.е. Примерно одинаковая вероятность для каждого номера), однако цифры 1,2,3 встречаются чаще, чем другие в этом диапазоне. Попробуйте создать между 0
и 10
, где каждая цифра встречается с той же вероятностью, и вы получите хороший дистрибутив.
Ответ 5
Если я понимаю, что хочет OP (человек, задающий вопрос), они хотят сделать лучшие случайные числа.
rand() и random(), откровенно говоря, не делают очень хорошие случайные числа; они оба плохо себя чувствуют при тестировании против несгибаемого и умственного (два пакета для проверки качества случайных чисел).
Mersenne twister - популярный генератор случайных чисел, который хорош для почти всего, кроме криптосильных случайных чисел; он проходит все испытания (с) с летающими цветами.
Если вам нужны криптосильные случайные числа (числа, которые нельзя угадать, даже если кто-то знает, какой именно криптосильный алгоритм используется), существует ряд шифровщиков потоков. Тот, который мне нравится использовать, называется RadioGatún [32] и имеет компактное представление C:
/*Placed in the public domain by Sam Trenholme*/
#include <stdint.h>
#include <stdio.h>
#define p uint32_t
#define f(a) for(c=0;c<a;c++)
#define n f(3){b[c*13]^=s[c];a[16+c]^=s[c];}k(a,b
k(p *a,p *b){p A[19],x,y,r,q[3],c,i;f(3){q[c]=b[c
*13+12];}for(i=12;i;i--){f(3){b[c*13+i]=b[c*13+i-
1];}}f(3){b[c*13]=q[c];}f(12){i=c+1+((c%3)*13);b[
i]^=a[c+1];}f(19){y=(c*7)%19;r=((c*c+c)/2)%32;x=a
[y]^(a[(y+1)%19]|(~a[(y+2)%19]));A[c]=(x>>r)|(x<<
(32-r));}f(19){a[c]=A[c]^A[(c+1)%19]^A[(c+4)%19];
}a[0]^=1;f(3){a[c+13]^=q[c];}}l(p *a,p *b,char *v
){p s[3],q,c,r,x,d=0;for(;;){f(3){s[c]=0;}for(r=0
;r<3;r++){for(q=0;q<4;q++){if(!(x=*v&255)){d=x=1;
}v++;s[r]|=x<<(q*8);if(d){n);return;}}}n);}}main(
int j,char **h){p a[39],b[39],c,e,g;if(j==2){f(39
){a[c]=b[c]=0;}l(a,b,h[1]);f(16){k(a,b);}f(4){k(a
,b);for(j=1;j<3;++j){g=a[j];for(e=4;e;e--){printf
("%02x",g&255);g>>=8;}}}printf("\n");}}
Есть также много других действительно хороших генераторов случайных чисел.
Ответ 6
Если вы хотите генерировать случайное значение из диапазона [0, x)
, вместо выполнения rand()%x
, вы должны применить формулу x*((double)rand()/RAND_MAX)
, которая даст вам хорошо распределенные случайные значения.
Скажем, RAND_MAX равен 15, поэтому rand
даст вам целые числа от 0 до 15. Когда вы используете оператор modulo для получения случайных чисел из [0, 10)
, значения [0,5]
будут иметь более высокую частоту, чем [6,9]
, потому что 3 == 3%10 == 13%10
.