2016-06-08 28 views
7

Tworzę aplikację wxWidget z C++, gdzie na początku programu chcę, aby okno aplikacji zawierało piksele o losowych kolorach:Wywołanie funkcji generowania liczb losowych nie generuje całkowicie losowych liczb.

Random coloured pixels

w powyższym zgłoszeniu istnieje 3600 pikseli (60 x 60) i dały każdy piksel losowego koloru RGB stosując uniform_int_distribution

koloru dla pikseli w obrazie są generowane w momencie, używając następującej funkcji w moim kodzie:

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

Wykonuję tę czynność, nadając tej funkcji tabelę o wymiarach 3600 x 3 i ta funkcja wypełnia wartości dla kolorów.

W ten sposób nie jest to, czego chcę. Chcę tylko utworzyć klasę o nazwie somNode, gdzie każdy obiekt somNode reprezentuje piksel na obrazie (z wartościami RGB jako atrybutem macierzy składowej). W tej klasie somNode mam funkcję składającą się z uniform_int_distribution, aby nadać każdemu z nich własny losowy kolor RGB. Jest to funkcja, która tworzy losową koloru dla każdej 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); 
    } 
} 

element tablicy oznacza RGB wartość somNode. Teraz, gdy tworzę ten „som-grid”, co mam w powyższym (3600 pikseli odpowiadających 3600 somNode s) Używam następujący kod obrazka (przyjrzeć SOM-konstruktora):

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

} 

Więc mam vector<somNode> somGrid, gdzie pcham wszystkie te 3600 somNode s, kiedy je konstruuję. Po skonstruowaniu każdego węzła wywoływana jest funkcja składowa , która tworzy wartość RGB.

Kiedy jednak zaimplementować ten kod zamiast jednej użyłem najpierw uzyskać ten wynik:

enter image description here

Widać, że istnieje wyraźny wzór więc coś jest nie tak tutaj. Moje pytanie brzmi: Co dzieje się w generowaniu liczb losowych podczas tworzenia somNodes? Dlaczego nie daje tego samego wyniku co kod, którego użyłem powyżej?

P.S. tutaj jest 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

Czy nazywasz 'random_colors' lub' rand_node_colour' kilka razy? Jeśli zrobisz to szybko, wiele połączeń może korzystać z tej samej wartości początkowej. –

+0

Hi @JoachimPileborg tak, za każdym razem, gdy budowany jest 'somNode', nazywam' rand_node_colour'. Spójrz na konstruktor 'somNode'. Moim pomysłem było, aby przy każdej konstrukcji stworzyć losowy kolor dla węzła. Rozumiem ... jak mogę to naprawić? :) – jjepsuomi

+0

Seed the gen. tylko raz w budowie, najlepiej przy użyciu 'std :: random_device'. Zobacz prosty przykład [tutaj] (http://en.cppreference.com/w/cpp/numeric/random/uniform_int_distribution). – vsoftco

Odpowiedz

6

Problem tutaj jest to, że stale odtworzyć i nasion generator liczb losowych w rand_node_colour. Wywołujesz go w ciasnej pętli, dzięki czemu możesz uzyskać ten sam czas, co oznacza, że ​​materiał siewny będzie taki sam, a to oznacza, że ​​generowane losowe liczby będą takie same.

Co trzeba zrobić, to posypać generator, a następnie używać losowego wyniku. Prostym sposobem na naprawienie twojego kodu byłoby uczynienie go static w funkcji sos, które zostanie zainicjalizowane tylko raz, a każde kolejne wywołanie funkcji będzie kontynuowane zamiast rozpoczynać generowanie wszystkiego.Jeśli to zrobimy, kod stanie się

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

Doskonale! Tak było. I teraz też rozumiem, dlaczego. Dziękujemy =) – jjepsuomi

+0

@jjepsuomi Nie ma problemu. Miło, że mogłem pomóc. – NathanOliver

+0

Ponadto, muszę zauważyć, że 'default_random_engine' ma zamiar nazywać różne generatory na różnych platformach i jest wysoce prawdopodobne, że jest jakimś słabym generatorem, takim jak LCG. Lepiej wyraźnie podać zamiar użycia jakiegoś konkretnego generatora. –

Powiązane problemy