Ok, auch die Variante mit der Multiplikation hat da naturgemäß gewisse Defizite bei der Gleichverteilung. Immerhin sind die häufigen und die weniger häufigen Zahlen einigermaßen gleichmäßig über den Wertebereich verteilt, wogegen bei der Modulo-Variante die kleineren Zahlen häufiger vorkommen (ob eines davon besser ist, mag jeder selbst beurteilen).
Selber implementieren: etwas mehr Zeitaufwand in der Codierungsphase, deutlich weniger Frust in der Testphase.
Muß man sich klar werden was man will: die üblichen derartigen Grundfunktionen liefern Gleichverteilung nicht Gaußverteilung. Und meist auch ohne den Wert 0. D.h. will man eine "natürliche" Gaußkurve mit Mittelwert 3sec ?
Für Modellbau zur Simulation "Feuerschein, brennendes Haus" mit LEDs scheint typisch LFSR d.h. Gleichverteilung gereicht zu haben.
Zur Implementierungen der Grundfunktion mit Gleichverteilung auf Controller eignet sich: a) lineare Kongruenz LCG: bessere Verteilung, benötigt aber Multiplikation Da 8 bit Controller bereits 8x8->16Bit Befehl haben heute oft von Rechenzeit akzeptabel. b) LFSR Linear Feedback Shift Register: minimaler Aufand, maue Qualität. c) noch mieser: 256 Byte Tabelle die man z.B. während Compilierung mit LFSR füllt. Das hat bei mir schonmal voll gereicht einem PWM-getakteten Schrittmotor das unangenehme Pfeifen abzugewöhnen.
Die Umwandlung von Gleichverteilung auf Gauß auf 8 Bit Controller typisch LCG und Mittelwert über 12 Samples. Auf Seite 7/8 von Heft 2 / 2007 der FORTH e.V. kurzer Artikel:
formatting link
Man kann sich andere Varianten ausdenken: ( unfertig )
formatting link
Die timing Angaben beziehen sich auf 68HC908 der im Befehlssatz ähnlich AVR ist, aber langsamer.
Ein ungelöstes und auch schwer lösbares Problem ist "zufälliger" Startwert SEED für LCG und LFSR. Minimal sollte man nach Reset ein Bit setzen damit der Wert wenigstens nicht 0 ist.
Am Thu, 15 Aug 2013 09:39:33 +0200, meinte Rafael Deliano :
Naja .... ich wollte eigentlich nicht auch noch in die Untiefen (bzw. undendlichen Tiefen) der Erzeugung einer Zufallszahl mittels uC eintauchen ...
Ich bin nicht sicher, Dich richig zu verstehen. Ungebildet wie ich in dieser Hinsicht bin bedeutet für mich "zufällig" eben, daß auf Dauer alle Werte gleich häufig auftreten. Eine Häufigkeitsverteilung nach der Gaußschen Kurve ist aber doch gerade das Gegenteil, nämlich eine Häufung der Werte/Ergebnisse um den Mittelwert von 3 (bei einem Wertebereich von 0 bis 6). Wobei das "gleich häufig" hier nicht wirklich wörtlich zu nehmen ist, ich möchte nur keine "Klumpenbildung" um eine bestimmte Zeitdauer.
Meine Anmerkung bezog sich auf die konkrete Anwendung der rnd()-Funktion: Wenn es vom Ergebnis her egal ist, ob ich für rnd() einen Wertebereich bis 40 vorgebe oder z.B. als Wertebereich 40000 nehme und dann auf (in diesem Beispiel) 40 Werte für die Verzögerung herunterrechne, dann kann ich es so belassen wie es ist.
Das habe ich jetzt nicht verstanden - aber auch nicht, was ich mit der Vorgabe eines SEED-Werts bewirken kann (die BASCOM-Hilfe ist für mich unverständlich).
Die Funktion hat eine 16 Bit Variable SEED die man laden muß/sollte, bevor man aus dem Generator Werte entnimmt. BASACOM empfiehlt einen 16 Bit Timerwert als Startwert reinzukopieren. Das ist jedenfalls besser als eine Konstante und durchaus praktikabel.
Hängt letztlich von der Anwendung ab was man will: die Gaußverteilung ist die "natürliche" Verteilung für die meisten physikalischen Vorgänge a la analoges Rauschen. BASCOM wird absehbar Gleichverteilung und nicht Gauß liefern.
Die rnd-Funktion liefert keine wirklich zufälligen Zahlen, sondern eine deterministische, sich zyklisch wiederholende Pseudo-Zufallszahlenfolge. Die Startposition innerhalb dieser zyklischen Folge ist durch den SEED-Wert beeinflussbar.
Falls es für deine Anwendung akzeptabel ist, dass jedesmal nach dem Einschalten die gleichen 'Zufallszahlen' generiert werden, musst du nichts unternehmen, dann ist rnd() gut genug.
Ist das jedoch unerwünscht, musst du für sogenannte 'Entropie' sorgen, und damit den SEED initialisieren, oder dafür sorgen, dass die Position in deiner Zufallszahlenfolge über das Ausschalten hinaus gespeichert wird.
Entropie kann man durch Ereignisse, die eben nicht jedesmal nach dem Einschalten auf die gleiche Art ablaufen, gewinnen:
- Zeitpunkt von Tastendrücken des Benutzers
- die untersten Bits von digitalisierten Analogsignalen (Rauschen)
- Zeitpunkt des Einschaltens, falls eine Echtzeituhr verfügbar ist
Alternativ könntest du die jeweils zuletzt generierte Zufallszahl im nichtflüchtigen Speicher (EEPROM) des Controllers speichern und als Startwert fürs nächste Einschalten verwenden. Dabei muss man allerdings auf die Lebensdauer der EEPROM-Zellen achten, die lassen sich nur begrenzt oft (z.B. 100000 mal) programmieren. Man kann den Wert aber auf mehrere EEPROM-Zellen verteilen, so dass die Gesamtlebensdauer dann wieder passt.
Am Sat, 17 Aug 2013 14:58:00 +0200, meinte "Peter Schneider" :
Ersteres war mir klar, jetzt verstehe ich auch SEED. Danke.
Ja, das spielt nicht die geringste Rolle.
Wie geschrieben bin ich unsicher hinsichtlich der onkreten Anwendung der rnd()-Funktion: Wenn es vom Ergebnis her egal ist, ob ich für rnd() einen Wertebereich bis 40 vorgebe oder z.B. als Wertebereich
40000 nehme und dann auf (in diesem Beispiel) 40 Werte für die Verzögerung herunterrechne, dann kann ich es so belassen wie es ist.
Solange du nicht weißt, wie die rnd-Funktion implementiert ist, kannst du da nicht sicher sein.
Das an anderer Stelle im Thread genannte Beispiel in der Arduino-Programmierumgebung ist da z.B. suboptimal implementiert.
Wenn du dir dort Zahlen modulo 40000 wünschst, ergibt sich eine stark verzerrte Verteilung, da der Zufallszahlengenerator (RNG) Zahlen im Bereich von 0 bis 65535 liefert und der zurückgelieferte Wert modulo 40000 berechnet wird.
RNG random()-Wert
0...39999 0..39999
40000..65535 0..25535
Somit ergibt sich trotz Gleichverteilung des RNG eine doppelt so hohe Wahrscheinlichkeit für die 20000 wie für die 30000. Wenn du das Ergebnis noch durch 1000 teilst, wird das nicht besser, die 20 kommt doppelt so oft wie die 10 vor.
Die Verzerrung ist bei Berechnung modulo 40 nicht so schlimm, und bei modulo-Werten, die Potenzen von 2 sind (Teiler von 65536), bleibt es bei einer Gleichverteilung.
Wie das bei der Bascom-Library aussieht, bleibt vermutlich das Geheimnis des Herstellers, bis du den Disassembler ansetzt oder die Gleichverteilung durch ein Testprogramm überprüfst.
Am Sat, 17 Aug 2013 17:10:51 +0200, meinte "Peter Schneider" :
...
So etwas meinte ich.
Wäre es dann nicht sinnvoller, sicherheitshalber den vollen Bereich von 65535 zu wählen und das Ergebnis mit einer zehnfachen Shift-Operation in den brauchbaren Bereich bis ungefähr 60 zu dividieren?
Ja, falls 0..65535 der 'natürliche' Bereich der Bascom-Funktion ist. Die von Rafael verlinkte Doku sagt: "returns an Integer/Word" und "Each new call to Rnd() will give a new positive random number."
Was das genau in Basic-Speak bedeutet, weiß ich nicht.
Es gibt Algorithmen, die bei 0 eine recht wenig zufällige Folge liefer n, nämlich nach dem Motto "einmal 0, immer 0". Das nennt man einen "Fixpu nkt" des Algorithmus - einmal erreicht, wird er nie wieder verlassen. Allerdings ist er insofern wenig kritisch, als er nur von einem einzigen Startwert aus erreicht werden kann (er ist disjunkt zu dem anderen, üblichen Wertebereich), nämlich vom Wert 0 aus. Deshalb ist es n ützlich, den Startwert so zu initialisieren, daß er mit Sicherheit nicht 0 sein kann.
--
--
(Weitergabe von Adressdaten, Telefonnummern u.ä. ohne Zustimmung
Solche Algorithmen sind allerdings völlig indiskutabel. Nicht nur wegen des Fixpunkt an sich, sondern umgekehrt auch, weil eben dieser Fixpunkt ja auch nicht Teil der "normalen" Peudozufallsfolge sein kann.
Welcher Idiot verwendet _heute_ noch so einen Algorithmus?
ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here.
All logos and trade names are the property of their respective owners.