| Autor |
Beitrag |
Experience1986
      
Beiträge: 192
Win XP Pro SP2
Delphi 7
|
Verfasst: Mi 18.05.05 11:02
Hi,
ich mittlerweile das Problem das random() mir, trotz randomize sehr "schlechte" zufallszahlen zurückliefert.
Wie kann ich das verbessern?
|
|
WeBsPaCe
      
Beiträge: 2322
Erhaltene Danke: 1
FireFox 3, Internet Explorer 6 SP1
D1, D3Prof, D6Pers, D7Pers+Indy, VisualStudio Express
|
Verfasst: Mi 18.05.05 11:10
Wie meinen? 
|
|
Stefan S.
      
Beiträge: 184
D5
|
Verfasst: Mi 18.05.05 11:11
Soweit ich weiss wird eine Zufallszahl bei "Random" immer aus der vorhergehenden Zahl erzeugt, sprich, die Wahrscheinlichkeit, dass immer die selbe oder eine ähnliche Abfolge von Zufallszahlen kommt, ist recht hoch, was ich zum Beispiel bei einem Vokabeltrainer, den ich mal programmiert habe, gemerkt habe, weil die Abfrage immer mit den selben Vokabeln angefangen hat. Verbessern könnte man es zum Beispiel, indem man die Zufallszahl aus der Uhrzeit erzeugt, denke ich, aber eine wirklich elegante Lösung hab ich auch noch nicht. Interessiert mich selber, die Antwort auf deine Frage.
|
|
delfiphan
      
Beiträge: 2684
Erhaltene Danke: 32
|
Verfasst: Mi 18.05.05 11:11
In welcher Hinsicht ist Random deiner Meinung nach schlecht? Wofür brauchst du es.
DaSteve: Dein Problem lässt sich durch einmaliges Aufrufen von Randomize lösen.
|
|
Experience1986 
      
Beiträge: 192
Win XP Pro SP2
Delphi 7
|
Verfasst: Do 19.05.05 09:16
Ich brauche es um einen zufälligen Index meines Arrays anzusteuern.
Delphi-Quelltext 1: 2: 3:
| randomize; xy:=random(length(MeinRecordArray)); MeinRecordArray[xy].Irgendwas:=''; |
Ich nutze bereits randomize und dennoch passiert es öfters das ich einen vorherigen Index generiert bekomme. Da es sich bei meinem Programm um ein Musik Programm handelt ist es extrem nervig wenn man ein bereits zuvor wiedergegebenes Lied erneut hören muss.
Ich hatte bereits versucht ein Integer Array, mit bisher abgespielten Index(en), mitlaufen zu lassen.
Jedes mal wenn ein zufälliger Index generiert wird, der bereits in meinem mitlaufenden Integer Array vorhanden ist, rufe ich die Prozedur erneut auf, in der Hoffnung das ein bislang nicht generierter Index generiert wird.
Nun gibt es an dieser Stelle ein Haken, und zwar wenn ich nur wenige Datensätze (in meinem Fall Songs) in meinem RecordArray habe (1,2,3...) kann es durchaus vorkommen, dass ein neuer Index eher selten getroffen wird, somit passiert es dann, dass das Programm eine CPU Auslaustung von 100% verursacht, was nicht besonders schön ist.
Also, gibt es nun eine andere Möglichkeit Zufallszahlen zu generieren als mit random() bzw. kennt ihr eine Möglichkeit random() weiterhin zu verfeinern, auser randomize?
|
|
Gausi
      
Beiträge: 8554
Erhaltene Danke: 481
Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
|
Verfasst: Do 19.05.05 09:53
Ich denke, dass du das Problem von der falschen Seite her angehst. Solange einen zufälligen Song auszuwählen, bis man einen findet, der noch nciht abgespielt wurde, ist eher ungünstig.
Wie wäre es, wenn du zu Beginn eine Liste erzeugst, in der Verweise auf deine Record-Struktur gegeben sind. Aus dieser Liste suchst du nun ein zufälliges Element aus, fängst an, es abzuspielen, und entfernst es aus der Liste. Damit wird es beim nächsten Mal bestimmt nicht abgespielt.
btw.: Es zeugt nicht von einem schlechten Zufallsgenerator, wenn öfter mal dieselbe Zufallszahl ermittelt wird.
_________________ We are, we were and will not be.
|
|
Experience1986 
      
