Forum: Compiler & IDEs array mit rand() füllen


von andy (Gast)


Lesenswert?

Hallo ich habe mir einen 8x8x8 Led Cube gebaut.Jetzt möchte ich mit 
rand() eine Zufallszahl zwischen 0 und 511 ziehen und damit nach und 
nach jede Led einschalten bis alle leuchten.Ich habe mir also ein 512 
zeichen grosses array angelegt,lasse rand eine zahl berechnen,schaue im 
array nach ob auf diesem arrayplatz eine 0 steht.Wenn ja,diesen Platz 
mit einer 1 beschreiben und entsprechende Led einschalten.Klappt auch 
alles,nur wird das einschalten einer neuen led immer langsamer,da er ja 
immer öfters eine schon gezogene Zahl zieht.Die letzten Leds dauern 
ewig.Grübel jetzt schon einige zeit darüber nach,wie man das ändern 
könnte.MC ist ein mega644.
Hier die kurze for schleife.

  for(uint16_t a = 0;a<512;a++)  //array nullen
   {
    komplett [a] = 0;
   }
  uint16_t zufall;
  for(uint16_t t = 0;t < 512;)
   {
    zufall = rand()%512;
    if(komplett[zufall] == 0)
     {
      komplett[zufall] = 1;
      t++;
      ebene = zufall / 64;   //ab hier nur berechnung welche led es ist
      test = zufall - (ebene * 64);
      reihe = test / 8;
      ergebniss = reihe * 8;
      test = test - ergebniss;
      anzeige [ebene] [reihe] |= (1<<test);
      zeig_bild(2);
     }
    else
     {
      zeig_bild(1);
      continue;
     }
   }
Wäre super,wenn jemand helfen könnte.
gruss

andy

von Karl H. (kbuchegg)


Lesenswert?

> Grübel jetzt schon einige zeit darüber nach,wie man das ändern
> könnte.

Du legst dir ein Array der Größe 512 an.
In dieses Array schreibst du nacheinander die Zahlen 0 bis 511.

Dann lässt du dir mittels rand() Zufallszahlen erzeugen und (AChtung 
jetzt kommts) fasst die Werte als Index in dieses Array auf. Diese Werte 
vertauscht du dann ganz einfach.

Im Grund mischt du die Zahlen in deinem Array einfach durch in dem du 
die Reihenfolge zufällig vertauscht, so wie beim Kartenspielen.

Ist das Array gemischt, dann gehst du es von vorne nach hinten durch und 
die Zahl an der jeweiligen Stelle sagt dir, welche LED einzuschalten 
ist.

von Karl H. (kbuchegg)


Lesenswert?

1
  // Initialisieren
2
  for( i = 0; i < 512; ++i )
3
    komplett[i] = i;
4
5
  // Mischen
6
  for( i = 0; i < 512; ++i )
7
  {
8
    // wähle zufällig eine andere LED aus
9
    uint16_t k = rand() % 512;
10
11
    // und vertausche die Nummern der beiden
12
    uint16_t tmp = komplett[i];
13
    komplett[i] = komplett[k];
14
    komplett[k] = tmp;
15
  }
16
17
  // Ausgeben
18
  for( i = 0; i < 512; ++i )
19
  {
20
    erleuchte LED  komplett[i]
21
  }

von andy (Gast)


Lesenswert?

Hallo,danke für die antwort.Das hört sich ja sehr gut an.
Ich verstehe nur das mit dem Index und dem vertauschen nicht so ganz.
Könntest du mir das etwas anschaulicher erklären?

gruss

andy

von Karl H. (kbuchegg)


Lesenswert?

andy schrieb:

> Könntest du mir das etwas anschaulicher erklären?

Sicher.

(Siehe Code)
Beitrag "Re: array mit rand() füllen"

ANgenommen, du hast nicht 512 sondern 8 (sonst zeichne ich mir einen 
Wolf)

So gehts los

  +---+---+---+---+---+---+---+---+
  | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
  +---+---+---+---+---+---+---+---+

Die 2.te Schleife beginnt.
Die erste Zufallszahl sei 5.
Also wird Element 0 mit Element 5 vertauscht

    +-------------------+
    v                   v
  +---+---+---+---+---+---+---+---+
  | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
  +---+---+---+---+---+---+---+---+

  +---+---+---+---+---+---+---+---+
  | 5 | 1 | 2 | 3 | 4 | 0 | 6 | 7 |
  +---+---+---+---+---+---+---+---+

