如何在 C++ 中生成随机数?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13445688/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 17:20:11  来源:igfitidea点击:

How to generate a random number in C++?

c++random

提问by Predictability

I'm trying to make a game with dice, and I need to have random numbers in it (to simulate the sides of the die. I know how to make it between 1 and 6). Using

我正在尝试用骰子制作游戏,我需要在其中包含随机数(以模拟骰子的侧面。我知道如何在 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"; 
}

doesn't work very well, because when I run the program a few times, here's the output I get:

不能很好地工作,因为当我运行程序几次时,这是我得到的输出:

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

So I want a command that will generate a differentrandom number each time, not the same one 5 times in a row. Is there a command that will do this?

所以我想要一个命令,每次都会生成不同的随机数,而不是连续 5 次相同。有没有一个命令可以做到这一点?

采纳答案by Serge Dundich

The most fundamental problem of your test application is that you call srandonce and then call randone time and exit.

您的测试应用程序的最根本问题是您调用srand一次然后调用rand一次并退出。

The whole point of srandfunction is to initialize the sequence of pseudo-random numberswith a random seed.

srand函数的全部意义在于用随机种子初始化伪随机数序列

It means that if you pass the same valueto srandin two different applications (with the same srand/randimplementation) then you will get exactly the same sequenceof rand()values read after that in both applications.

这意味着,如果传递相同的值,以srand在两个不同的应用程序(使用相同srand/rand执行),那么你会得到完全相同的序列rand()后,在这两个应用程序读取值。

But in your application pseudo-random sequence consists only of one element - so your output is the first element of a pseudo-random sequence generated from seed which is current time of one second precision. What do you expect to see on output then?

但是在您的应用程序中,伪随机序列仅由一个元素组成 - 因此您的输出是从种子生成的伪随机序列的第一个元素,这是一秒精度的当前时间。那么你希望在输出上看到什么?

Obviously when you happen to run application on the same second - you use the same seed value - thus your result is the same of course (as Martin York already mentioned in a comment to the answer).

显然,当您碰巧在同一秒运行应用程序时 - 您使用相同的种子值 - 因此您的结果当然是相同的(正如 Martin York 在对答案的评论中已经提到的那样)。

Actually you should call srand(seed)one time and then call rand()many timesand analyze that sequence - it should look random.

实际上,您应该调用srand(seed)一次,然后调用rand()多次并分析该序列 - 它应该看起来是随机的。

EDIT:

编辑:

Oh I get it. Verbal description is not enough for people with language barrier (or semantic recognition barrier :) ).

哦,我明白了。对于有语言障碍(或语义识别障碍:))的人来说,口头描述是不够的。

OK. C code sample to illustrate:

好的。C代码示例来说明:

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

int main(void)
{
    unsigned long j;
    srand( (unsigned)time(NULL) );

    for( j = 0; j < 100500; ++j )
    {
        printf( "%d,\t%d\n", rand(), rand() % 6 + 1 );
    }

    return 0;
}

^^^ THATsequence should be random.

^^^ THAT顺序应该是随机的。

回答by Cornstalks

Using modulo may introduce bias into the random numbers, depending on the random number generator. See this question for more info.Of course, it's perfectly possible to get repeating numbers in a random sequence.

使用取模可能会在随机数中引入偏差,具体取决于随机数生成器。有关更多信息,请参阅此问题。当然,以随机序列获得重复数字是完全可能的。

Try some C++11 features for better distribution:

尝试一些 C++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;
}

See this question/answer for more info on C++11 random numbers.The above isn't the only way to do this, but is one way.

有关 C++11 随机数的更多信息,请参阅此问题/答案。以上不是做到这一点的唯一方法,而是一种方法。

回答by madx

If you are using boostlibs you can obtain a random generator in this way:

如果您使用的是boost库,您可以通过这种方式获得一个随机生成器:

#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;
    }
}

Where the function current_time_nanoseconds()gives the current time in nanoseconds which is used as a seed.

该函数current_time_nanoseconds()以纳秒为单位给出当前时间,用作种子。



Here is a more general class to get random integers and dates in a range:

这是一个更通用的类,用于获取范围内的随机整数和日期:

#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);
    }
};

回答by Arley

#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

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

回答by Gusev Slava

Can get full Randomerclass code for generating random numbers from here!

可以Randomer从这里获取生成随机数的完整类代码!

If you need random numbers in different parts of the project you can create a separate class Randomerto incapsulate all the randomstuff inside it.

如果您需要在项目的不同部分使用随机数,您可以创建一个单独的类Randomer来封装其中的所有random内容。

Something like that:

类似的东西:

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_);
    }
};

Such a class would be handy later on:

这样的类稍后会很方便:

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

You can check this link as an example how i usesuch Randomerclass to generate random strings. You can also use Randomerif you wish.

您可以查看此链接作为我如何使用此类Randomer生成随机字符串的示例Randomer如果您愿意,您也可以使用。

回答by Amir Fo

This code produces random numbers from nto m.

