Как я могу написать функцию генератора случайных чисел? - PullRequest
0 голосов
/ 11 апреля 2020

История: Используя функцию rand() в C ++, я могу получить случайные числа, а используя %, я могу установить диапазон. Однако, если я также хочу добавить смещение, то я также должен добавить смещение к результату. Это слишком много работы, поэтому я решил написать свою собственную функцию для этого. Однако я застрял в одной точке.

Я знаю, что мне нужно вводить новую последовательность (srand(time(NULL))) при каждом запуске программы, в противном случае я буду получать одни и те же числа все время.

Очевидный способ сделать это - вставить srand(time(NULL)) в функцию main(). Однако я не хочу этого делать, я хочу, чтобы каким-то образом это делалось автоматически, когда я включаю мой .h файл.

Предположим, myFunctions.h:

#include <iostream>
#include <string>
#include <vector>
#include <cstdio>
#include <ctime>

int randint(int start, int end);

и myFunctions.cpp:

#include "myFunctions.h"

/* [start,end) */
int randint(int start, int end)
{

    return (rand() % (end - start)) + start;

}

Теперь я запутался, когда мне нужно добавить srand(). Если я сделаю это в определении randint(), я предполагаю, что из-за того, что разница во времени будет слишком мала, time(NULL) будет оценивать одно и то же значение для каждого шага l oop и будет подавать все семена время, когда я хочу получить случайные числа за очень короткое время, например:

for(int i = 0; i < 50; i++){
    std::cout << randint(0, 3) << std::endl;
}

На выходе получается то же число, 50 раз. Так что это подтверждает мое подозрение.

Я пробовал что-то подобное в моем определении randint(),

int randint(int start, int end)
{

    #ifndef SEED
        srand(time(NULL));
        #define SEED
    #endif 

    return (rand() % (end - start)) + start;

}

Однако, это тоже не сработало, потому что, я полагаю, #ifndef выполняется только один раз на этапе предварительной обработки.

Итак, после этих попыток я попытался вызвать srand() прямо в начале моего .h файла, но я столкнулся с тем фактом, что на самом деле вы не можете вызывать функции вне какой-либо функции (например, main())

Короче, я застрял прямо сейчас, любая помощь будет оценена.

Ответы [ 2 ]

1 голос
/ 11 апреля 2020

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

0 голосов
/ 11 апреля 2020

Используйте функцию call_once, доступную в C ++ 11 и далее. Это требует использования <mutex>. Вы должны создать вспомогательный объект once_flag. f должно быть установлено c, поэтому оно сохраняется при вызове функций. В этом примере используется лямбда, но вы также можете легко создать обычную старую функцию выше этой, называемой seedrand() или чем-то еще, и передать ее в качестве параметра.

Пример поднял с https://en.cppreference.com/w/cpp/thread/call_once и модифицировано, чтобы соответствовать вашей программе.

#include <iostream>
#include <mutex>

int randint(int start, int end)
{
    static std::once_flag f;
    std::call_once(f, []() {srand(time(NULL)); std::cout << "Random Seeded\n"; });

    return (rand() % (end - start)) + start;
}

int main(int argc, char** argv)
{
    for (int i = 0; i < 10; i++)
    {
        std::cout << i << ": " << randint(1, 100) << "\n";
    }
}

Если вы хотите передать srand непосредственно как функцию, вы должны передать ее аргументы в качестве дополнительных параметров. Обратите внимание на отсутствие () после srand. Вы не хотите передавать RESULT srand в call_once, вы хотите передать саму функцию. call_once позвонит вам за это.

static std::once_flag f;
std::call_once(f, srand, time(NULL)); // notice the lack of () after srand

Редактировать: std::call_once излишне

Тот факт, что вам нужно скомпилировать это с pthread, просто смешно. std::call_once следует использовать только для того, чтобы сделать что-то подобное, если у вас есть несколько потоков, вызывающих один и тот же кусок кода, и вы хотите, чтобы он вообще выполнялся один раз.

Гораздо более простым решением было бы просто использовать stati c логическое:

int randint(int start, int end)
{
    static bool seeded = false;
    if (!seeded)
    {
        srand(time(NULL));
        seeded = true;
    }

    return (rand() % (end - start)) + start;
}
...