Beiträge: 192
Win XP Pro SP2
Delphi 7
|
Verfasst: Do 19.05.05 10:05
Das ist ne Super Idee...
Danke... Das hilf mir bestimmt weiter, muss nur noch schauen wo ich eine solche liste anlege, da ich an X verschiedenen Stelllen mein RecordArray erweitere, sauber müsste man coden 
|
|
Tobias1
      
Beiträge: 454
Win 98, XP Prof
D3 Prof, D2005 Prof
|
Verfasst: Do 19.05.05 10:08
Hier gabs schon man ein Thema über den Delphi-Zufallsgenerator:
www.delphi-forum.de/...41856&highlight=
_________________ Auch das schlechteste Buch hat seine gute Seite: die letzte. (John Osborne)
|
|
OneOfTen
Ehemaliges Mitglied
Erhaltene Danke: 1
|
Verfasst: Do 19.05.05 10:32
du könntest auch, wenn du es bei deinem unsauberen Code nicht schaffst, eine Liste einzufügen, folgendes machen:
Immer, wenn der zufällige Index einen bereits gewählten Song ausgewählt hat, nicht einfach einen neuen zufälligen berechnen, sondern einfach den Index solange um 1 erhöhen, bis ein noch nicht gehörter Song ausgewählt ist.
|
|
aXiEd
      
Beiträge: 17
|
Verfasst: Sa 21.05.05 16:23
Du musst darauf achten dass Randomize nur einmal aufgerufen wird (und nicht vor jedem Random). Am besten machst du das beim Erstellen der Form.
|
|
F34r0fTh3D4rk
      
Beiträge: 5285
Erhaltene Danke: 28
Win Vista (32), Win 7 (64)
Eclipse, SciTE, Lazarus
|
Verfasst: Sa 21.05.05 16:36
|
|
Tilo
      
Beiträge: 1098
Erhaltene Danke: 13
Win7 geg. WInXP oder sogar Win98
Rad2007
|
Verfasst: So 22.05.05 18:42
|
|
Stefan S.
      
Beiträge: 184
D5
|
Verfasst: Mi 08.06.05 16:17
|
|
alzaimar
      
Beiträge: 2889
Erhaltene Danke: 13
W2000, XP
D6E, BDS2006A, DevExpress
|
Verfasst: Mi 08.06.05 16:54
@Experience: Du erwartest von dem Zufallszahlengenerator, das er Dir perfekt alle Zahlen genau 1x präsentiert. Das ist dann aber kein Zufall mehr. Das ist ja gerade das 'tolle' (bzw. Blöde, wie in deinem Fall) an den Zufallszahlen.
Was Du benötigst, ist eine zufällige Permutation deiner Songs.
Wenn deine Songs also z.B. die Nummern 1,2,3,4,5 und 6 sind, dann wäre eine zufällige Permutation dann z.B.: 265341.
Wie erzeugt man eine zufällige Permutation? Z.B. so wie OneOfTen es vorgeschlagen hat. Das ist IMHO die einfachste und eleganteste Möglichkeit.
|
|
delfiphan
      
Beiträge: 2684
Erhaltene Danke: 32
|
Verfasst: Mi 08.06.05 20:16
alzaimar hat folgendes geschrieben: | | Wie erzeugt man eine zufällige Permutation? Z.B. so wie OneOfTen es vorgeschlagen hat. Das ist IMHO die einfachste und eleganteste Möglichkeit. |
Nur hast du das Problem, dass der Algorithmus immer langsamer wird und man nicht immer einfach den Index erhöhen kann, weil du sonst übers Array hinaus liest. D.h. brauchst du noch eine Modulo-Operation. Und musst dir zusätzlich auch noch merken, welche Zahl schon vorgekommen ist...
Eine zufällige Permutation erzeugt man normalerweise so, in linearer Zeit (nach Fisher-Yates):
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16:
| Const Count = 10; Var A : Array[0..Count-1] of Integer; I, J, T : Integer; begin For I := 0 to Count-1 do A[I] := I; For I := 0 to Count-1 do begin J := I+random(Count-I); T := A[J]; A[J] := A[I]; A[I] := T; end; end; |
|
|
BenBE
      
