Можно ли раздавать рандомизатор более одного раза, если это делается таким образом?

Скажем, у меня есть этот цикл:

for (i=0; i < 100; i++)
{
    srand(time(NULL));
    printf("%d\n", rand());
}

Если моя машина достаточно быстра, она должна напечатать одно и то же число 100 раз.

Но если я изменю его так:

for (i=0; i < 100; i++)
{
    srand(time(NULL) + rand());
    printf("%d\n", rand());
}

Затем он должен вывести 100 различных чисел. Мой вопрос: есть ли что-то неправильное в такой раздаче рандомизатора? Как насчет эффективности? Сильно ли это снижает эффективность?

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

ИЗМЕНИТЬ

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

Пример:

int main()
{
    int i;

    srand(time(NULL));  // Seeded here, but the print_rand() function does not know it

    for (i=0; i < 100; i++)
    {
        print_rand();
    }

    return(0);
}


// Pretend this function is in a library
void print_rand()
{
    srand(time(NULL) + rand()); // No guarantee if seeding was done before, so doing it here

    printf("%d\n", rand());
}

ИЗМЕНИТЬ 2

Я только что протестировал его с 1000000 циклов. Раздача один раз занимала 0.024s, а раздача каждый раз занимала 4.972s. Поэтому я предполагаю, что это приводит к значительному снижению производительности, если это большой цикл.


person CluelessNoob    schedule 25.08.2015    source источник
comment
Однократного заполнения рандомизатора должно быть достаточно для большинства приложений. В противном случае вам все равно следует изучить другие (более специализированные) рандомизаторы.   -  person Kninnug    schedule 25.08.2015
comment
Если вы хотите что-то действительно случайное, вам не следует использовать rand()/srand(). Вместо этого используйте Intel Secure Key (доступно на процессорах Intel с 2006 г.).   -  person ArtOfWarfare    schedule 25.08.2015
comment
Вопрос в том, почему вы хотели бы заполнить его более одного раза. Это как спросить: мне нужен красный дом. Можно ли покрасить мой дом в красный цвет 100 раз вместо одного раза?   -  person Lundin    schedule 25.08.2015
comment
Спасибо, теперь намного понятнее. Я не собираюсь использовать его для чего-то очень безопасного. Это только для небольших игр и тому подобного. Пожалуйста, смотрите редактирование.   -  person CluelessNoob    schedule 25.08.2015
comment
Вы можете использовать статическую переменную, чтобы помнить, если вы уже засеяли. статический интервал семени = 0; if(!seed) { srand(...); посеянный = 1; }   -  person Daniel S    schedule 25.08.2015


Ответы (3)


Не делай этого.

Посев один раз.

srand(time(NULL) + rand()); приведет к статистической погрешности при повторном использовании. Интуитивно это происходит из-за двух эффектов: (i) srand(rand()) эффективно опускает все остальные числа, что увеличивает дисперсию, и (ii) srand(time(NULL)) вводит дополнительную аддитивную константу, которая приводит к тому, что оператор по модулю в генераторе будет вызываться чаще, чем это должно. Вы можете даже нарушить периодичность генератора.

Почему бы не проверить это? Я ожидаю, что среднее значение будет в целом правильным, но я предполагаю, что дисперсия и более высокие моменты будут неправильными.

person Bathsheba    schedule 25.08.2015
comment
вы правы насчет предвзятости, но это только потому, что rand() - это линейный конг. генератор. - person Gianluca Ghettini; 25.08.2015
comment
Повторное заполнение приводит к смещению, но добавление смещения к начальному значению не приводит к смещению, если вы делаете это только один раз. Заполнение PRNG — это выбор точки входа в свой цикл, добавление сдвига просто перемещает точку входа. Цикл выдаваемых чисел идентичен независимо от того, где вы поднимаетесь на борт, если вы не выполняете повторную раздачу. - person pjs; 25.08.2015

Как правило, неправильно заполнять PRNG более одного раза. Это действительно не повышает безопасность PRNG и не делает его быстрее (может быть, медленнее!)

ГПСЧ необходимо заполнить один раз

И да, достаточно посеять его в одном месте. Другая история была бы, если бы у вас было несколько экземпляров одного и того же prng, но это не так, это C, а не C++, а rand() является статическим.

Все дело в том, что вы хотите делать со случайными данными...

  • Криптовалюта? забудьте об использовании rand(), srand() и time()
  • рандомизировать какой-нибудь игровой ИИ? это может быть хорошо
person Gianluca Ghettini    schedule 25.08.2015

Похоже, вы хотите улучшить вывод rand.

  1. Ваш метод этого не сделает. Поскольку ваш код, скорее всего, будет известен, любой сможет увидеть, что вы сделали, и тогда ваш метод эквивалентен вызову srand всего один раз.
  2. Даже не зная вашего кода, просто зная, что вы используете rand, числа, сгенерированные из него, в большинстве систем будут легко предсказуемы.

rand полезен только в очень простых ситуациях, когда что-то должно выглядеть случайным для человека. Как простая игра. И в таких ситуациях достаточно одного вызова srand.

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

Чтобы ответить на вопрос. Это не должно повредить. Возможно, вы сделаете предсказуемые цифры еще более предсказуемыми. Возможно, предвзятые цифры будут немного более предвзятыми. Человек (единственное существо, которое может быть обмануто rand) по-прежнему, вероятно, будет считать их достаточно случайными. С другой стороны, вы ничего от этого не получите, так зачем терять время?

person Art    schedule 25.08.2015