nächster Schleifendurchgang: Die Zufallszahl sei 3

        +-------+
        v       v
  +---+---+---+---+---+---+---+---+
  | 5 | 1 | 2 | 3 | 4 | 0 | 6 | 7 |
  +---+---+---+---+---+---+---+---+

  +---+---+---+---+---+---+---+---+
  | 5 | 3 | 2 | 1 | 4 | 0 | 6 | 7 |
  +---+---+---+---+---+---+---+---+

Nächster Durchgang: Tausche Element 2 mit ..... 7

            +-------------------+
            v                   v
  +---+---+---+---+---+---+---+---+
  | 5 | 3 | 2 | 1 | 4 | 0 | 6 | 7 |
  +---+---+---+---+---+---+---+---+

  +---+---+---+---+---+---+---+---+
  | 5 | 3 | 7 | 1 | 4 | 0 | 6 | 2 |
  +---+---+---+---+---+---+---+---+

Nächster Durchgang: Tausche Element 3 mit ....  2

        +---+
        v   v
  +---+---+---+---+---+---+---+---+
  | 5 | 3 | 7 | 1 | 4 | 0 | 6 | 2 |
  +---+---+---+---+---+---+---+---+

  +---+---+---+---+---+---+---+---+
  | 5 | 7 | 3 | 1 | 4 | 0 | 6 | 2 |
  +---+---+---+---+---+---+---+---+

Nächster Durchgang: Tausche Element 4 mit ..... 6

                    +-------+
                    v       v
  +---+---+---+---+---+---+---+---+
  | 5 | 7 | 3 | 1 | 4 | 0 | 6 | 2 |
  +---+---+---+---+---+---+---+---+

  +---+---+---+---+---+---+---+---+
  | 5 | 7 | 3 | 1 | 6 | 0 | 4 | 2 |
  +---+---+---+---+---+---+---+---+


.....

Durch die for-Schleife wird jedes Array Element mit irgendeinem anderen 
getauscht (kann auch mit sich selbst 'getauscht' werden). Am Ende hast 
du ein Array, in dem die Zahlen 0 bis 7 in irgendeiner zufälligen 
Reihenfolge drinnenstehen. Das muss so sein, denn du hast ja nur Werte 
getauscht und die Werte an sich ja nicht verändert; und am Anfang waren 
die Werte von 0 bis 7 drinnen, also sind sie auch zum Schluss noch 
drinnen. Nur eben vertauscht.

zb
  +---+---+---+---+---+---+---+---+
  | 0 | 7 | 3 | 4 | 2 | 5 | 1 | 6 |
  +---+---+---+---+---+---+---+---+

Du schaltest also die LED in der Reihenfolge

  LED 0
  LED 7
  LED 3
  LED 4
  LED 2
  LED 5
  LED 1
  LED 6

ein. Die Reihenfolge ist zufällig und jede LED kommt irgendwann drann. 
Anstelle, dass du während des Einschaltens abprüfst, ob du eine zufällig 
gewählte LED schon eingeschaltet hast oder nicht, legst du die 
Reihenfolge aller LEDs schon ganz am Anfang komplett fest. Das geht aber 
schnell.

von andy (Gast)


Lesenswert?

Vielen Dank.Seit zwei Tagen brüte ich darüber und du schüttelst das so 
aus dem ärmel.Es läuft schon und sieht klasse aus.Jetzt werde ich deine 
erklärung durchgehen bis ich sie richtig begriffen habe.
Nochmals vielen Dank.

gruss

andy

von Karl H. (kbuchegg)


Lesenswert?

andy schrieb:
> Vielen Dank.Seit zwei Tagen brüte ich darüber und du schüttelst das so
> aus dem ärmel.

Tja.
Ich hab auch Algorithmenbücher studiert :-)
Ist eine Standardaufgabe.

(Das ist ja auch nicht auf meinem Mist gewachsen. Ich hab das auch von 
anderen gelernt. Lang lang ists her.
Viele dieser Standardaufgaben wurden in den 60.er Jahren des letzten 
Jahrhunderts entwickelt, als Informatik die große Blütezeit hatte und 
man praktisch überall Neuland betrat. Die großen Namen der Informatik 
sind zum Teil mit genau diesen kleinen Algorithmen untrennbar verknüpft)

> Es läuft schon und sieht klasse aus.Jetzt werde ich deine
> erklärung durchgehen bis ich sie richtig begriffen habe.

Ich hoffe mal, die Zeichnungen machen es klarer

von andy (Gast)


Lesenswert?

