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

我想用骰子做一个游戏,我需要随机数字(模拟死亡的边缘,我知道如何在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次。 有没有这样的命令?

你的testing应用程序的最基本的问题是你调用srand一次,然后一次调用rand并退出。

srand函数的全部要点是用随机种子初始化伪随机数的序列。 这意味着,如果你在两个不同的应用程序(使用相同的srand / rand实现)将相同的值传递给srand ,那么将会得到完全相同的rand()值序列。 但是,您的伪随机序列只包含一个元素 – 您的输出包含不同的伪随机序列的第一个元素,接种时间为1秒精度。 那么你期望看到什么? 当你碰巧在同一秒钟运行应用程序时,结果当然是一样的(就像Loki Astari在回答的评论中已经提到的那样)。

其实你应该一次调用srand(seed) ,然后多次调用rand()并分析这个序列 – 它应该看起来是随机的。

根据随机数发生器,使用模可以将偏差引入随机数。 看到这个问题的更多信息。 当然,以随机顺序获得重复的数字是完全可能的。

尝试一些C + + 11function更好地分配:

 #include <random> #include <iostream> int main() { std::mt19937 rng; rng.seed(std::random_device()()); std::uniform_int_distribution<std::mt19937::result_type> dist6(1,6); // distribution in range [1, 6] std::cout << dist6(rng) << std::endl; } 

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

如果你使用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; } } 

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


这是一个更一般的类来获得在一个范围内的随机整数和date:

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

这是一个解决scheme。 创build一个返回随机数的函数,并将其放在主函数之外以使其成为全局函数。 希望这可以帮助

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

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

可预测性提出了问题…

我想要一个每次都会产生一个不同的随机数的命令,而不是连续的5次。 有没有这样的命令?

…答案是,“当然,这是我提出来的。”

在开始编码之前,我想象一下真实世界的场景。

用例场景

我把可预见性的问题比作一包六位纸,每一个都写有0到5的值。 每次需要新的值时,从包中抽出一张纸。 如果袋子是空的,那么这些数字就会被放回袋子里。

…从这个,我可以创build一个sortingalgorithm。

algorithm

一个包通常是一个Collection 。 我select了bool[] (或者称为布尔数组,位平面或位图)来扮演这个angular色。

我selectbool[]的原因是每个项目的索引已经是每张纸的值,我可以使用布尔值来跟踪数字是否已经被绘制。

一个名为RemainingNumberCount的计数器被初始化为5 ,随着一个随机数被select而倒数。 这使我们不必计算每次我们想要画一个新号码时剩下多less张纸。

要select下一个随机值,我使用for..loop来扫描索引包,并且在indexfalse的情况下计数器计数,称为NumberOfMoves

NumberOfMoves用于select下一个可用的号码。 NumberOfMoves首先被设置为一个介于05之间的随机值,因为我们可以通过包进行0..5个可用步骤。 在下一次迭代中, NumberOfMoves被设置为04之间的随机值,因为现在我们可以通过包进行0..4个步骤。 在使用数字时,可用数字会减less,所以我们使用rand() % (RemainingNumberCount + 1)来计算NumberOfMoves的下一个值。

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

  1. 将当前值设置为与for..loop的索引相同。
  2. 将袋中的所有数字设置为false
  3. 从… for..loop

上述解决scheme的代码如下所示:

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

一个控制台类

我创build这个控制台类,因为它可以很容易地redirect输出。

在代码下面…

 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编写的,我select使用.Net 4.6.1作为Visual C++ Windows Console Application项目。

我在这里没有做任何特别的事情,所以代码也可以在早期版本的Visual Studio上工作。