此代码生成从n到 的随机数m

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

example:

例子:

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

回答by WonderWorker

Generate a different random number each time, not the same one six times in a row.

每次生成不同的随机数,连续六次不相同。

Use case scenario

用例场景

I likened Predictability's problem to a bag of six bits of paper, each with a value from 0 to 5 written on it. A piece of paper is drawn from the bag each time a new value is required. If the bag is empty, then the numbers are put back into the bag.

我将可预测性的问题比作一袋六张纸,每张纸上都写着 0 到 5 的值。每次需要一个新值时,都会从袋子里抽出一张纸。如果袋子是空的,则将数字放回袋子中。

...from this, I can create an algorithm of sorts.

...由此,我可以创建各种算法。

Algorithm

算法

A bag is usually a Collection. I chose a bool[](otherwise known as a boolean array, bit plane or bit map) to take the role of the bag.

一个包通常是一个Collection。我选择了一个bool[](也称为布尔数组、位平面或位图)来充当包的角色。

The reason I chose a bool[]is because the index of each item is already the value of each piece of paper. If the papers required anything else written on them then I would have used a Dictionary<string, bool>in its place. The boolean value is used to keep track of whether the number has been drawn yet or not.

我之所以选择a,bool[]是因为每一项的索引已经是每张纸的价值了。如果这些文件需要在上面写任何其他东西,那么我会用 aDictionary<string, bool>代替它。布尔值用于跟踪数字是否已被绘制。

A counter called RemainingNumberCountis initialised to 5that counts down as a random number is chosen. This saves us from having to count how many pieces of paper are left each time we wish to draw a new number.

一个被调用的计数器RemainingNumberCount被初始化5为在选择一个随机数时倒计时。这使我们不必在每次想画一个新数字时计算还剩多少张纸。

To select the next random value I'm using a for..loopto scan through the bag of indexes, and a counter to count off when an indexis falsecalled NumberOfMoves.

为了选择下一个随机值,我使用 afor..loop来扫描索引包,并使用一个计数器在 anindexfalse调用时进行计数NumberOfMoves

NumberOfMovesis used to choose the next available number. NumberOfMovesis first set to be a random value between 0and 5, because there are 0..5 available steps we can make through the bag. On the next iteration NumberOfMovesis set to be a random value between 0and 4, because there are now 0..4 steps we can make through the bag. As the numbers are used, the available numbers reduce so we instead use rand() % (RemainingNumberCount + 1)to calculate the next value for NumberOfMoves.

NumberOfMoves用于选择下一个可用号码。NumberOfMoves首先设置为0和之间的随机值5,因为我们可以通过袋子进行 0..5 个可用步骤。在下一次迭代NumberOfMoves中设置为0和之间的随机值4,因为现在我们可以通过袋子进行 0..4 步。随着数字的使用,可用数字减少,因此我们改为使用rand() % (RemainingNumberCount + 1)来计算 的下一个值NumberOfMoves

When the NumberOfMovescounter reaches zero, the for..loopshould as follows:

NumberOfMoves计数器达到零时,for..loop应该如下:

  1. Set the current Value to be the same as for..loop's index.
  2. Set all the numbers in the bag to false.
  3. Break from the for..loop.
  1. 将当前值设置为for..loop与 的索引相同。
  2. 将袋子中的所有数字设置为false
  3. for..loop.

Code

代码

The code for the above solution is as follows:

上述解决方案的代码如下:

(put the following three blocks into the main .cpp file one after the other)

(将以下三个块依次放入主.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;

    }

};

A Console class

控制台类

I create this Console class because it makes it easy to redirect output.

我创建这个 Console 类是因为它可以很容易地重定向输出。

Below in the code...

在代码下面...

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

...can be replaced by...

……可以换成……

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

...and then this Consoleclass can be deleted if desired.

...然后Console可以根据需要删除此类。

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

    }

};

Main method

主要方法

Example usage as follows:

示例用法如下:

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");

}

Example output

示例输出

When I ran the program, I got the following output:

当我运行程序时,我得到以下输出:

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 . . .

Closing statement

闭幕词

This program was written using Visual Studio 2017, and I chose to make it a Visual C++ Windows Console Applicationproject using .Net 4.6.1.

该程序是使用Visual Studio 2017编写的,我选择Visual C++ Windows Console Application使用.Net 4.6.1.

I'm not doing anything particularly special here, so the code should work on earlier versions of Visual Studio too.

我在这里没有做任何特别的事情,所以代码也应该适用于早期版本的 Visual Studio。

回答by Nehigienix

for random every RUN file

随机每个 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);
}

回答by HDSSNET

Here is a solution. Create a function that returns the random number and place it outside the main function to make it global. Hope this helps

这是一个解决方案。创建一个返回随机数的函数,并将其放在 main 函数之外以使其成为全局变量。希望这可以帮助

#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;
}

回答by Andrushenko Alexander

Here is a simple random generator with approx. equal probability of generating positive and negative values around 0:

这是一个简单的随机生成器,大约有。在 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;
   }