Генерация случайных значений без time.h - PullRequest
0 голосов
/ 11 мая 2018

Я хочу генерировать случайные числа повторно без использования библиотеки time.h. Я видел другой пост относительно использования

srand(getpid()); 

однако, похоже, что это не работает для меня, getpid не был объявлен. Это потому что я скучаю по библиотеке? Если это так, мне нужно разобраться, как генерировать числа случайным образом без использования каких-либо других библиотек, кроме тех, которые у меня есть в настоящее время.

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


int main(void) {
    int minute, hour, day, month, year;
    srand(getpid());
    minute = rand() % (59 + 1 - 0) + 0;
    hour = rand() % (23 + 1 - 0) + 0;
    day = rand() % (31 + 1 - 1) + 1;
    month = rand() % (12 + 1 - 1) + 1;
    year = 2018;

    printf("Transferred successfully at %02d:%02d on %02d/%02d/%d\n", hour, 
    minute, day, month, year);

    return 0;
}

Примечание: Я могу использовать только библиотеки <stdio.h> и <stdlib.h> и <string.h> - строгие правила для назначения.

Ответы [ 3 ]

0 голосов
/ 11 мая 2018

однако, похоже, что это не работает для меня, getpid не был объявлен.

Это потому, что вам нужно включить заголовки для getpid():

   #include <sys/types.h>
   #include <unistd.h>

Другой вариант - использовать time() для заполнения (вместо getpid()):

   srand((unsigned int)time(NULL));
0 голосов
/ 11 мая 2018

Как указано в другом ответе, вам нужно включить заголовок unistd.h. Если вы не хотите этого делать, поместите объявление getpid() выше main(). Прочтите страницу руководства getpid() здесь http://man7.org/linux/man-pages/man2/getpid.2.html

Один подход может быть

#include <stdio.h>
#include <stdlib.h>
pid_t getpid(void); /* put the declrataion of getpid(), if don't want to include the header */
int main(void) {

   /* .. some code .. */
   return 0;
} 

Или вы можете использовать time() как

srand((unsigned int)time(NULL));
0 голосов
/ 11 мая 2018

getpid не был объявлен.

Нет, потому что вы не включили заголовок <unistd.h>, где он объявлен (и согласно вашему комментарию , вы не можете использовать его, потому что вы ограничены использованием <stdlib.h>, <string.h> и <stdio.h>).

В этом случае я бы использовал что-то вроде

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

static int randomize_helper(FILE *in)
{
    unsigned int  seed;

    if (!in)
        return -1;

    if (fread(&seed, sizeof seed, 1, in) == 1) {
        fclose(in);
        srand(seed);
        return 0;
    }

    fclose(in);
    return -1;
}

static int randomize(void)
{
    if (!randomize_helper(fopen("/dev/urandom", "r")))
        return 0;
    if (!randomize_helper(fopen("/dev/arandom", "r")))
        return 0;
    if (!randomize_helper(fopen("/dev/random", "r")))
        return 0;

    /* Other randomness sources (binary format)? */

    /* No randomness sources found. */
    return -1;
}

и простой main() для вывода некоторых псевдослучайных чисел:

int main(void)
{
    int i;

    if (randomize())
        fprintf(stderr, "Warning: Could not find any sources for randomness.\n");

    for (i = 0; i < 10; i++)
        printf("%d\n", rand());

    return EXIT_SUCCESS;
}

Символьные устройства /dev/urandom и /dev/random доступны в Linux, FreeBSD, macOS, iOS, Solaris, NetBSD, Tru64 Unix5.1B, AIX 5.2, HP-UX 11i v2 и /dev/random и /dev/arandom в OpenBSD 5.1 и более поздних версиях.

Как обычно, похоже, что Windows не предоставляет таких источников случайности: программы на Windows Cвместо этого необходимо использовать проприетарные интерфейсы Microsoft.

randomize_helper() возвращает ненулевое значение, если входной поток равен NULL или если он не может прочитать с него unsigned int.Если он может читать из него беззнаковое целое, он используется для заполнения стандартного генератора псевдослучайных чисел, к которому вы можете получить доступ, используя rand() (который возвращает int в диапазоне от 0 до RAND_MAX включительно).Во всех случаях randomize_helper() закрывает ненулевые потоки.

Вы можете добавить другие двоичные источники случайности к randomize() тривиально.

Если randomize() вернет 0, rand() должен вернутьсяпсевдослучайные числа.В противном случае rand() вернет ту же последовательность псевдослучайных чисел по умолчанию.(Они все равно будут «случайными», но одна и та же последовательность будет происходить при каждом запуске программы. Если randomize() вернет 0, последовательность будет отличаться при каждом запуске программы.)


