【问题标题】:Random numbers in a constructor of an object array对象数组的构造函数中的随机数
【发布时间】:2020-07-07 16:16:42
【问题描述】:

首先,对不起,如果这是一个愚蠢的问题,但我最近学习了如何处理课程。 我的问题是我创建了一个构造函数,它给每个数据成员一个随机数,语法如下:

#include <random>

...

//Constructor
cSystem::cSystem(void)
{
//Range of random numbers
double lower_bound = -100;
double upper_bound = 100;
std::uniform_real_distribution<double> unif(lower_bound,upper_bound);
std::default_random_engine re;

/*Initialization of data members*/
sMass=1.0014;
sPositionX= unif(re);
sPositionY= unif(re);
}

但是,我想在我的主函数中创建一个由这些“系统”组成的数组

int main (void)
{
cSystem systems[numsist]; //numsist is a constant defined to be 1000

//Function that writes its characteristics in a file using a method that returns positions
getPositions(systems);

return 0;
}

但在文件中,我得到了

-73.6924    -8.26997
-73.6924    -8.26997
-73.6924    -8.26997

我以为我正在遍历数组的每个元素的构造函数,给它一个不同的随机值,但似乎在开始时给出了一个值,然后在整个向量中重复。 我该怎么做才能获得一个以随机方式初始化每个元素的构造函数?

注意:我每次运行程序时也得到相同的值,我想种子没有改变,为什么会这样?

【问题讨论】:

  • 但是您在构造函数中创建了一个新的 RNG。这将产生相同系列的随机数。为什么不使用全局 RNG 单例?
  • 或者只是让reunifstatic班级成员?

标签: c++ arrays class random constructor


【解决方案1】:

我的问题是我创建了一个构造函数,它给每个数据成员一个随机数

  • 当您将 PRNG 设为默认构造时,您并未播种它。每次都会以默认状态开始。
  • PRNG 不应归任何one 类所有。播种它的成本很高,并且它应该由需要生成随机数的所有函数(每个线程)共享 - 所以将它与任何类分开。

我更喜欢选择某个 PRNG,但默认情况下,它可能如下所示:

std::default_random_engine& prng() {
    // seed only one PRNG per thread that needs is:
    static thread_local std::default_random_engine gen(std::random_device{}());
    return gen;
}

在您在程序中使用的每个分布函数(成员函数或其他函数)中,您现在可以调用prng() 来获取生成器,播种一次 而不是过度播种

【讨论】:

  • 它解决了整个数组的编号相同的问题,我非常感谢。但是,种子似乎没有改变(正如我在问题的“注释”部分中提到的那样),因为每次运行程序时我都会得到相同的值。这个程序是一个星系的模拟,因此,我希望在每次运行中都有不同的太阳系随机初始位置。我不知道如何很好地使用 ,但也许我可以使用 srand(time(NULL)) 并将其插入 使用的种子中,或者可能有一个不那么复杂的解决方案。
  • @A.D.EscañuelaCopado 如果种子没有改变(你可以通过打印来测试它),你可能需要自己添加熵。这是一个半心半意的版本:portable seeding if buggy random_devices are taken into account。第二个注释中的第三个项目符号适用于您的案例。
  • ...不,我建议您不要使用srand(time(NULL))。使用&lt;random&gt;,您走在正确的轨道上。各方面都比较好。
  • @A.D.EscañuelaCopado 您实际上并没有在我的回答中测试示例prng(),是吗?我刚刚注意到您对另一个答案发表了同样的评论,该答案根本不包含任何种子,而我的却是。
  • 我在 Windows 10 中使用 CodeBlocks 作为我的 IDE,并且我已经实现了 C++17,但我可能没有正确完成,这就是 std::size 不起作用的原因。我曾经使用 Linux 命令行,但我的电脑坏了,所以这是目前唯一可用的东西。关于prng()()cout,我得到一个不同值的字符串,但是每次运行时字符串都是一样的。我很高兴地告诉您,使用 (sizeof(si)/sizeof(*si))std::extent&lt;decltype(si)&gt;::value 可以使它工作:D。 谢谢你一千次
【解决方案2】:

对于cSystem 的每个实例,您将获得相同的sPositionXsPositionY 值,因为每次调用构造函数时您都在创建std::uniform_real_distribution&lt;double&gt;std::default_random_engine

您需要创建一次并在构造函数中重用它们。一种方法是创建类范围 static 对象。

struct cSystem
{
   ...

   static std::uniform_real_distribution<double> unif;
   static std::default_random_engine re;
};

只需在构造函数中使用它们。

这是一个完整的程序。

#include <random>
#include <iostream>

struct cSystem
{
   cSystem();

   double sPositionX;
   double sPositionY;
   double sMass;

   static std::uniform_real_distribution<double> unif;
   static std::default_random_engine re;
};

std::uniform_real_distribution<double> cSystem::unif(-100, 100);
std::default_random_engine cSystem::re;

//Constructor
cSystem::cSystem()
{
   /*Initialization of data members*/
   sMass=1.0014;
   sPositionX= unif(re);
   sPositionY= unif(re);
}

void getPositions(cSystem* systems)
{
   for (unsigned i = 0; i < 3; ++i )
   {
      std::cout << systems[i].sPositionX << " " << systems[i].sPositionY << std::endl;
   }
}

int main (void)
{
   cSystem systems[3];

   getPositions(systems);

   return 0;
}

https://ideone.com/bS8E4u查看它。

更新,以回应 OP 的评论。

您可以如下初始化re,以便在程序反复运行时得到不同的随机数。

std::default_random_engine cSystem::re{std::random_device()()};

【讨论】:

  • 它解决了整个数组中编号相同的问题,我非常感谢。但是,种子似乎没有改变(正如我在问题的“注释”部分中提到的那样),因为每次运行程序时我都会得到相同的值。这个程序是一个星系的模拟,因此,我希望在每次运行中都有不同的太阳系随机初始位置。我不知道如何很好地使用 ,但也许我可以使用 srand(time(NULL)) 并将其插入 使用的种子中,或者可能有一个不那么复杂的解决方案。
猜你喜欢
  • 2016-07-17
  • 1970-01-01
  • 2010-09-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-19
  • 2018-06-26
相关资源
最近更新 更多