Erstellen von korrelierten Arrays
-
Hallo
Ich bin noch sehr neu in C++ und möchte um Hilfe bei folgendem Problem bitten:
Zuerst ein von mir geschriebener, funktionierender Code Block:
int ADSIZE = 5; int MAX_MUSTER = 2; int muster[MAX_MUSTER][ADSIZE]; int ik, il; for(ik=0;ik<MAX_MUSTER;++ik){for(il=0;il<ADSIZE;++il){muster[ik][il]=(rand()%2) ;}}Dies erstellt mir ein Array mit 2 Zeilen und 5 Spalten, dessen Einträge zufällig gewählt und 0 oder 1 betragen.
Nun mein Problem: Ich möchte selbst bestimmen wie viele 1er und 0er darin enthalten sind und ich will das nicht von Hand deklarieren, weil dieses Array später einmal sehr groß sein, wenn ich ADSIZE und MAX_MUSTER hoch setze. Ich benötige daher die Automatisierung. Dazu habe ich mir folgendes überlegt, was jedoch an der C++ Umsetzung aufgrund noch zu geringer Programmierkenntnisse scheitert:
Die Idee ist eine integer Variable corr einzuführen, mit deren Inhalt x ich steuere wie viele 1er und 0er im Array sind und eine if-Schleife der Art:
int corr=x if(rand()%100<corr) {muster[il] = 1;} else {muster[il]=0;}Das dies nicht funktioniert ist offensichtlich, auch ist die Variable ik nicht enthalten, welche die Zeilen steuert. Ich vermute, dass ich um diese If Schleife noch eine for Schleife setzen muss aber ich weiss nicht genau wie ich das mit dem Array und der If Schleife mache. Leider weiss ich nicht wie man es richtig programmiert.
Ich möchte dann das x so wählen, dass ich als ersten Test z.B. in jeder Zeile nur eine 1 stehen habe. Würde mir bitte jemand dabei helfen wie ich vorzugehen habe?
Danke sehr und viele Grüße
cpp_Jungspund
-
Hallo,
schau dir mal random shuffle an.
Also (Teil-)Arry mit x Einsen und y Nullen füllen und dann shufflen.
Sollte das machen was du willst, sofern ich deine Frage richtig verstanden habe.
-
Hallo
Du hast meine Frage richtig verstanden. Erstmal danke für diesen Verweis. ich werde mir das auf jedenfall aus Interesse ansehen. random_shuffle hat mich sehr abgeschreckt, auch weil ich noch keine Ahnung von Templates habe, aber ich möchte das noch erlernen.
Zu dem Beispiel aus meiner Eingangsfrage, würdest du mir bitte da auch helfen wie das richtig gecoded wird? Ich werde solche Sache noch öfters brauchen und mir fehlen noch viele C++ Basics. Deswegen möchte ich das erlernen.
Danke und Gruß
cpp_Jungspund
-
- 1D mit random shuffle und statischem Array:
#include <iostream> #include <algorithm> #include <iterator> int main() { const int ADSIZE = 25; // Wenn das bei dir ohne const funktioniert hat, dann hast // du eine unportable Spracherweiterung deines Compiler benutzt. int muster[ADSIZE] = {}; int num_ones = 7; std::fill(muster, muster + num_ones, 1); std::random_shuffle(std::begin(muster), std::end(muster)); for(auto i : muster) std::cout << i << ' '; std::cout << '\n'; }- 2D:
#include <iostream> #include <algorithm> #include <iterator> int main() { const int ADSIZE = 25; const int MAX_MUSTER = 3; int muster[MAX_MUSTER][ADSIZE] = {}; int num_ones = 21; std::fill(*muster, *muster + num_ones, 1); std::random_shuffle(*std::begin(muster), *std::end(muster)); for(const auto &i : muster) { for(auto j : i) std::cout << j << ' '; std::cout << '\n'; } }- Oder etwas allgemeiner:
std::fill(std::begin(*std::begin(muster)), std::begin(*std::begin(muster)) + num_ones, 1); std::random_shuffle(std::begin(*std::begin(muster)), std::begin(*std::end(muster)));- Dann kann man nämlich auch andere Container nutzen, ohne den Code zu ändern (Das ist der große Vorteil von Templates: sie funktionieren mit allen Typen!):
#include <iostream> #include <algorithm> #include <iterator> #include <array> int main() { const int ADSIZE = 25; const int MAX_MUSTER = 3; std::array<std::array<int, ADSIZE>, MAX_MUSTER> muster = {{}}; int num_ones = 21; std::fill(std::begin(*std::begin(muster)), std::begin(*std::begin(muster)) + num_ones, 1); std::random_shuffle(std::begin(*std::begin(muster)), std::begin(*std::end(muster))); for(const auto &i : muster) { for(auto j : i) std::cout << j << ' '; std::cout << '\n'; } }- Oder wir sparen uns das unnötige Füllen mit der nötigen Menge an Nullen und Einsen mit anschließendem Mischen und machen stattdessen Mathematik. Das heißt, wir erzeugen gleich die richtige Verteilung ohne Umschweife (und ich hoffe stark, dass ich mich nicht verrechnet habe, sonst wäre das echt peinlich
):
#include <iostream> #include <algorithm> #include <iterator> #include <array> #include <cstdlib> struct zero_one_generator { int num_ones; int total_size; int num_generated; zero_one_generator(int num_ones, int total_size): num_ones(num_ones), total_size(total_size), num_generated(0) {} int operator()() { double prob = static_cast<double>(num_ones)/(total_size - num_generated++); if (static_cast<double>(rand()) / RAND_MAX < prob) { num_ones--; return 1; } else { return 0; } } }; int main() { const int ADSIZE = 25; const int MAX_MUSTER = 3; std::array<std::array<int, ADSIZE>, MAX_MUSTER> muster; int num_ones = 21; std::generate(std::begin(*std::begin(muster)), std::begin(*std::end(muster)), zero_one_generator(num_ones, ADSIZE*MAX_MUSTER)); for(const auto &i : muster) { for(auto j : i) std::cout << j << ' '; std::cout << '\n'; } }Mag zwar etwas umständlicher aussehen, aber der Code macht dafür gleich das was man möchte, anstatt Umwege zu gehen.
- Wenn es aus irgendwelchen Gründen ganz ohne jede Templates gehen soll (an denen aber eigentlich gar nichts schwieriges oder geheimnisvolles ist), wird der Code unschöner:
#include <iostream> #include <cstdlib> struct zero_one_generator { int num_ones; int total_size; int num_generated; zero_one_generator(int num_ones, int total_size): num_ones(num_ones), total_size(total_size), num_generated(0) {} int operator()() { double prob = static_cast<double>(num_ones)/(total_size - num_generated++); if (static_cast<double>(rand()) / RAND_MAX < prob) { num_ones--; return 1; } else { return 0; } } }; int main() { const int ADSIZE = 25; const int MAX_MUSTER = 3; int muster[MAX_MUSTER][ADSIZE]; int num_ones = 21; zero_one_generator generator(num_ones, MAX_MUSTER*ADSIZE); for(int i = 0; i < MAX_MUSTER; ++i) { for(int j = 0; j < ADSIZE; ++j) { muster[i][j] = generator(); } } for(int i = 0; i < MAX_MUSTER; ++i) { for(int j = 0; j < ADSIZE; ++j) std::cout << muster[i][j] << ' '; std::cout << '\n'; } }- Oder wenn's sogar ohne (selbst definierte) Klassen sein muss:
#include <iostream> #include <cstdlib> int main() { const int ADSIZE = 25; const int MAX_MUSTER = 3; int muster[MAX_MUSTER][ADSIZE]; int num_ones = 21; int num_generated = 0; int total_size = MAX_MUSTER*ADSIZE; for(int i = 0; i < MAX_MUSTER; ++i) { for(int j = 0; j < ADSIZE; ++j) { double prob = static_cast<double>(num_ones)/(total_size - num_generated++); if (static_cast<double>(rand()) / RAND_MAX < prob) { num_ones--; muster[i][j] = 1; } else { muster[i][j] = 0; } } } for(int i = 0; i < MAX_MUSTER; ++i) { for(int j = 0; j < ADSIZE; ++j) std::cout << muster[i][j] << ' '; std::cout << '\n'; } }
-
Dann kann man nämlich auch andere Container nutzen
Gibt es außer int[][] und std::array<std::array<>> noch einen Container, der diese Art von Iterierung unterstützt?
Ach ja: random_shuffle wurde ersetzt durch shuffle.
-
wx++ schrieb:
Dann kann man nämlich auch andere Container nutzen
Gibt es außer int[][] und std::array<std::array<>> noch einen Container, der diese Art von Iterierung unterstützt?
Jeder STL-konforme Container, der eine zusammenhängende 2D-Struktur darstellt. Ein Beispiel wäre ein vector<array>, aber natürlich auch irgendwelche selbst geschriebenen Container oder Containeradapter (z.B. ein 2D-Wrapper um einen vector), solange sie die nötigen Teile der STL-Schnittstelle umsetzen.
Der Knackpunkt ist natürlich das "zusammenhängend", weil das bei den meisten 2D-Containern nicht gegeben ist. Aber da dies das herausragende Feature eines 2D-Arrays ist, vermutete ich mal, dass diese Eigenschaft dem Threadersteller wichtig ist und dies daher keine große Einschränkung darstellt. Zumal die Alternative eher ekelig wird, zumindest wenn man alles in einem Rutsch machen möchte. Spontan würde ich da eine Art Iteratoradapter für schreiben.
-
Hi
Vielen Dank für die Antworten. Ich werde mich jetzt hinsetzen und versuchen das zu verstehen.
Grüße
cpp_Jungspund
-
Nochmal Hallo
Würdest du mir bitte bei folgendem Code von dir erklären was in der for Schleife mit der if-Schleife darinnen genau passiert? Der Code funktioniert ganz phantastisch, ich kapier nur nicht genau was du da berechnest und was die Variablen darin genau machen.
#include <iostream> #include <cstdlib> int main() { const int ADSIZE = 25; const int MAX_MUSTER = 3; int muster[MAX_MUSTER][ADSIZE]; int num_ones = 21; int num_generated = 0; int total_size = MAX_MUSTER*ADSIZE; for(int i = 0; i < MAX_MUSTER; ++i) { for(int j = 0; j < ADSIZE; ++j) { double prob = static_cast<double>(num_ones)/(total_size - num_generated++); if (static_cast<double>(rand()) / RAND_MAX < prob) { num_ones--; muster[i][j] = 1; } else { muster[i][j] = 0; } } } }Vielen Dank für die Hilfe und Grüße
cpp_Jungspund
-
Obligatorischer Link: www.if-schleife.de
Die Idee ist: Wir wissen, wie viele Einsen insgesamt gesetzt werden sollen. Wir wissen auch, wie viele Elemente wir insgesamt noch zu setzen haben (also die Anzahl Einsen und Nullen zusammen). Das heißt, die Wahrscheinlichkeit, eine Eins zu setzen ist eigentlich
(Anzahl zu setzender Einsen)/(Gesamtzahl zu setzender Elemente)
Wenn wir über den gesamten Bereich diese Wahrscheinlichkeit annehmen, haben wir aber das Problem, dass die Einsen zwar gleichmäßig verteilt werden, die gewünschte Anzahl zu setzender Einsen jedoch nur im Durchschnitt über viele Läufe erreicht wird. Wir wollen hier aber die genaue Zahl der Einsen in jedem Durchlauf garantiert haben und trotzdem sollen die Einsen gleichverteilt sein.Und hier kommt die Stelle, an der ich ehrlich gesagt nur intuitiv geschätzt (und getestet) habe, ohne es genau zu berechnen: Wenn wir bei jedem zu setzenden Element erneut berechnen, wie viele Einsen noch zu setzen sind (anhand der mitgezählten Anzahl der bereits gesetzten Einsen) und daraus die neue Wahrscheinlichkeit zum Setzen einer Eins berechnen (anhand der noch zu setzenden Elemente), dann sollte die resultierende Verteilung der Einsen immer noch gleichmäßig sein, aber die totale Anzahl der Einsen ist fest. Denn wenn wir am Anfang überdurchschnittlich viele Einsen gesetzt haben sollten, dann sinkt die Wahrscheinlichkeit weiterer Einsen, notfalls bis aus 0. Und umgekehrt kann, wenn noch viele Einsen fehlen, die Wahrscheinlichkeit zum Setzen einer Eins gegen 1 gehen.
Genau das macht der Code. Wenn du Fragen zu konkreten Stellen im Code hast, dann stell auch konkrete Fragen. Ich werde dir nicht auf gut Glück erklären, was eine Schleife oder eine Division ist, bloß weil du keine genaue Frage stellst.
num_ones ist die Anzahl noch zu setzender Einsen.
num_generated ist die Gesamtzahl bereits gesetzter Elemente (Nullen und Einsen).
total_size ist die Gesamtzahl aller zu setzenden Elemente.
prob ist die Wahrscheinlichkeit, dass das aktuelle Element eine Eins werden soll
-
Das hat mir sehr weiter geholfen. Vielen Dank.
Was mir dabei auffällt ist, dass die feste Zahl der 1er zwar so passt, es aber passieren kann, dass mehrere 1er in den gleichen Zeilen stehen. Ich frage mich wie man den Code abändern müsste, um in jeder Zeile auch nur eine 1 zu haben. Entsprechend muss die Zahl der 1er dann die Zahl der Zeilen sein.
Das übergeordnete Ziel für mich ist ein Programm zu schreiben, welches steuern kann in welchem Maß die Zeilen orthogonal zu einander sind, spricht ob 1er in der gleichen Komponente stehen oder nicht.
Meine Idee ist da noch irgendwie eine Schleife um den Code von dir herum zu bauen, der den Hammingabstand berechnet und dann eine 1 setzt oder 0. Ob das aber zielführend ist weiss ich nicht. Muss da noch mehr recherchieren.
-

Toll! Dann war ja jede Hilfe umsonst, denn du hast nicht nach dem gefragt, was du wolltest, sondern nach etwas völlig anderem, von dem du bloß dachtest, dass es dir eventuell helfen könnte. Weniger noch: Von dem du nicht einmal einen genauen Plan hattest, ob oder wie es dir weiter helfen könnte, bloß dass es irgendwie ähnliche Elemente enthält. Nun hast du nach viel verschwendeter Helferszeit also eine Lösung für ein Problem, das du nie hattest und die dir bei deinem eigentlichen Problem überhaupt nicht weiter hilft.
In Fachkreisen nennt man so etwas übrigens ein XY-Problem
-
Es geht mir nicht nur um das Problem mit dem Maß für die Orthogonalität sondern ich will auch C++ allgemein erlernen und ich bin dir daher sehr dankbar für deine Erklärungen und den Code. Didaktisch im Sinne von C++ war das sehr wertvoll für mich, daher sehe ich das nicht als verschwendete Helferzeit sondern freue mich darüber, dass ich dazu lernen kann.