Beiträge: 8721
Erhaltene Danke: 191
Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
|
Verfasst: Mi 08.06.05 20:20
Just BTW: Wie sieht das denn bei zufälligen Permutationen nach Alphabeth aus?
d.h. ich möchte die 519. Permutation (alphabethisch gesehen) von 'ABCDEFGHIJ'???
_________________ Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
|
|
delfiphan
      
Beiträge: 2684
Erhaltene Danke: 32
|
Verfasst: Mi 08.06.05 20:22
BenBE hat folgendes geschrieben: | Just BTW: Wie sieht das denn bei zufälligen Permutationen nach Alphabeth aus?
d.h. ich möchte die 519. Permutation (alphabethisch gesehen) von 'ABCDEFGHIJ'??? |
Zufällige Permutation oder 519. Permutation? Was jetzt?
Wie definierst du die 519. Permutation?
|
|
alzaimar
      
Beiträge: 2889
Erhaltene Danke: 13
W2000, XP
D6E, BDS2006A, DevExpress
|
Verfasst: Mi 08.06.05 20:50
Man kann Permutationen aufzählen. Dazu schreibt man alle Permutationen auf. Anschließend schreibt man neben jede Permutation den Inverse-Code: Für jedes Zeichen wird die Anzahl der Zeichen gezählt, die rechts vom Zeichen vorkommen, und größer sind.
Jede Stelle i dieses Codes wird nun mit (i-1)! multipliziert (von rechts zählen). Wir erhalten die Zahlen von 0 bis n!-1 (n=Anzahl der Stellen). Damit haben wir eine Ordnung auf den Permutationen und können auch die 519.te Permutation ermitteln. Allerdings nicht alphabetisch gesehen. Tschuldigung.
321 000 0
312 010 1
231 100 2
213 110 3
132 200 4
123 210 5
Hier der Algorithmus:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19:
| Function NthPermutation (aString : String; aCount : Integer) : String; Var d : Array Of Integer; g, i, n : Integer;
Begin n := Length (aString); setlength (d, n); d[1] := 1; For i := 2 to n - 1 do d[i] := i * d[i-1]; Result := ''; for i := n-1 downto 1 do begin g := (aCount div d[i]) + 1; Result := Result + aString[g]; delete (aString, g, 1); aCount := aCount mod d[i]; End; Result := Result + aString; End; |
Kann man bestimmt verbessern. Aber danach wäre die 519.te Permutation (graycodisch gesehen  ) von 'ABCDEFGHIJ' = 'ABCDIFHGJE'. So gesehen vermutlich auch alphabetisch korrekt 
|
|
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1
|
Verfasst: Mi 08.06.05 22:18
Experience1986 hat folgendes geschrieben: | Delphi-Quelltext 1: 2: 3:
| randomize; xy:=random(length(MeinRecordArray)); MeinRecordArray[xy].Irgendwas:=''; |
|
Du darfst Randomize nur einmal aufrufen! Steht auch in der Hilfe.
|
|
Maweki
      
Beiträge: 197
Ubuntu Linux
Lazarus
|
Verfasst: Do 09.06.05 06:24
also ich habe mein Randomize in der System.pas etwas veraendert.
Damit sollte RandSeed besser verteilt sein. Denke ich zumindest...
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13:
| procedure Randomize; inline; {$IFDEF MSWINDOWS} var Counter, Ticks: Int64; begin if QueryPerformanceCounter(Counter) then RandSeed := Counter else begin Ticks := GetTickCount; RandSeed := Ticks * 2 - (Ticks and 1); end; end; |
|
|