【问题标题】:Calling a random number generating member function doesn't produce entirely random numbers调用随机数生成成员函数不会产生完全随机数
【发布时间】:2026-02-25 11:05:01
【问题描述】:

我正在使用 C++ 创建一个 wxWidget 应用程序,在程序开始时我希望应用程序窗口包含具有随机颜色的像素,如下所示:

在上面的应用程序中有 3600 个像素 (60 x 60),我使用 uniform_int_distribution 为每个像素分配了随机的 RGB 颜色

上图中像素的颜色是在我的代码中使用以下函数生成的:

void random_colors(int ctable[][3], int n)
{
  // construct a trivial random generator engine from a time-based seed:
  unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
  std::default_random_engine generator (seed);
  std::uniform_int_distribution<int> distribution(0,255);
  for(int i=0; i<n; i++)
  {
      for(int j=0; j<3; j++)
      {
        ctable[i][j] = distribution(generator);
      }
  }
}

我通过给这个函数一个尺寸为 3600 x 3 的表格来做到这一点,这个函数将填充颜色的值。

然而,这种方式不是我想要的。我想要的是创建一个名为somNode 的类,其中每个somNode-object 代表图片中的一个像素(RGB 值作为成员数组属性)。在这个somNode 类中,我有一个成员函数,使用uniform_int_distribution 在构造每个somNode 时给出它自己的随机RGB 颜色。这是为每个somNode 创建随机颜色的函数:

void rand_node_colour(int nodeWeights[])
{
  // construct a trivial random generator engine from a time-based seed:
  unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
  std::default_random_engine generator (seed);
  std::uniform_int_distribution<int> distribution(0,255);
  for(int i=0; i<3; i++)
  {
    nodeWeights[i] = distribution(generator);
  }
}

nodeWeights 成员数组表示somNode 的 RGB 值。现在,当我创建上图中的“som-grid”时(3600 像素对应于 3600 somNodes),我使用以下代码(查看 som-constructor):

#include "somNode.h"
#include <vector>

class som
{
    public:
        double learning_rate;
        std::vector<somNode> somGrid;
    public:
        som(double lrate);
        void epoch();
        void trainOnce();

};

/*
* Initialize the som grid
*/
som::som(double lrate)
{
    learning_rate = lrate;
    // Create the som grid
    for(int i=0; i<60; i++)
    {
        for(int j=0; j<60; j++)
        {
            int xL = j*10;
            int xR = (j+1)*10;
            int yT = i*10;
            int yB = (i+1)*10;
            somGrid.push_back(somNode(xL, xR, yB, yT));
        }
    }
}

// Train som by one epoch
void som::epoch()
{

}

// Train som by one color
void som::trainOnce()
{

}

所以我有一个vector&lt;somNode&gt; somGrid,当我构造它们时,我会在其中推送所有这些 3600 个somNodes。当每个节点被构造时,somNode 成员函数 rand_node_colour 被调用,它创建了 RGB 值。

然而,当我实现这个代码而不是我一开始使用的代码时,我得到了这个结果:

您可以看到有一个清晰的模式,所以这里出了点问题。我的问题是:创建 somNodes 时随机数生成中发生了什么?为什么它不会产生与我上面使用的代码相同的结果?

附:这是somNode.cpp

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

void rand_node_colour(int nodeWeights[]);

/*
* This class represent a node in the som-grid
*/
class somNode
{
    public:
        // Weight of the node representing the color
        int nodeWeights[3];
        // Position in the grid
        double X, Y;
        // corner coorinates for drawing the node on the grid
        int x_Left, x_Right, y_Bottom, y_Top;

    public:
        // Constructor
        somNode(int xL, int xR, int yB, int yT);
        void editWeights(int r, int g, int b);
        double getDistance(int r, int g, int b);
};


somNode::somNode(int xL, int xR, int yB, int yT)
{
    // Set the corner points
    x_Left = xL;
    x_Right = xR;
    y_Bottom = yB;
    y_Top = yT;
    // Initialize random weights for node
    rand_node_colour(nodeWeights);
    // Calculate the node's position (center coordinate)
    X = x_Left + (double)((x_Right - x_Left)/double(2));
    Y = y_Bottom + (double)((y_Top - y_Bottom)/double(2));
}

void somNode::editWeights(int r, int g, int b)
{
    nodeWeights[0] = r;
    nodeWeights[1] = g;
    nodeWeights[2] = b;
}

double somNode::getDistance(int r, int g, int b)
{
    return sqrt(pow(nodeWeights[0]-r, 2) + pow(nodeWeights[1]-g, 2) + pow(nodeWeights[2]-b, 2));
}


void rand_node_colour(int nodeWeights[])
{
  // construct a trivial random generator engine from a time-based seed:
  unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
  std::default_random_engine generator (seed);
  std::uniform_int_distribution<int> distribution(0,255);
  for(int i=0; i<3; i++)
  {
    nodeWeights[i] = distribution(generator);
  }
}

【问题讨论】:

  • 您是否多次致电random_colorsrand_node_colour?如果你这样做很快,那么多个调用可能会使用相同的种子值。
  • 嗨@JoachimPileborg 是的,每次构造somNode 时,我都会调用rand_node_colour。看看somNode 构造函数。我的想法是在每个构造中为节点创建随机颜色。我明白了……我该如何解决这个问题? :)
  • 种子生成。施工时只使用一次,最好使用std::random_device。看一个简单的例子here
  • 只创建一个生成器和一个分发对象,并且一直使用相同的。例如,将它们(和种子)声明为 static 变量。
  • 知道了 :) 我会尝试static 方法。谢谢你:)

标签: c++ random wxwidgets


【解决方案1】:

这里的问题是您不断地在rand_node_colour 中重新创建和播种随机数生成器。你在一个紧密的循环中调用它,这样你就可以获得相同的时间,这意味着种子将是相同的,这意味着生成的随机数将是相同的。

您需要做的是给生成器播种一次,然后继续使用它的随机输出。修复代码的一种简单方法是在函数中将其设为static,因此它只初始化一次,并且对该函数的每次后续调用都将继续进行,而不是重新启动生成器。如果我们这样做,代码就变成了

void rand_node_colour(int nodeWeights[])
{
  // construct a trivial random generator engine from a time-based seed:
  static std::default_random_engine generator (std::chrono::system_clock::now().time_since_epoch().count());
  std::uniform_int_distribution<int> distribution(0,255);
  for(int i=0; i<3; i++)
  {
    nodeWeights[i] = distribution(generator);
  }
}

【讨论】:

  • 太棒了!做到了。现在我也明白为什么了。谢谢=)
  • @jjepsuomi 没问题。很高兴能提供帮助。
  • 另外,我必须注意default_random_engine 将在不同平台上为不同的生成器起别名,并且很可能是像 LCG 这样的低级生成器。最好明确说明使用具体生成器的意图。