Подтвердить что ты не робот

Как сгенерировать случайное число в С++?

Я пытаюсь сделать игру с кубиками, и мне нужно иметь в ней случайные числа (имитировать стороны кубика. Я знаю, как сделать это между 1 и 6). Использование

#include <cstdlib> 
#include <ctime> 
#include <iostream>

using namespace std;

int main() 
{ 
    srand((unsigned)time(0)); 
    int i;
    i = (rand()%6)+1; 
    cout << i << "\n"; 
}

работает не очень хорошо, потому что, когда я запускаю программу несколько раз, здесь вывод я получаю:

6
1
1
1
1
1
2
2
2
2
5
2

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

4b9b3361

Ответ 1

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

Весь смысл функции srand заключается в инициализации последовательности псевдослучайных чисел случайным начальным числом. Это означает, что если вы передадите одно и то же значение в srand в двух разных приложениях (с одной и той же реализацией srand/rand), вы получите одинаковую последовательность значений rand() прочитанную после этого. Но ваша псевдослучайная последовательность состоит только из одного элемента - ваши выходные данные состоят из первых элементов различных псевдослучайных последовательностей, высеянных с точностью до 1 секунды. Так что вы ожидаете увидеть? Когда вы запускаете приложение в одну и ту же секунду, ваш результат, конечно же, одинаков (как уже упоминал Мартин Йорк в комментарии к ответу).

На самом деле вы должны вызвать srand(seed) один раз, а затем вызвать rand() много раз и проанализировать эту последовательность - она должна выглядеть случайной.

Ответ 2

Использование по модулю может вносить смещение в случайные числа в зависимости от генератора случайных чисел. Смотрите этот вопрос для получения дополнительной информации. Конечно, вполне возможно получить повторяющиеся числа в случайной последовательности.

Попробуйте некоторые функции С++ 11 для лучшего распространения:

#include <random>
#include <iostream>

int main()
{
    std::random_device dev;
    std::mt19937 rng(dev());
    std::uniform_int_distribution<std::mt19937::result_type> dist6(1,6); // distribution in range [1, 6]

    std::cout << dist6(rng) << std::endl;
}

Смотрите этот вопрос/ответ для получения дополнительной информации о С++ 11 случайных чисел. Вышесказанное не единственный способ сделать это, но это один из способов.

Ответ 3

Если вы используете boost libs, вы можете получить случайный генератор таким образом:

#include <iostream>
#include <string>

// Used in randomization
#include <ctime>
#include <boost/random/mersenne_twister.hpp>
#include <boost/random/uniform_int_distribution.hpp>
#include <boost/random/variate_generator.hpp>

using namespace std;
using namespace boost;

int current_time_nanoseconds(){
    struct timespec tm;
    clock_gettime(CLOCK_REALTIME, &tm);
    return tm.tv_nsec;
}

int main (int argc, char* argv[]) {
    unsigned int dice_rolls = 12;
    random::mt19937 rng(current_time_nanoseconds());
    random::uniform_int_distribution<> six(1,6);

    for(unsigned int i=0; i<dice_rolls; i++){
        cout << six(rng) << endl;
    }
}

Если функция current_time_nanoseconds() дает текущее время в наносекундах, которое используется в качестве затравки.


Вот более общий класс для получения случайных целых чисел и дат в диапазоне:

#include <iostream>
#include <ctime>
#include <boost/random/mersenne_twister.hpp>
#include <boost/random/uniform_int_distribution.hpp>
#include <boost/random/variate_generator.hpp>
#include "boost/date_time/posix_time/posix_time.hpp"
#include "boost/date_time/gregorian/gregorian.hpp"


using namespace std;
using namespace boost;
using namespace boost::posix_time;
using namespace boost::gregorian;


class Randomizer {
private:
    static const bool debug_mode = false;
    random::mt19937 rng_;

    // The private constructor so that the user can not directly instantiate
    Randomizer() {
        if(debug_mode==true){
            this->rng_ = random::mt19937();
        }else{
            this->rng_ = random::mt19937(current_time_nanoseconds());
        }
    };

    int current_time_nanoseconds(){
        struct timespec tm;
        clock_gettime(CLOCK_REALTIME, &tm);
        return tm.tv_nsec;
    }

    // C++ 03
    // ========
    // Dont forget to declare these two. You want to make sure they
    // are unacceptable otherwise you may accidentally get copies of
    // your singleton appearing.
    Randomizer(Randomizer const&);     // Don't Implement
    void operator=(Randomizer const&); // Don't implement

public:
    static Randomizer& get_instance(){
        // The only instance of the class is created at the first call get_instance ()
        // and will be destroyed only when the program exits
        static Randomizer instance;
        return instance;
    }
    bool method() { return true; };

    int rand(unsigned int floor, unsigned int ceil){
        random::uniform_int_distribution<> rand_ = random::uniform_int_distribution<> (floor,ceil);
        return (rand_(rng_));
    }