Большинство стандартных реализаций C rand() - это линейные конгруэнтные генераторы псевдослучайных чисел, часто с плохим выбором параметров, и, как следствие, медленные и не очень «случайные».

Для некриптографической работы Iхотел бы реализовать одну из функций семейства Xorshift , первоначально Джорджа Марсалья.Они очень, очень быстрые и достаточно случайные;они проходят большинство тестов статистической случайности, таких как несгибаемые тесты .

. В случае OP можно использовать генератор xorwow .Согласно действующим стандартам C, unsigned int составляет не менее 32 бит, поэтому мы можем использовать его в качестве типа генератора.Давайте посмотрим, как будет выглядеть реализация для замены стандартного srand () / rand ():

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

/* The Xorwow PRNG state. This must not be initialized to all zeros. */
static unsigned int  prng_state[5] = { 1, 2, 3, 4, 5 };

/* The Xorwow is a 32-bit linear-feedback shift generator. */
#define  PRNG_MAX  4294967295u

unsigned int  prng(void)
{
    unsigned int  s, t;

    t = prng_state[3] & PRNG_MAX;
    t ^= t >> 2;
    t ^= t << 1;
    prng_state[3] = prng_state[2];
    prng_state[2] = prng_state[1];
    prng_state[1] = prng_state[0];
    s = prng_state[0] & PRNG_MAX;
    t ^= s;
    t ^= (s << 4) & PRNG_MAX;
    prng_state[0] = t;
    prng_state[4] = (prng_state[4] + 362437) & PRNG_MAX;
    return (t + prng_state[4]) & PRNG_MAX;
}

static int prng_randomize_from(FILE *in)
{
    size_t        have = 0, n;
    unsigned int  seed[5] = { 0, 0, 0, 0, 0 };

    if (!in)
        return -1;

    while (have < 5) {
        n = fread(seed + have, sizeof seed[0], 5 - have, in);
        if (n > 0 && ((seed[0] | seed[1] | seed[2] | seed[3] | seed[4]) & PRNG_MAX) != 0) {
            have += n;
        } else {
            fclose(in);
            return -1;
        }
    }

    fclose(in);
    prng_seed[0] = seed[0] & PRNG_MAX;
    prng_seed[1] = seed[1] & PRNG_MAX;
    prng_seed[2] = seed[2] & PRNG_MAX;
    prng_seed[3] = seed[3] & PRNG_MAX;
    prng_seed[4] = seed[4] & PRNG_MAX;

    /* Note: We might wish to "churn" the pseudorandom
             number generator state, to call prng()
             a few hundred or thousand times. For example:
       for (n = 0; n < 1000; n++) prng();
             This way, even if the seed has clear structure,
             for example only some low bits set, we start
             with a PRNG state with set and clear bits well
             distributed.
    */

    return 0;
}

int prng_randomize(void)
{
    if (!prng_randomize_from(fopen("/dev/urandom", "r")))
        return 0;
    if (!prng_randomize_from(fopen("/dev/arandom", "r")))
        return 0;
    if (!prng_randomize_from(fopen("/dev/random", "r")))
        return 0;
    /* Other sources? */
    /* No randomness sources found. */
    return -1;
}

Соответствующий main() выше будет

int main(void)
{
    int  i;

    if (prng_randomize())
        fprintf(stderr, "Warning: No randomness sources found!\n");

    for (i = 0; i < 10; i++)
        printf("%u\n", prng());

    return EXIT_SUCCESS;
}

Обратите внимание, что PRNG_MAX имеет двойное назначение.С одной стороны, он сообщает максимальное значение, которое prng() может вернуть - это unsigned int, а не int, как rand().С другой стороны, поскольку оно должно быть 2 32 -1 = 4294967295, мы также используем его для обеспечения того, чтобы временные результаты при генерации следующего псевдослучайного числа в последовательности оставались 32-битными.Если бы был доступен тип uint32_t, объявленный в stdint.h или inttypes.h, мы могли бы использовать его и отбросить маски (& PRNG_MAX).

Обратите внимание, что функция prng_randomize_from() написана так, чтоон все еще работает, даже если источник случайности не может предоставить все запрошенные байты одновременно, и возвращает «короткий счет» .Вопрос о том, происходит ли это на практике, остается спорным, но я предпочитаю быть уверенным.Также обратите внимание, что он не принимает состояние, если все его нули, так как это единственное запрещенное начальное начальное состояние для Xorwow PRNG.

Очевидно, вы можете использовать как srand() / rand(), так и prng() / prng_randomize() в той же программе.Я написал их так, чтобы все функции генератора Xorwow начинались с prng.

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

...