Hallo,
ich möchte für mein Schulprojekt einen Zufallsgenerator in c Schreiben.
Da ich nicht wirklich Lösungen für mein Projekt finde frage ich einfach
mal hier ^^
also ich brauche nur eine zufallszahl von 0-5, ich habe schon RAND_MAX
und RANDOM_MAX in der h-file geändert (Bringt das was?) also auf 0x05.
ich bräuchte eine einfache und gut erklärte Version damit ich die
einzelnen Schritte nachverfolgen kann und eventuell anpassen kann.
hier wäre mein C-Code aber es funktioniert leider nicht ganz wie ich
will.
Ich habe hier mit einem AT-tiny85 gearbeitet.
Und es wäre schön und praktisch wenn mir jemand helfen kann und die If
Funktionen so bleiben könnten(Brauch ich für später)
C-Code
Michelle Erne schrieb:> mein C-Code aber es funktioniert leider nicht ganz wie ich will.
Was funktioniert nicht? Was erwartest du und was passiert stattdessen?
> also ich brauche nur eine zufallszahl von 0-5, ich habe schon RAND_MAX> und RANDOM_MAX in der h-file geändert (Bringt das was?) also auf 0x05.
Warum rechnest du da mit Hex-Zahlen? 5 ist doch sowieso das selbe wie
0x05...
BTW:
Bitte in Zukunft so:
Einene "Zufallsgenerator" kann man nicht programmieren, da ja die
Zustände zufällig sein sollen.
Was bleibt ist ein pseudo Zufallsgenerator, der Beim selben Startwert
auch die gleichen Zustände annimmt.
http://www.kuno-kohn.de/crypto/crypto/prngs.htm
Als Startwert könnte man eine ADC-Wandung eines unbeschaltenten
ADC-Eingangs verwenden.
Michelle Erne schrieb:> also ich brauche nur eine zufallszahl von 0-5, ich habe schon RAND_MAX> und RANDOM_MAX in der h-file geändert (Bringt das was?) also auf 0x05.
Nein, das bringt nix.
RANDOM_MAX ist die Information für dich, welches die größte Zahl ist,
die vom Zufallszahlengenerator kommen wird.
Die Zahl zu ändern bringt genausowenig, wie in einer Übersicht zu
behaupten, ein bestimmtes Buch hätte nich 236 Seiten sondern nur 20.
Behaupten kannst du es natürlich, aber deswegen wird sich die Anzahl der
Seiten nicht ändern.
> ich bräuchte eine einfache und gut erklärte Version damit ich die> einzelnen Schritte nachverfolgen kann und eventuell anpassen kann.
Die gibt es im Web zu hauf.
Dreh und Angelpunkt ist praktisch immer, dass man mit Zahlen auch
rechnen kann. Was du also brauchst ist eine Rechenvorschrift, wie du dir
aus dem Ergebnis von random(), welches in einem bestimmten Bereich
liegt, neue Zahlen errechnen kannst, die in dem von dir gewünschten
Bereich liegen.
Du kennst doch die Modulo-Funktion (in C ist das die Operation %). Das
Ergebnis einer Modulo-Operation (das ist nichts anderes als der Rest bei
einer ganzzahligen Division) liegt immer in welchem Bereich?
Das ist nicht unbedingt die beste Lösung, aber es ist eine einfache
Lösung, die so schlechte Ergebnisse auch wieder nicht bringt, solange
nur RAND_MAX (oder bei dir eben RANDOM_MAX) nur gross genug ist.
Nimm ein LFSR (google) und kein Float oder so.
Auch keine delays.
EIN LFSR ist deterministisch, und waehlbar in der Periode. Die Periode
kann sehr lang sein, ohne viel code.
Leute
Ich bin mir recht sicher, dass das Problem des TO nicht in einer nicht
optimal gleichverteilten Verteilung liegt oder sonstigen technischen
Finessen.
Das Problem liegt, wie meistens bei der Verwendung von rand() ganz
einfach darin, dass man erhaltene Zahlen als Gott-gegeben hinnimmt und
sich nicht traut damit ganz einfach ein wenig rumzurechnen.
Man kann einem rand() nicht vorgeben, in welchem Zahlenbereich die
Ergebnisse liegen sollen. Aber man kann den (bekannten) Zahlenbereich,
bzw. die von rand() erhaltenen Zahlen so umrechnen, dass sie im
gewünschten Zahlenbereich zu liegen kommen. Für viele Neulinge besteht
das Hauptproblem darin, dass sie erkennen müssen, das sie sich etwas
einfallen lassen müssen um mit dem Gegebenen das Gewünschte zu
erreichen. Und das verunsichert sie. Das sind sie nicht mehr gewohnt,
bzw. das haben sie noch nie gemacht, dass sie auch mal selbst eine
mathematische Formel 'erfinden' müssen. Bisher haben sie immer alles von
ihrem Lehrer aufs Auge gedrückt bekommen.
Die Ergebnisse vom rand() sind, wenn auch nicht ideal, für 99% aller
Neulings-Projekte gut genug.
Da fällt mir der hier ein:
http://dilbert.com/strip/2001-10-25
:-)
Interessant ist ja auch, wofür die Zufallszahl gebraucht wird.
Die einfachen elektronischen Würfel zählen nur sehr schnell und man hält
die zufällig auf einer Zahl an.
chris schrieb:> Ich bin mir relativ sicher, dass das Problem hieran liegt:>> Michelle Erne schrieb:>> while(0)
Autsch.
Den hab ich nicht gesehen.
Guter Fang
Michelle Erne schrieb:> else if (x==0x04)> {> PORTB |= 1<<PB4;> _delay_ms(500);> PORTB &= ~(1<<PB4);> }> else if (x==0x05)> {> PORTB |= 1<<PB4;> _delay_ms(500);> PORTB &= ~(1<<PB4);> }> }> }
Hier sollte beim letzten doch sicherlich PB5 und nicht auch PB4 stehen,
oder?
Ansonsten könnte man die hundert Zeilen auch deutlich einfacher
schreiben mit:
1
PORTB|=(1<<x);
2
_delay_ms(500);
3
PORTB&=~(1<<x);
Copy&Paste-Programmierung riecht und führt auch nur zu Fehlern wie dem
da oben.
das habe ich so gemacht weil er sonst Fehlermeldungen bring, und das hat
mein Lehrer auch bemängelter, aber so wie ich einsehen musste..
der Zufallgenerator ist für eine uslesbox die ich selber machen möchte
und zuerst mal möchte ich die einzelnen Schritte erlernen bevor ich
weiter mache.
aber ich möchte euch nochmal darum bitten mir falls ihr das könnt mir
einen c-code zu schreiben da ich so am besten nachvollziehen kann wie es
gemacht wird! nur mit trockender Theorie kann ich nicht wirklich viel
anfangen. wahrscheinlich wird jetzt alle auch mich losgehen aber vl gibt
es ja welche die mir weiter helfen können!
Oder zumindest ein Beispiel wie man rand() oder random richtig anwendet.
und noch danke an die dir mir geantwortet haben hat mir doch etwas
geholfen:
)
Michelle Erne schrieb:> der Zufallgenerator ist für eine uslesbox die ich selber machen möchte
Was ist denn das?
Michelle Erne schrieb:> Oder zumindest ein Beispiel wie man rand() oder random richtig anwendet.
Lies dir dazu mal die Dokumentation von 'stdlib.h' in der avr-libc
durch. Der zufällige Startwert, von dem die Teilnehmer hier reden, wird
dort als 'seed' bezeichnet und soll dafür sorgen, das der Generator
nicht immer die gleiche Sequenz an Zufallszahlen erzeugt. Hier mal ein
ungetestetes Snippet:
1
#include<stdlib.h>
2
#include<avr/io.h>
3
int16_tmyRandom;
4
uint16_tseed;
5
DDRB=0xFF// all outputs
6
seed=ADCRead(noisyChannel);// irgendein Wert, der immer anders ist
7
srand(seed);// Seed setzen
8
while(1){
9
myRandom=rand();
10
PortB=(myRandom&0xFF)>>8;
11
_delay_ms(20);
12
}
ADC Init usw. sind hier nicht bei, musst du selber schreiben.
>Die Ergebnisse vom rand() sind, wenn auch nicht ideal, für 99% aller
Neulings-Projekte gut genug.
IMO, benoetigt Rand() floating point. Was ein LFSR das nicht tut.
Jetzt Nicht schrieb:>>Die Ergebnisse vom rand() sind, wenn auch nicht ideal, für 99% aller> Neulings-Projekte gut genug.>> IMO, benoetigt Rand() floating point.
Deine Opionion ist falsch.
Die Funktion rand() gibt dir einen 16 Bit (Pseudo)-Zufallswert zurück,
aber immer die gleichen in der selben Rheinfolge.
Um das zu ändern muss die Funktion seed() einmalig mit einem 16-Bit
zufallswert gefüttert werden.
Also hast du ein Henne-Ei Problem. Du willst Zufallszahlen, brauchst
aber einmalig eine (echte) Zufallszahl, damit dir rand() eine aus 2^16
möglichen Zahlenreihen Pseudozufallszahlen ausspuckt.
Eine Möglichkeit ist an einem ADC-Kanal zu messen (am besten 16 Mal und
immer nur das niederwertigste Bit verwenden).
Eine andere Möglichkeit ist den nicht initialisierten Arbeitsspeicher zu
verwenden, der nach einem Power-Down-Reset ziemlich zufällig sein
sollte.
1
uint16_tget_seed(){
2
uint16_tseed=0;
3
uint16_t*p=(uint16_t*)(RAMEND+1);
4
externuint16_t__heap_start;// This Variable is defined elsewhere
5
while(p>=&__heap_start+1){
6
seed^=*(--p);
7
}
8
returnseed;
9
}
Nach einem Watchdog-Reset behält der Arbeitsspeicher seine alten Werte,
daher funktioniert diese Methode dann nicht mehr 100tig.
rand() gibt dir einen 16-Bit Zufallswert zurück, will man mehr ruft man
die Funktion mehrmals auf:
1
uint32_tx=(rand()<<16)|rand();
Du willst jetzt aber weniger, ist es ein vielfaches von 2, einfach die
variable nach rechts shiften.
Willst du jetzt eine Zahl zwischen 1 und 5 ist der einfachste weg eine
Modulu-Rechnung
1
uint8_tx=rand()%5+1;
Das + 1 weil sonst Zahlen zwischen 0 und 4 raus kommen.
Die Modulu-Rechnung ist nicht das beste, da die Zahlen dann nicht
gleichverteilt sind.
Bei deiner 5 hast du aber Glück, da 2^16 - 1 = 65535 und diese Zahl ist
Ganzzahlig durch 5 Teilbar. Also dann doch gleichverteilt.
> Eine andere Möglichkeit ist den nicht initialisierten Arbeitsspeicher zu> verwenden, der nach einem Power-Down-Reset ziemlich zufällig sein> sollte.
Noch eine andere Möglichkeit ist es, eine Benutzereingabe zu benutzen.
Gerade bei einer Useless Box würde es sich anbieten, die 'Zeit' bis zur
ersten Schalterbetätigung als Seed Wert zu nehmen.
Eine andere Variante ist es, auf rand() bzw seed() komplett zu
verzichten und den µC einfach in der Zeit in der es nichts zu tun gibt,
eine Variable laufend von 0 bis 5 durchzuzählen. Wieder: die
Schalterbetätigung durch den Benutzer ist das Signal den aktuellen
Zählerwert als Zufallszahl zu nehmen.
Malte S. schrieb:> Und ich denke nicht, dass Matthias das beabsichtigt hatte.
Ich sach' doch noch:
Matthias Sch. schrieb:> Hier mal ein> ungetestetes Snippet:
Aber man kann ja einfach das >>8 weglassen:
1
PORTB=(myRandom&0xFF);
Es ging ja auch eher um rand(), als um die Bitshifterei.