    // Is not considering the millisecons
    time_duration rand_time_duration(){
        boost::posix_time::time_duration floor(0, 0, 0, 0);
        boost::posix_time::time_duration ceil(23, 59, 59, 0);
        unsigned int rand_seconds = rand(floor.total_seconds(), ceil.total_seconds());
        return seconds(rand_seconds);
    }


    date rand_date_from_epoch_to_now(){
        date now = second_clock::local_time().date();
        return rand_date_from_epoch_to_ceil(now);
    }

    date rand_date_from_epoch_to_ceil(date ceil_date){
        date epoch = ptime(date(1970,1,1)).date();
        return rand_date_in_interval(epoch, ceil_date);
    }

    date rand_date_in_interval(date floor_date, date ceil_date){
        return rand_ptime_in_interval(ptime(floor_date), ptime(ceil_date)).date();
    }

    ptime rand_ptime_from_epoch_to_now(){
        ptime now = second_clock::local_time();
        return rand_ptime_from_epoch_to_ceil(now);
    }

    ptime rand_ptime_from_epoch_to_ceil(ptime ceil_date){
        ptime epoch = ptime(date(1970,1,1));
        return rand_ptime_in_interval(epoch, ceil_date);
    }

    ptime rand_ptime_in_interval(ptime floor_date, ptime ceil_date){
        time_duration const diff = ceil_date - floor_date;
        long long gap_seconds = diff.total_seconds();
        long long step_seconds = Randomizer::get_instance().rand(0, gap_seconds);
        return floor_date + seconds(step_seconds);
    }
};

Ответ 4

#include <iostream>
#include <cstdlib>
#include <ctime>

int main() {
    srand(time(NULL));
    int random_number = std::rand(); // rand() return a number between ​0​ and RAND_MAX
    std::cout << random_number;
    return 0;
}

http://en.cppreference.com/w/cpp/numeric/random/rand

Ответ 5

Randomer можно получить полный Randomer класса Randomer для генерации случайных чисел!

Если вам нужны случайные числа в разных частях проекта, вы можете создать отдельный класс Randomer для Randomer всех random вещей внутри него.

Что-то вроде того:

class Randomer {
    // random seed by default
    std::mt19937 gen_;
    std::uniform_int_distribution<size_t> dist_;

public:
    /*  ... some convenient ctors ... */ 

    Randomer(size_t min, size_t max, unsigned int seed = std::random_device{}())
        : gen_{seed}, dist_{min, max} {
    }

    // if you want predictable numbers
    void SetSeed(unsigned int seed) {
        gen_.seed(seed);
    }

    size_t operator()() {
        return dist_(gen_);
    }
};

Такой класс пригодится позже:

int main() {
    Randomer randomer{0, 10};
    std::cout << randomer() << "\n";
}

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

Ответ 6

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

#include <iostream>
#include <cstdlib>
#include <ctime>
int rollDie();
using std::cout;
int main (){
    srand((unsigned)time(0));
    int die1;
    int die2;
    for (int n=10; n>0; n--){
    die1 = rollDie();
    die2 = rollDie();
    cout << die1 << " + " << die2 << " = " << die1 + die2 << "\n";
}
system("pause");
return 0;
}
int rollDie(){
    return (rand()%6)+1;
}

Ответ 7

для случайных файлов RUN

size_t randomGenerator(size_t min, size_t max) {
    std::mt19937 rng;
    rng.seed(std::random_device()());
    //rng.seed(std::chrono::high_resolution_clock::now().time_since_epoch().count());
    std::uniform_int_distribution<std::mt19937::result_type> dist(min, max);

    return dist(rng);
}

Ответ 8

Каждый раз генерируйте разные случайные числа, а не одно и то же шесть раз подряд.

Сценарий использования

Я сравнил проблему предсказуемости с пакетом из шести кусочков бумаги, на каждом из которых было написано значение от 0 до 5. Кусок бумаги вытягивается из пакета каждый раз, когда требуется новое значение. Если сумка пуста, номера возвращаются обратно в сумку.

... из этого я могу создать алгоритм сортов.

Алгоритм

Сумка - это обычно Collection. Я выбрал bool[] (также известный как логический массив, битовая плоскость или битовая карта), чтобы взять на себя роль мешка.

Причина, по которой я выбрал bool[] заключается в том, что индекс каждого элемента уже является значением каждого куска бумаги. Если бы бумаги требовали что-то еще, написанное на них, я бы использовал Dictionary<string, bool> на его месте. Логическое значение используется для отслеживания того, было ли число нарисовано или нет.

Счетчик с именем RemainingNumberCount инициализируется равным 5 который отсчитывается при выборе случайного числа. Это избавляет нас от необходимости подсчитывать, сколько листов бумаги остается каждый раз, когда мы хотим нарисовать новое число.