Hallo,jetzt ist alles klar.Ich hätte gerne Algorithmenbücher studiert
durfte es aber nicht (Vater meinte nur Handwerk taugt was,war in den 70 
Jahren).Habe damals mit einem Schneider CPC und Schildkröt Basic 
rumgemacht.
Danach Frau,Kind und Haus.Jetzt ist Haus fertig,Kind erwachsen und Frau 
immer noch da.Also kann ich jetzt da weitermachen wo ich damals leider 
nicht weitermachen durfte.

gruss

andy

von Karl H. (kbuchegg)


Lesenswert?

Ist zwar schon alt und wenn du nichts gegen PASCAL hast, kann man da 
viel lernen. Ich hab Wirth immer sehr gemocht, weil ich mit seiner 
Erklärweise gut zurecht gekommen bin.
http://www.amazon.de/Algorithmen-Datenstrukturen-Niklaus-Wirth/dp/3519022508

Ein anderes Standardwerk ist zb der Sedgewick
http://www.amazon.de/Algorithmen-C-Robert-Sedgewick/dp/3893193766


Aber im Grunde sind meine Literaturkentnisse schon lang veraltet. Heute 
gibt es sicher modernere und didaktisch besser aufbereitete 
'Standardwerke'. Wenn du mal 30 oder 40 Euro übrig hast, kauf dir was. 
Du und deine Programmierweise kann davon nur profitieren.


:-)
Irgendwann kauf ich mir auch noch den Knuth. Den dann allerdings als 
Sammlerstück, das man einfach haben muss :-)

von Andreas B. (andreas_b77)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Nächster Durchgang: Tausche Element 3 mit ....  2

Das ist aber keine korrekte Implementierung (oder die Implementierung 
eines nicht so guten Algorithmus) und führt nicht zu gleichen 
Wahrscheinlichkeiten für alle Verteilungen.

Man iteriert über das Array und tauscht nur zwischen dem aktuellen Index 
und dem Bereich aktueller Index bis letzter Index. Das ist der 
Fisher-Yates Algorithmus.

Ob das jetzt beim LED Cube eine spürbare Verzerrung darstellt wenn man 
den falschen Algorithmus verwendet, darüber lässt sich streiten. Gerade 
bei solchen Mustern könnte ich mir aber vorstellen, dass man 
Ungleichgewichte sieht.

von Karl H. (kbuchegg)


Lesenswert?

Andreas B. schrieb:
> Karl Heinz Buchegger schrieb:
>> Nächster Durchgang: Tausche Element 3 mit ....  2
>
> Das ist aber keine korrekte Implementierung (oder die Implementierung
> eines nicht so guten Algorithmus) und führt nicht zu gleichen
> Wahrscheinlichkeiten für alle Verteilungen.
>
> Man iteriert über das Array und tauscht nur zwischen dem aktuellen Index
> und dem Bereich aktueller Index bis letzter Index. Das ist der
> Fisher-Yates Algorithmus.

AH, ja. Richtig da war noch was. Danke

> Ob das jetzt beim LED Cube eine spürbare Verzerrung darstellt wenn man
> den falschen Algorithmus verwendet, darüber lässt sich streiten. Gerade
> bei solchen Mustern könnte ich mir aber vorstellen, dass man
> Ungleichgewichte sieht.

Na ja. wenn man es ganz genau nimmt, dann ist ja auch

    rand() % 512

bzw. dann eben

    i + rand() % ( 512 - i )

nicht der Weisheit letzter Schluss.

Spielhöllentauglich ist das alles nicht, aber für den Hausgebrauch gut 
genug.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Wenn es darum geht, eine gegebene Menge durchzuschütteln, dann verwende 
ich folgendes Verfahren. Hier ein Beispiel mit 4 Werten A, B, C und D.

Zunächst schreibt man die 4 zu permutierenden Objekte hin:
1
Liste : A, B, C, D

Dann zieht man eine Zufallszahl 1..4 (hier 3) und nimmt diese Element 
aus der Liste und schreibt es in die Permutation:
1
Zufall = 3
2
Liste : A, B, C, D   ->  A, B, D
3
              ^
4
Permu : C

Dann eine Zufallszahl 1..3 (hier 3)
1
Zufall = 3
2
Liste : A, B, D   ->  A, B
3
              ^
4
Permu : C, D

Dann eine Zufallszahl 1..2 (hier 1)
1
Zufall = 1
2
Liste : A, B   ->  B
3
        ^   
4
Permu : C, D, A

Schließlich gibt's nur noch eine Möglichkeit:
1
Zufall = 1
2
Liste : B   ->  {}
3
        ^   
