rand () генерирует одно и то же число - даже с srand (time (NULL)) в моем главном! - PullRequest
14 голосов
/ 13 июня 2010

Итак, я пытаюсь создать случайный вектор (например, геометрия, а не расширяемый массив), и каждый раз, когда я вызываю свою функцию случайного вектора, я получаю одно и то же значение x, хотя y и z различны.

int main () {
    srand ( (unsigned)time(NULL));
    Vector<double> a;
    a.randvec();
    cout << a << endl;
    return 0;
}

с использованием функции

//random Vector
template <class T>
void Vector<T>::randvec()
{
    const int min=-10, max=10;
    int randx, randy, randz;

    const int bucket_size = RAND_MAX/(max-min);

    do randx = (rand()/bucket_size)+min;
    while (randx <= min && randx >= max);
    x = randx;

    do randy = (rand()/bucket_size)+min;
    while (randy <= min && randy >= max);
    y = randy;

    do randz = (rand()/bucket_size)+min;
    while (randz <= min && randz >= max);
    z = randz;
}

По какой-то причине randx будет последовательно возвращать 8, тогда как другие числа, по-видимому, идеально следуют (псевдо) случайности.Однако, если я добавлю вызов, чтобы определить, скажем, randy перед randx, randy всегда вернет 8.

Почему мое первое случайное число всегда равно 8?Я неправильно высеваю?

Ответы [ 7 ]

8 голосов
/ 13 июня 2010

Проблема заключается в том, что генератор случайных чисел засевается значениями, которые очень близки друг к другу - каждый запуск программы лишь незначительно меняет возвращаемое значение time () - возможно, 1 секунду, возможно, даже ни одного!Довольно слабый стандартный генератор случайных чисел затем использует эти аналогичные начальные значения для генерации явно идентичных начальных случайных чисел.По сути, вам нужен лучший начальный генератор начальных чисел, чем time (), и лучший генератор случайных чисел, чем rand ().

Реальный используемый алгоритм зацикливания, я думаю, был снят с Accelerated C ++ и предназначен для получения лучшего разбросачисел в требуемом диапазоне, чем, скажем, с помощью оператора мод будет.Но это не может компенсировать постоянное (эффективное) получение одного и того же семени.

5 голосов
/ 13 июня 2010

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

do randx = (rand()/bucket_size)+min;
while (randx <= min && randx >= max);

Эта строка, вероятно, не делает то, что вы хотели. Пока min < max (и так должно быть всегда), для randx невозможно быть одновременно меньше или равным min и больше или равным max. Кроме того, вам не нужно цикл вообще. Вместо этого вы можете получить значение между min и max, используя:

randx = rand() % (max - min) + min;
3 голосов
/ 13 июня 2010

Также стоит упомянуть, что вы даже можете избавиться от этой странной переменной bucket_size и использовать следующий метод для генерации чисел от a до b включительно:

srand ((unsigned)time(NULL));

const int a = -1;
const int b = 1;

int x = rand() % ((b - a) + 1) + a;
int y = rand() % ((b - a) + 1) + a;
int z = rand() % ((b - a) + 1) + a;
2 голосов
/ 13 июня 2010

Простое быстрое исправление - это вызов rand несколько раз после заполнения.

int main ()
{
    srand ( (unsigned)time(NULL));
    rand(); rand(); rand();

    Vector<double> a;
    a.randvec();
    cout << a << endl;
    return 0;
}

Просто, чтобы объяснить лучше, первый вызов rand () в четырех последовательных запусках тестовой программыдал следующий вывод:

27592
27595
27598
27602

Обратите внимание, насколько они похожи?Например, если вы разделите rand() на 100, вы получите одно и то же число 3 раза подряд.Теперь взгляните на второй результат rand () в четырех последовательных прогонах:

11520
22268
248
10997

Это выглядит намного лучше, не так ли?Я действительно не вижу причин для отрицательных голосов.

1 голос
/ 22 февраля 2012

У меня была точно такая же проблема.Я исправил это, переместив вызов srand (), чтобы он вызывался в моей программе только один раз (ранее я помещал его в начало вызова функции).Не очень разбираюсь в технических деталях - но это была решенная проблема.

0 голосов
/ 05 декабря 2018

Не имеет прямого отношения к коду в этом вопросе, но у меня была та же проблема с использованием srand ((unsigned)time(NULL)) и все еще имеет ту же последовательность значений, которые возвращаются из следующих вызовов rand().

Оказалось, что srand нужно вызывать для каждого потока, в котором вы используете его отдельно. У меня был поток загрузки, который генерировал случайный контент (который не был случайным, потому что проблема семени). Я просто использовал srand в основной ветке, а не в загрузочной. Поэтому добавлен еще один srand ((unsigned)time(NULL)) к началу загрузки темы, исправил эту проблему.

0 голосов
/ 13 июня 2010

Ваша реализация через целочисленное деление игнорирует младший 4-5 бит случайного числа.Поскольку ваш RNG засевается с использованием системного времени, первое полученное из него значение будет изменяться только (в среднем) каждые 20 секунд.

Это должно работать:

randx = (min) + (int) ((max - min) * rand() / (RAND_MAX + 1.0));

где

rand() / (RAND_MAX + 1.0)

- случайное двойное значение в [0, 1), а остальное просто сдвигает его.

...