2016-06-08 22 views
7

Sto creando un'applicazione wxWidget con C++, dove all'inizio del programma che voglio la finestra dell'applicazione per contenere pixel con colori casuali come questo:Chiamare una funzione membro numero casuale generando non produce numeri del tutto casuali

Random coloured pixels

Nell'applicazione sopra ci sono 3600 pixel (60 x 60) e che hanno dato ogni pixel di un colore RGB casuale utilizzando uniform_int_distribution

i colori dei pixel nell'immagine sopra sono generati al momento utilizzando la seguente funzione nel mio codice:

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

Lo faccio dando a questa funzione una tabella con dimensioni 3600 x 3 e questa funzione inserirà i valori per i colori.

In questo modo, tuttavia, non è quello che voglio. Quello che voglio è creare una classe chiamata somNode dove ogni oggetto somNode rappresenta un pixel nell'immagine (con valori RGB come attributo matrice membro). In questa classe somNode ho una funzione membro che usa uniform_int_distribution per dare quando viene costruito ogni somNode proprio colore RGB casuale. Questa è la funzione che crea il colore casuale per ogni 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); 
    } 
} 

matrice membro rappresenta il RGB valore del somNode. Ora, quando ho creare questa immagine "som-grid" quello che ho nell'immagine sopra (i 3600 pixel corrispondenti a 3600 somNode s) Io uso il seguente codice (date un'occhiata alla SOM-costruttore):

#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() 
{ 

} 

Quindi ho uno vector<somNode> somGrid dove spingo tutti questi 3600 somNode quando li costruisco. Quando viene creato ciascun nodo, viene chiamata la funzione membro che crea il valore RGB.

Quando però a implementare questo codice al posto di quello che ho usato in un primo momento ho ottenere questo risultato:

enter image description here

Si può vedere che c'è un modello chiaro in modo da qualcosa sta andando male qui. La mia domanda è: cosa sta succedendo nella generazione di numeri casuali quando vengono creati i somNodes? Perché non produce lo stesso risultato del codice che ho usato sopra?

P.S. qui è la 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); 
    } 
} 
+0

Chiama 'random_colors' o' rand_node_colour' più volte? Se lo fai rapidamente, più chiamate potrebbero utilizzare lo stesso valore di inizializzazione. –

+0

Salve @JoachimPileborg si, ogni volta che viene costruito un 'somNode', chiamo' rand_node_colour'. Dai un'occhiata al costruttore 'somNode'. La mia idea era di creare in ogni costruzione un colore casuale per il nodo. Capisco ... come posso risolvere questo problema? :) – jjepsuomi

+0

Sementi il ​​gen. solo una volta alla costruzione, preferibilmente usando un 'std :: random_device'. Vedi un semplice esempio [qui] (http://en.cppreference.com/w/cpp/numeric/random/uniform_int_distribution). – vsoftco

risposta

6

Il problema qui è che si costantemente ricreare e inizializzare il generatore di numeri casuali in rand_node_colour. Si chiama in un ciclo stretto in modo da poter ottenere lo stesso tempo, il che significa che il seme sarà lo stesso e questo significa che i numeri casuali generati saranno gli stessi.

Quello che devi fare è seminare il generatore una volta e continuare a usare la sua uscita casuale. Un modo semplice per risolvere il tuo codice sarebbe quello di renderlo static nella funzione sos è solo inizializzato una volta e ogni successiva chiamata alla funzione continuerà su invece di avviare il generatore dappertutto.Se lo facciamo il codice diventa

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); 
    } 
} 
+0

Eccellente! Questo è stato. E ora capisco anche perché. Grazie =) – jjepsuomi

+0

@jjepsuomi Nessun problema. Felice di aiutare. – NathanOliver

+0

Inoltre, devo notare che 'default_random_engine' sta per alias diverso generatori su diverse piattaforme ed è altamente probabile che sia un po 'di generatore entri come LCG. È meglio dichiarare esplicitamente l'intenzione di utilizzare un generatore di cemento. –