【问题标题】:How to make a member function of a class in C++ generate a different random number each time it is called?如何使C++中类的成员函数每次调用时生成不同的随机数?
【发布时间】:2015-08-16 05:43:09
【问题描述】:

我有一个类,其中还包括一个随机数引擎及其分布:

#include <iostream>
#include <cmath>
#include <random>
#include <chrono>

class C
{ 
  public:
      typedef std::mt19937_64 engine;
      typedef std::uniform_real_distribution<double> distribution;
      .
      .
      .

  protected:
      engine rng;
      distribution dist;
      void func();
      .
      .
      .
};

由于构造函数只被调用一次,所以我将种子放入其中:

C::C()
{   .
    .
    .  
    unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
    distribution dist(0.0, pow(10,12));
    engine rng(seed);
}

下面的成员函数应该生成一个随机数,并且会在程序的一次运行中被调用很多次:

void C::func()
{    .
     .
     .
     double randNum = floor(dist(rng));
     std::cout << randNum << std::endl;      
     .
     .
     .
}

但是,它每次都会生成数字 0 作为随机数。 dist(rng) 似乎没有做好它的工作。

我真的需要找到问题并纠正输出。我将不胜感激。

【问题讨论】:

  • 您为构造函数显示的代码似乎正在创建隐藏类成员的 local 变量(即您初始化 local variables 而不是 成员稍后使用)。不要这样做。
  • 基本上,从你的构造函数中删除“distribution”和“engine”,同时保留变量名并将它们放在初始化列表中
  • @KABoissonneault 不,这不会编译。这些东西必须在初始化列表中。
  • @SebastianRedl 哎呀,现在我忘了说如果你需要变量种子,你必须做一个赋值

标签: c++ class random constructor member-functions


【解决方案1】:

您在类中定义 disteng 变量

protected:
  engine rng;
  distribution dist; // Here
  void func();

在构造函数中定义另一个同名

C::C()
{   .
    .
    .  
    unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
    distribution dist(0.0, pow(10,12)); // Here
    engine rng(seed);
}

我假设您希望后者是一个赋值,而不是一个新变量。然后你会得到你想要的数字。

C::C()
{   .
    .
    .  
    unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
    dist = distribution(0.0, pow(10,12)); // Here
    rng = engine(seed);
}

或者用初始化

C() : dist(0.0, pow(10, 12)),
  rng(std::chrono::system_clock::now().time_since_epoch().count())

【讨论】:

  • 你为什么要复制分配这些?为什么不初始化?!
  • @LightnessRacesinOrbit 如果它们是常量,当然你也可以。生成的代码很可能是相同的,在我看来,这只是更清晰,更接近 OP 使用的方式。也加了
  • 我发现它不太清楚,最浪费和误导。这是一个“为什么要竭尽全力做错事”的案例。养成“除非你不能初始化”的习惯是一种更好的生活方式。 :)
  • 谢谢@SamiKuhmonen!有效。但我不明白一件事。 engine 是一个类型,rng 是一个对象。为什么我不能在构造函数中写rng(seed) 而不是rng = engine(seed)?这个engine在后者对我来说看起来很奇怪。
  • 编译器会将rng(seed)视为函数调用,而不是构造,因此不被接受。在初始化中,它被理解为构造对象,就像从engine(seed) 分配一样。在赋值中创建了一个新对象,然后将其赋值给变量,这就是为什么应该使用初始化方法的原因。 (如果我的术语有点不对,欢迎 C++ 大师更正)
【解决方案2】:

在构造函数中,您正在创建一个隐藏类成员的局部变量dist,而类成员被默认初始化。默认初始化的 uniform_real_distribution 生成范围 [0,1) 中的值,floor 将始终变为 0。

【讨论】:

  • 故事就是这样...谢谢! :)
【解决方案3】:

Sami 很接近,但你真的应该初始化这些成员:

C::C()
  : dist(0.0, pow(10, 12))
  , rng(std::chrono::system_clock::now().time_since_epoch().count())
{}

【讨论】:

    猜你喜欢
    • 2017-09-11
    • 2016-10-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多