调用随机数生成成员函数不会产生完全随机数
Calling a random number generating member function doesn't produce entirely random numbers
我正在使用 C++ 创建一个 wxWidget 应用程序,在程序开始时我希望应用程序 window 包含具有随机颜色的像素,如下所示:
在上面的应用程序中有 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 的 table 来做到这一点,这个函数将填充颜色的值。
然而这种方式不是我想要的。我想要的是创建一个名为 somNode
的 class,其中每个 somNode
-对象代表图片中的一个像素(RGB 值作为成员数组属性)。在这个 somNode
-class 中,我有一个成员函数使用 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 somNode
s 的 3600 像素),我使用以下代码(查看 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<somNode> somGrid
,当我构建它们时,我将所有这些 3600 somNode
推入其中。当构建每个节点时,调用 somNode
成员函数 rand_node_colour
来创建 RGB 值。
然而,当我实现这个代码而不是我最初使用的代码时,我得到了这个结果:
你可以看到有一个清晰的模式,所以这里出了点问题。我的问题是:创建 somNodes 时随机数生成发生了什么?为什么它不会产生与我上面使用的代码相同的结果?
P.S。这是 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);
}
}
这里的问题是您不断地在 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);
}
}
我正在使用 C++ 创建一个 wxWidget 应用程序,在程序开始时我希望应用程序 window 包含具有随机颜色的像素,如下所示:
在上面的应用程序中有 3600 个像素 (60 x 60),我使用 uniform_int_distribution
上图中像素的颜色是在我的代码中使用以下函数生成的:
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 的 table 来做到这一点,这个函数将填充颜色的值。
然而这种方式不是我想要的。我想要的是创建一个名为 somNode
的 class,其中每个 somNode
-对象代表图片中的一个像素(RGB 值作为成员数组属性)。在这个 somNode
-class 中,我有一个成员函数使用 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 somNode
s 的 3600 像素),我使用以下代码(查看 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<somNode> somGrid
,当我构建它们时,我将所有这些 3600 somNode
推入其中。当构建每个节点时,调用 somNode
成员函数 rand_node_colour
来创建 RGB 值。
然而,当我实现这个代码而不是我最初使用的代码时,我得到了这个结果:
你可以看到有一个清晰的模式,所以这里出了点问题。我的问题是:创建 somNodes 时随机数生成发生了什么?为什么它不会产生与我上面使用的代码相同的结果?
P.S。这是 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);
}
}
这里的问题是您不断地在 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);
}
}