Hallo!
Ich stehe vor folgendem Problem, und zwar möchte ich mit einem ATtiny
2313 eine Zufallszahl generieren, die im bereich inkl. 0 bis inkl. 6
liegt.
Der Hintergrund dazu ist eine Simulation eines Würfels.
Wenn ich das folgender maßen mache:
1
doubler;
2
doublezufallszahl;
3
unsignedcharmin=0;
4
unsignedcharmax=6;
5
6
srand(TCNT1L);
7
// zufallszahl aus [0,1[
8
r=rand()/(RAND_MAX+1.0);
9
10
// transformation -> zufallszahl aus [a,b[
11
zufallszahl=min+(max-min)*r;
12
// Zuzfallszahl in general Purpose Register schreiben
13
GPIOR0=zufallszahl;
die Funktion srand() füttere ich dabei mit dem jeweiligen Registerinhalt
der unteren 8 Bits der Timers1 welcher permanent läuft und dessen
Overflow Interrupt disabled ist.
Der Algorithmus oben ist der wie wir ihn auf der Uni in C kennengelernt
haben, allerdings haben wir da auf einem normalen PC programmiert -> die
Register des AVR haben aber nur 8 Bit. und genau da liegt der Hund, den
ich nicht ausgraben kann, nämlich in der allerletzten Anweisung meines
obenstehenden Codes... AVRstudio sagt mir dann nämlich dass der Flash zu
193% voll ist. Kommentiere ich die letzte Zeile aus, gibts kein problem.
Klar, zufallszahl is ein double (=16Bit) und das register fasst nur 8...
Und jetzt eigentlich recht knapp gehalten: wie umgeh ich das? auf
irgendeine art und weise muss des ja einfach funktionieren...
Bin schon auf eure Antworten gespannt und sag schon mal danke ;)
LG markus
Mike schrieb:> 2313 eine Zufallszahl generieren, die im bereich inkl. 0 bis inkl. 6> liegt.> Der Hintergrund dazu ist eine Simulation eines Würfels.
Was hast denn du für Würfel?
> die Funktion srand() füttere ich dabei mit dem jeweiligen Registerinhalt> der unteren 8 Bits der Timers1 welcher permanent läuft und dessen> Overflow Interrupt disabled ist.
Lass das.
srand wird am Anfang des Programms (oder vor dem ersten rand()) einmal
aufgerufen und danach lässt man es in Ruhe.
Es ist wichtig, dass du srand() in Ruhe lässt. Ansonsten kannst du
gleich deinen Registerinhalt als Zufallszahl nehmen.
Zufallszahlen charakterisieren sich dadurch, dass eine große Menge von
Zahlen bestimmte statistische Merkmale aufbauen. Das geht aber nur, wenn
du den Generator in Ruhe arbeiten lässt und nicht jedesmal neu
eingreifst. Zufallszahlen sind heikle Gebilde und es ist sehr leicht,
sich eine zufällige Verteilung durch gut gemeinte Manipulationen zu
zerstören.
> 193% voll ist. Kommentiere ich die letzte Zeile aus, gibts kein problem.> Klar, zufallszahl is ein double (=16Bit) und das register fasst nur 8...
Kommentierst du die Zuweisung aus, gibt es keinen Grund mehr
'zufallszahl' zu berechnen. Dadurch fällt auch der Grund für diese
Berechnung
r = rand() / (RAND_MAX + 1.0);
weg und es bleibt keine Floating Point Arithmetik mehr übrig, die daher
dann auch aus dem Programm rausfliegt.
Zieh die Formeln zusammen und verzichte komplett auf Floating Point. Du
brauchst sie nicht.
GPIOR0 = min + rand() % ( max - min );
Dir ist aber hoffentlich klar, dass das hier, genauso wie deine Version,
keine gute Formel zur Berechnung von Zufallszahlen darstellt. Stichwort:
Schubladenargument. Es gibt keine Möglichkeit m Socken in n Schubladen
so zu verteilen, dass alle Schubladen gleich viele Socken enthalten. Es
sei denn m ist ein ganzzahliges Vielfaches von n.
Den Fall hast du aber nicht. RAND_MAX ist typischerweise 32767 (du hast
also 32768 Socken) während du 7 Schubladen hast. 32768 / 7 = 4681.1428 =
nicht ganzzahlig. Einige Augenzahlen werden auf deinem Würfel
signifikant häufiger auftreten als andere.
Hehe, ja gut da muss ich wohl zugeben dass ich nicht nachgedacht hab,
solche Würfel besitze ich nicht ;)
Mit der Formel:
GPIOR0 = min + rand() % ( max - min );
Klappt es leider nicht... Ich habe mein programm jetzt reduziert (also
alles auskommentiert bis auf:
Hauptoprogramm bis externer Interrupt, und in der ISR steht unmittelbar
PORTB = min + rand() % ( max - min );
Leider werden mir an meinen würfelaugenfürmig angeordneten LEDS nur 3
(dafür aber unterschiedlich) angesteuert, die den Pins PB0, PB1 und PB2
entsprechen...ahja, und das der komplette PORTB null ist kommt auch vor
:/
Ich verstehs nicht... :(
Kannst es ja auch so machen, dass du während des Tastendrucks des
Würflers eine Variable hochzählst (0 1 2 3 4 5 6 0 1 2 3 ...).
Das geht so schnell, dass der Benutzer unmöglich ausnutzen kann, dass
einfach nur gezählt wird.
So funktionieren auch die guten alten Selbstbau-Würfel (mit Zähler und
Decoder).
Flo schrieb:> Kannst es ja auch so machen, dass du während des Tastendrucks des>> Würflers eine Variable hochzählst (0 1 2 3 4 5 6 0 1 2 3 ...).>> Das geht so schnell, dass der Benutzer unmöglich ausnutzen kann, dass>> einfach nur gezählt wird.>
Die Variante habe ich schon probiert, und zwar im main(), und wenn der
ext interrupt kommt steht irgendein wert im register. witzigerweise ist
eine klare tendenz zu hohen zahlen zu bemerken, darum will ich mich ja
nach einer vernünftigen variante umsehen :)
übrigens... kommt mir das nur so vor oder ist die Simulations Funktion
von AVRstudio eher müll?
Mike schrieb:> Ich verstehs nicht... :(
Ich auch nicht.
Programm herzeigen, nicht beschreiben.
Edit:
Ähm. Wenn du die generierten Zahlen direkt ausgibst, ist klar, dass du
nur BP0, PB1 und PB2 siehst.
Die Zahlen von 0 bis 6 sind nun mal in ihrer Bitdarstellung
0 0000
1 0001
2 0010
3 0011
4 0100
5 0101
6 0110
Nur die Bits 0, 1 und 2 sind betroffen.
Du musst schon eine Umkodierung der Zahlen auf die Bitmuster machen, die
die richtigen Leds aufleuchten lassen.
Karl heinz Buchegger schrieb:> Edit:>> Ähm. Wenn du die generierten Zahlen direkt ausgibst, ist klar, dass du>> nur BP0, PB1 und PB2 siehst.>> Die Zahlen von 0 bis 6 sind nun mal in ihrer Bitdarstellung>>>> 0 0000> 1 0001> 2 0010> 3 0011> 4 0100> 5 0101> 6 0110>> Nur die Bits 0, 1 und 2 sind betroffen.> Du musst schon eine Umkodierung der Zahlen auf die Bitmuster machen, die> die richtigen Leds aufleuchten lassen.
Um Gottes Willen, STIMMT!!! Ohjeoje... jetzt habe ich gerade das ganze
Progrmm eliminiert - manchmal ist abreißen und neu bauen besser als
dranflicken... Na gut, dann werd ich mich wieder melden und sagen wie's
ausgegangen ist ;)
Aber heute eher nicht mehr.
LG
Geht es hier um möglichst guten (Pseudo-)Zufall, oder um die Umsetzung
einer unangebrachten PC-Routine (real-Mathematik) auf einen µC?
Wo liegt das Problem bei hohen Zahlen, wenn man sie (z.B. durch
modulo 7) auf 0..6 begrenzt? Je höher, desto geringer die
Wahrscheinlichkeit, dass einer der Werte bevorzugt wird...
Falls das nicht einleuchtet:
ERST EIN BISSCHEN NACHDENKEN, dann loswursteln!
Ralli schrieb:> Wo liegt das Problem bei hohen Zahlen, wenn man sie (z.B. durch> modulo 7) auf 0..6 begrenzt? Je höher, desto geringer die> Wahrscheinlichkeit, dass einer der Werte bevorzugt wird...
Kommt drauf an, was du mit 'Wahrscheinlichkeit' meinst.
Je höher RAND_MAX, desto kleiner wird die prozentuale Abweichung der
generierten Verteilung von der idealen Gleich-Verteilung. Aber
verschwinden wird sie nie, solange m % n != 0
Karl heinz Buchegger schrieb:> GPIOR0 = min + rand() % ( max - min );
Im Intervall [a,b] mit ganzzahligen
Intervallgrenzen hat's b-a+1 ganze Zahlen.
Ergo:
GPIOR0 = min + rand() % (max - min +1);
> Den Fall hast du aber nicht. RAND_MAX ist typischerweise 32767 (du hast> also 32768 Socken) während du 7 Schubladen hast. 32768 / 7 = 4681.1428 => nicht ganzzahlig. Einige Augenzahlen werden auf deinem Würfel> signifikant häufiger auftreten als andere.
Naja, signifikant...? Notfalls schleift man solange wie
wert >= RAND_MAX - (RAND_MAX % 7)
Du wirst bei so einer Routine durch die CPU nie "echte" Zufallszahlen
generieren können, das Thema wurde schon x mal durchgekaut.
Aber du hast doch 2 externe willkürlich und nicht kalkulierbare
Ereignisse, nämlich den Zeitpunkt wann der Taster "jetzt würfeln"
gedrückt wird und wann er wieder losgelassen wird. Lass bei beiden
Ereignissen einen Timer abfragen und die Ergebnisse in einen
entprechenden Algoritmus einfließen. An die Gleichverteilung der so
erzeugten Zufallszahlen kommst du mit einer reinen µC Berechnung nie
heran.
Johann L. schrieb:> Karl heinz Buchegger schrieb:>> GPIOR0 = min + rand() % ( max - min );>> Im Intervall [a,b] mit ganzzahligen> Intervallgrenzen hat's b-a+1 ganze Zahlen.
Yep. Da hab ich nicht nachgedacht bzw. zu schnell getippt.
>> Den Fall hast du aber nicht. RAND_MAX ist typischerweise 32767 (du hast>> also 32768 Socken) während du 7 Schubladen hast. 32768 / 7 = 4681.1428 =>> nicht ganzzahlig. Einige Augenzahlen werden auf deinem Würfel>> signifikant häufiger auftreten als andere.>> Naja, signifikant...?
In einem Spielcaslno wäre so was tödlich. Fürs Haus, nicht für die
Spieler.