rand () каждый раз дает почти одинаковое число - PullRequest
0 голосов
/ 29 сентября 2019

Я изучаю C и хочу сгенерировать число от 0 до 6400. Вот код, который я придумал:

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

int main()
{
    srand(time(0));
    int i = (rand() % 6401);
    printf("Random number between 0 and 6400: %d\n", i);
    return 0;
}

Когда я компилирую и запускаю этот код из командной строки, яполучить очень странные результаты:

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6282

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6282

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6285

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6285

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6289

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6289

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6292

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6292

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6295

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6298

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6298

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6302

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6302

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6305

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6305

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6308

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6308

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6311

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6311

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6315

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6315

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6318

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6318

K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6321

K:\C\Labo\Oefeningen 2019>

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

РЕДАКТИРОВАТЬ: Я знаю, он даст то же значение, когда вы запустите код в течение той же секунды.Я ждал несколько секунд (10-20) между выполнениями, и я все еще получаю тот же результат?Значения редко бывают одинаковыми, они просто очень, очень, очень похожи в 100% случаев.Как мне обойти это?

Ответы [ 5 ]

3 голосов
/ 29 сентября 2019

time() имеет разрешение 1 секунда.Таким образом, ваша программа будет генерировать другое значение только через полсекунды в среднем.

Если ваш компилятор поддерживает C11, вы можете использовать функцию с более высоким разрешением, timespec_get().Ваш srand(time(0)); будет преобразован в следующее:

struct timespec ts;
timespec_get(&ts, TIME_UTC);
srand(ts.tv_nsec);

Здесь ts.tv_nsec - это наносекундная часть метки времени, разрешение которой должно быть достаточно для вашей цели.

Есливаш компилятор не поддерживает C11, вы все равно можете иметь лучший источник случайного начального числа, чем time(), с разрешением около миллисекунды (фактическое разрешение задается макросом CLOCKS_PER_SEC): функция clock().Тогда ваш код заполнения будет

srand(clock());

Обратите внимание, что на самом деле он может быть плохим источником энтропии, особенно если ваша ОС не занята, так что программа будет работать в несколько предсказуемом темпе.Это потому, что начало эры clock() связано с выполнением программы, а не с реальным временем.Возможно, было бы лучше, например, использовать сумму clock() и time(0), чтобы получить более непредсказуемое значение:

srand(time(0)+clock());
0 голосов
/ 30 сентября 2019

Числа, сгенерированные rand, на самом деле не случайны, они генерируются по формуле.Вот почему посев возможен и необходим.В зависимости от используемой формулы, может быть высокая корреляция между начальным числом и первыми несколькими случайными числами.

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

0 голосов
/ 29 сентября 2019

Если кто-то еще столкнется с этой проблемой, я думаю, что нашел обходной путь.Я знаю, что это не идеальное решение, но это единственное, что сработало для меня.Я думаю, что генератор случайных чисел, используемый в моем компиляторе, вообще не любит подобные семена.С помощью этого фрагмента кода он фактически генерирует несколько приемлемых полуслучайных чисел:

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

int main()
{
    srand((unsigned int)time(0) * 100000000);
    int i = (rand() % 6401);
    printf("Random number between 0 and 6400: %d\n", i);
    return 0;
}

Вот где я получил свой компилятор мусорных баков от btw: http://tdm -gcc.tdragon.net / download

0 голосов
/ 29 сентября 2019

Если ваш rand обанкротился, вы можете попробовать один из генераторов псевдослучайных чисел xorshift .Они не идеальны, но полученная реализация очень коротка.Этого может быть достаточно для вашего собственного использования.

Вот пример реализации: я использовал этот один в качестве ссылки.

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

uint64_t    xorshift64s(uint64_t seed)
{
    static uint64_t i = 1;

    if (seed != 0)
        i = seed;
    i ^= i >> 12;
    i ^= i << 25;
    i ^= i >> 27;
    i *= 0x2545f4914f6cdd1d;
    return (i >> 32);
}


int main()
{
    srand(time(0));
    int i = (rand() % 6401);
    printf("rand    : Random number between 0 and 6400: %d\n", i);
    xorshift64s(time(0));
    int j = (xorshift64s(0) % 6401);
    printf("xorshift: Random number between 0 and 6400: %d\n", j);
    return 0;
}
0 голосов
/ 29 сентября 2019

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

Имейте в виду, что это все еще не случайно.

...