4
Permu : C, D, A, B

Nach Konstruktion sind die erzeugten Folgen gleichverteilt (unter der 
Voraussetzung, daß die Zufallszahlen 1..n gleichverteilt sind).

Wenn man keine Listen mag, kann man auch Arrays nehmen und merken, 
welche Elemente bereits gestrichen sind. In C ist das zum Beispiel viel 
einfacher als Listen anzupacken.

Dieses Verfahren kann auch dazu verwendet werden, bei 10 Elementen die 
10000-te Permutation zu bestimmen, ohne eine vorherigen Permutation 
erzeugen zu müssen. Dazu bringt man man 10000 in ihre faktorielle 
Darstellung und wendet das obige Verfahren an, siehe 
http://de.wikipedia.org/wiki/Faktorielles_Stellenwertsystem

Auf der faktoriellen Darstellung kann man auch eine Arithmetik aufbauen, 
die ebenso einfach ist wie die Arithmetik im 10er oder 2er System. Indem 
man 1 aufaddiert, bekommt man die Ziffern (welche den Zufallszahlen von 
oben entsprechen) für die Auswahl der Elemente der nächsten 
Permutation etc.

Indem man das Verfahren (bzw. die faktorielle Darstellung) etwas 
verallgemeinert, kann man auch leicht alle Teilmengen gleichverteilt 
erzeugen bzw. enumerieren. D.h. ebenso wie bei den Permutationen kann 
man z.B. die 1000-te Teilmenge (von 10-elementige Teilmenge einer 
50-elementigen Menge etwa) erzeugen, ohne eine vorherigen Teilmengen 
erzeugt haben zu müssen.

Ist die ursprüngliche Liste in lexikographischer Ordnung, so trifft dies 
auch für die so erzeugten Teilmengen zu (wobei Permutationen nur den 
Spezialfall einer n-elementigen Teilmenge einer n-elementigen Menge 
bilden).

von Karl H. (kbuchegg)


Lesenswert?

> Wenn man keine Listen mag, kann man auch Arrays nehmen und merken,
> welche Elemente bereits gestrichen sind. In C ist das zum Beispiel
> viel einfacher als Listen anzupacken.

Das ist völlig äquivalent zu der Tausch-Variante (wenn man sie richtig 
macht, wie Andreas angemerkt hat). Nur das man in der Tausch Variante 
keine Liste braucht. Die 'Buchführung' welche Elemente bereits 
gestrichen wurden, steckt im Zusamennspiel aus for-Schleife und Tauschen 
drinnen - die bereits gezogenen Elemente wandern durch das Tauschen an 
den Anfang (oder an das Ende, wenn man von der anderen Seite anfängt) 
des Arrays.

Vorteil: man arbeitet in-Place und auch die O-Komplexität ist geringer.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Lässt sich damit auch eine gegebene Permutation erzeugen, z.b. Numero 
1000? Wobei wieder lexikograhisch gezählt wird.

von Karl H. (kbuchegg)


Lesenswert?

Das kann ich dir nicht beantworten, weil ich die Sache mit der 
faktoriellen Darstellung noch nicht durchdacht habe. Mir gings nur 
darum, dass man nicht notwendigerweise 2 Arrays braucht, sondern auch 
alles in 1 abwickeln kann, was Vorteile bringt weil die Verwaltung 
dadurch einfacher wird, bzw anstelle von O(n^2) man bei O(n) landet. 
O(n^2) weil man ja das Ausgangsarray immer wieder zusammenschieben muss 
um die Lücke durch die Entnahme zu schliessen. Vom statistischen Punkt 
der Gleichverteilung aller Permutationen, sind die beiden Verfahren 
gleichwertig.

http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Karl Heinz Buchegger schrieb:
> Das kann ich dir nicht beantworten, weil ich die Sache mit der
> faktoriellen Darstellung noch nicht durchdacht habe. Mir gings nur
> darum, dass man nicht notwendigerweise 2 Arrays braucht, sondern auch
> alles in 1 abwickeln kann, was Vorteile bringt weil die Verwaltung
> dadurch einfacher wird, bzw anstelle von O(n^2) man bei O(n) landet.

Das ist bei der faktoriellen Darstellung auch der Fall. Man muss das 
Array nicht zusammenschieben sondern kann einfach ein Element als 
entnommen markieren. Damit hat es Laufzeit O(n) unter der Annahme, daß 
Arrayzugriff O(1) kostet.

von Karl H. (kbuchegg)