Чтобы выбрать следующее случайное значение, я использую for..loop для сканирования пакета индексов и счетчик для отсчета, когда index равен false называется NumberOfMoves.

NumberOfMoves используется для выбора следующего доступного номера. NumberOfMoves устанавливается на случайное значение от 0 до 5, потому что есть 0,5 шага, которые мы можем сделать через пакет. На следующей итерации NumberOfMoves устанавливается в случайное значение от 0 до 4, потому что теперь мы можем сделать 0..4 шага через пакет. Поскольку числа используются, доступные числа уменьшаются, поэтому мы вместо этого используем rand() % (RemainingNumberCount + 1) чтобы вычислить следующее значение для NumberOfMoves.

Когда счетчик NumberOfMoves достигает нуля, for..loop должен for..loop следующим образом:

  1. Установите текущее значение for..loop индексу for..loop.
  2. Установите все числа в сумке на false.
  3. Перерыв из-за for..loop.

Код

Код для вышеуказанного решения выглядит следующим образом:

(поместите следующие три блока в основной файл .cpp один за другим)

#include "stdafx.h"
#include <ctime> 
#include <iostream>
#include <string>

class RandomBag {
public:
    int Value = -1;

    RandomBag() {
        ResetBag();

    }

    void NextValue() {
        int BagOfNumbersLength = sizeof(BagOfNumbers) / sizeof(*BagOfNumbers);

        int NumberOfMoves = rand() % (RemainingNumberCount + 1);

        for (int i = 0; i < BagOfNumbersLength; i++)            
            if (BagOfNumbers[i] == 0) {
                NumberOfMoves--;

                if (NumberOfMoves == -1)
                {
                    Value = i;

                    BagOfNumbers[i] = 1;

                    break;

                }

            }



        if (RemainingNumberCount == 0) {
            RemainingNumberCount = 5;

            ResetBag();

        }
        else            
            RemainingNumberCount--; 

    }

    std::string ToString() {
        return std::to_string(Value);

    }

private:
    bool BagOfNumbers[6]; 

    int RemainingNumberCount;

    int NumberOfMoves;

    void ResetBag() {
        RemainingNumberCount = 5;

        NumberOfMoves = rand() % 6;

        int BagOfNumbersLength = sizeof(BagOfNumbers) / sizeof(*BagOfNumbers);

        for (int i = 0; i < BagOfNumbersLength; i++)            
            BagOfNumbers[i] = 0;

    }

};

Консольный класс

Я создаю этот класс Console, потому что он облегчает перенаправление вывода.

Ниже в коде...

Console::WriteLine("The next value is " + randomBag.ToString());

... можно заменить на...

std::cout << "The next value is " + randomBag.ToString() << std::endl; 

... и затем этот класс Console может быть удален при желании.

class Console {
public:
    static void WriteLine(std::string s) {
        std::cout << s << std::endl;

    }

};

Основной метод

Пример использования следующим образом:

int main() {
    srand((unsigned)time(0)); // Initialise random seed based on current time

    RandomBag randomBag;

    Console::WriteLine("First set of six...\n");

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    Console::WriteLine("\nSecond set of six...\n");

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    Console::WriteLine("\nThird set of six...\n");

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    randomBag.NextValue();

    Console::WriteLine("The next value is " + randomBag.ToString());

    Console::WriteLine("\nProcess complete.\n");

    system("pause");

}

Пример вывода

Когда я запустил программу, я получил следующий вывод:

First set of six...

The next value is 2
The next value is 3
The next value is 4
The next value is 5
The next value is 0
The next value is 1

Second set of six...

The next value is 3
The next value is 4
The next value is 2
The next value is 0
The next value is 1
The next value is 5

Third set of six...

The next value is 4
The next value is 5
The next value is 2
The next value is 0
The next value is 3
The next value is 1

Process complete.

Press any key to continue . . .

Заключительное выражение

Эта программа была написана с использованием Visual Studio 2017, и я решил сделать ее Visual C++ Windows Console Application с использованием .Net 4.6.1.

Я не делаю здесь ничего особенного, поэтому код должен работать и в более ранних версиях Visual Studio.

Ответ 9

Этот код генерирует случайные числа от n до m.

int random(int from, int to){
    return rand() % (to - from + 1) + from;
}

пример:

int main(){
    srand(time(0));
    cout << random(0, 99) << "\n";
}

Ответ 10

Вот простой генератор случайных чисел с ок. равная вероятность получения положительных и отрицательных значений около 0:

  int getNextRandom(const size_t lim) 
  {
        int nextRand = rand() % lim;
        int nextSign = rand() % lim;
        if (nextSign < lim / 2)
            return -nextRand;
        return nextRand;
  }


   int main()
   {
        srand(time(NULL));
        int r = getNextRandom(100);
        cout << r << endl;
        return 0;
   }