2017-02-21 38 views
4

Это скорее всего проблема с машиной, но я не могу понять, что может быть неправильным.C rand() не является случайным даже при посеве

#include <stdio.h> 
#include <stdlib.h> 
#include <time.h> 

int main(int argc, char** argv) { 

    srand(time(NULL)); 
    int r1 = rand(); 
    int r2 = rand(); 
    printf("%d %d\n", r1, r2); 
} 

я скомпилировать выше фрагмент кода с помощью

gcc randd.c 

Затем запустить его несколько раз вручную, и первые цифры кажутся невероятно похожи, а вторые кажутся случайным:

1025720610 1435057801 
1025737417 1717533050 
1025754224 2000008299 
1025771031 134999901 
1025787838 417475150 

Этот первый вызов rand() кажется сильно связанным со временем и строго увеличивается с течением времени. Любые идеи относительно того, почему это происходит или как его решить?

Это происходит на OSX 10.11

+0

Какая система показывает проблему? 'printf ("% d \ n ", rand());' может показать проблему немного более четко. Я ожидаю получить тот же результат, если программа запускается дважды в течение 1 секунды, но вы получаете (слегка) разные результаты каждый раз. Убедитесь, что код, который вы нам показали, является * точно * кодом, который вы скомпилировали и запустили. –

+2

Возможный дубликат [srand (time (NULL)), генерирующий аналогичные результаты] (http: // stackoverflow.com/questions/6668282/srandtimenull-generate-подобные-результаты) – emlai

+0

@KeithThompson Я опубликовал скриншот с точным кодом и командами, которые я выполняю –

ответ

2
  1. rand() очень плохо, избежать его, если это возможно. В любом хорошем RNG первые значения будут неотличимы от случайных, даже когда семя будет близко (расстояние от хамминга). В rand это не тот случай.
  2. Если вы должны использовать rand, то засевайте его, предпочтительно с чем-то более высоким энтропией, чем время, и вызовите rand() несколько раз вместо пересадки-вызова-пересадки.

Для примера 2, рассмотрим:

#include <stdio.h> 
#include <stdlib.h> 
#include <time.h> 

int main(int argc, char** argv) { 
    int t=time(NULL); 
    srand(t); 

    for(int i=0; i < 10; i++) { 
    float r = (float)rand()/(float)(RAND_MAX); 
    printf("%f\n", r); 
    } 
} 

С результатом:

0.460600 
0.310486 
0.339473 
0.519799 
0.258825 
0.072276 
0.749423 
0.552250 
0.665374 
0.939103 

Это все еще плохо ГСЧ, но по крайней мере, диапазон лучше, если вы позволите использовать внутреннее состояние вместо того, чтобы давать ему другое подобное семя.

+1

Что-то вроде времени xor pid, например, является * несколько лучшим семенем, но все же очень предсказуемым. На самом деле используйте '/ dev/urandom' (или что-то, что эквивалентно Windows). – Schwern

+0

'rand()' не является по своей сути плохим. Некоторые реализации 'rand()' являются плохими. –

+0

@ KeithThompson С точки зрения безопасности, спецификация 'rand' настолько широка, и реализация настолько непредсказуема, что« rand »по своей сути плохо. – Schwern

1

Это именно то, чего вы должны ожидать. Нет такой вещи, как «случайное число». Есть только последовательностей чисел со случайным распределением. Функция rand() генерирует такие последовательности, но вы не даете ей возможности, потому что вы продолжаете повторное посев. Первое число, генерируемое rand(), вполне может быть просто функцией семени или самого семени. Некоторые функции rand() могут хешировать семя, чтобы скрыть это, но это на самом деле не делает их лучше, потому что контракт rand() заключается в создании случайной последовательности .

Если вам нужна последовательность случайных чисел, которая выживает при запуске нескольких программ, вам нужно будет сделать что-то вроде: (a) Записать программу, которая вызывает srand() один раз, а затем много раз называет rand(), а ваши другие программы запрашивают случайные числа из этой программы по IPC; (b) Используйте что-то вроде /dev/urandom; (c) Используйте что-то вроде random.org.