Rand() генерирует такое же число - даже с srand (time (NULL)) в моем главном!

Итак, я пытаюсь создать случайный вектор (думаю, геометрия, а не расширяемый массив), и каждый раз, когда я вызываю свою случайную векторную функцию, я получаю одно и то же значение 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? Исправлен ли я неправильно?

Ответы

Ответ 1

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

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

Ответ 2

Я не вижу проблем с вашим 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

Кроме того, вы можете даже избавиться от этой странной переменной 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;

Ответ 4

Простым quickfix является вызов 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

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

Ответ 5

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

Ответ 6

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

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

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

где

rand() / (RAND_MAX + 1.0)

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

Ответ 7

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

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