Lesenswert?

Johann L. schrieb:
> Karl Heinz Buchegger schrieb:
>> Das kann ich dir nicht beantworten, weil ich die Sache mit der
>> faktoriellen Darstellung noch nicht durchdacht habe. Mir gings nur
>> darum, dass man nicht notwendigerweise 2 Arrays braucht, sondern auch
>> alles in 1 abwickeln kann, was Vorteile bringt weil die Verwaltung
>> dadurch einfacher wird, bzw anstelle von O(n^2) man bei O(n) landet.
>
> Das ist bei der faktoriellen Darstellung auch der Fall. Man muss das
> Array nicht zusammenschieben sondern kann einfach ein Element als
> entnommen markieren.

Und landet damit wieder beim Problem, dass der TO in erster Linie hatte: 
Das man gegen Ende hin 'unendliche' viele Zufallszahlen generieren muss, 
bis man dann endlich irgendwann eine findet, deren Element noch nicht 
benutzt wurde.

Oder versteh ich dich jetzt falsch?

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Karl Heinz Buchegger schrieb:
> Johann L. schrieb:
>> [faktorielle Darstellung]
>
> Und landet damit wieder beim Problem, dass der TO in erster Linie hatte:
> Das man gegen Ende hin 'unendliche' viele Zufallszahlen generieren muss,
> bis man dann endlich irgendwann eine findet, deren Element noch nicht
> benutzt wurde.

Nö. Im ersten Schritt braucht man eine Zufallszahl 1..n, im 2. Schritt 
eine 1..n-1, ... im n-1-ten Schritt eine 1..2 und schliesslich eine 1..1 
(also 1).

Wie oben geschrieben, braucht man gleichverteilte Zufallszahlen 1..m; 
ansonsten sind die erzeugten Teilmengen/Permutationen nicht 
gleichverteilt. Diese Voraussetzung hat man bei FY aber doch auch?

von Karl H. (kbuchegg)


Lesenswert?

Johann L. schrieb:

> Nö. Im ersten Schritt braucht man eine Zufallszahl 1..n, im 2. Schritt
> eine 1..n-1, ... im n-1-ten Schritt eine 1..2 und schliesslich eine 1..1
> (also 1).

Jetzt verwirrst du mich.
Ich dachte du willst nicht das Array zusammenschieben?

Ah, du gehst das Array von vorne nach hinten durch und suchst die i-te 
Zahl die noch nicht benutzt wurde.
Damit sind wir wieder bei O(n^2)  (2 ineinander geschachtelte 
for-Schleifen, deren Endwerte, wenn auch über Umwege, von n abhängen)

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Karl Heinz Buchegger schrieb:
> Johann L. schrieb:
>
>> Nö. Im ersten Schritt braucht man eine Zufallszahl 1..n, im 2. Schritt
>> eine 1..n-1, ... im n-1-ten Schritt eine 1..2 und schliesslich eine 1..1
>> (also 1).
>
> Jetzt verwirrst du mich.
> Ich dachte du willst nicht das Array zusammenschieben?
>
> Ah, du gehst das Array von vorne nach hinten durch und suchst die i-te
> Zahl die noch nicht benutzt wurde.
> Damit sind wir wieder bei O(n^2)  (2 ineinander geschachtelte

Ahhhh ja *Birne-aufdotz* jetzt seh' ich auch daß es O(n^2) ist.

von Karl H. (kbuchegg)


Lesenswert?

Johann L. schrieb:

>> Damit sind wir wieder bei O(n^2)  (2 ineinander geschachtelte
>
> Ahhhh ja *Birne-aufdotz* jetzt seh' ich auch daß es O(n^2) ist.

Hätte ja auch sein können, dass du da noch einen Trick kennst, den ich 
nicht kenne.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Karl Heinz Buchegger schrieb:
> Johann L. schrieb:
>
>>> Damit sind wir wieder bei O(n^2)  (2 ineinander geschachtelte
>>
>> Ahhhh ja *Birne-aufdotz* jetzt seh' ich auch daß es O(n^2) ist.
>
> Hätte ja auch sein können, dass du da noch einen Trick kennst, den ich
> nicht kenne.

Man kann es natürlich so machen wie bei Fisher-Yates, bzw. es ist dann 
im Endeffekt Fisher-Yates. Allerdings verliert man dann die nette 
Sortierung der Ergebnisse, und ich sehe nicht, wie man das 
zurückbekommt, ohne Array-Teile verschieben zu müssen bzw. Listen 
einzusetzen oder zu durchmustern.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.