Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi randomize result ??? (https://www.delphipraxis.net/2174-randomize-result.html)

czapie 10. Jan 2003 18:28


randomize result ???
 
Hi,
ich hab in einem Programm eine Funktion die Zufallszahlen im Integer-Format erzeugt, ganz einfach über randomize und random.
Diese Funktion wird aus einer anderen mehrmals aufgerufen, aber gibt immer das gleiche result aus :-( .
Ich denke die Zufallsfunktion wird nur einmal ausgeführt und gibt dann immer ihr result zurück, ich brauch es aber unbedingt, dass sie mehrmals ausgeführt wird! Eben für verschiedene Zahlen.

danke, Czapie.

Sharky 10. Jan 2003 18:34

Re: randomize result ???
 
Zitat:

Zitat von czapie
Hi,
... ganz einfach über randomize und random. ...

Rufst Du randomize auch immer wieder neu auf? Das wäre IMHO falsch.

Poste doch mal die entscheidende Funktion.

Hansa 10. Jan 2003 18:56

Re: randomize result ???
 
Hi,

Zitat:

Zitat von "Sharky
Rufst Du randomize auch immer wieder neu auf? Das wäre IMHO falsch.

NEIN. Wäre nicht falsch, sondern richtig, da er das nicht macht, kommt immer dieselbe Zahl, die mit dem randomize am Anfang erzeugt wurde !!

Code:
procedure Zufall;
var   I: Integer;
 begin
   Randomize;
   for I := 1 to 50 do begin
     { Ausgabe an zufälligen Positionen im Fenster }
     Canvas.TextOut(Random(Width), Random(Height), 'Fang mich!');
   end;
end;
Quelle : OH.

Merke : vor jeder Zufallszahl randomize aufrufen :!: Sonst ist der Zufall ein gespeicherter.

Gruß
Hansa

sakura 10. Jan 2003 19:00

Re: randomize result ???
 
Zitat:

Zitat von Hansa
Hi,

Zitat:

Zitat von Sharky
Rufst Du randomize auch immer wieder neu auf? Das wäre IMHO falsch.

NEIN. Wäre nicht falsch, sondern richtig, da er das nicht macht, kommt immer dieselbe Zahl, die mit dem randomize am Anfang erzeugt wurde !!

Hi Hansa, ich glaube Du hast Sharky falsch verstanden, lass mal das auch aus seinem Satz ;)
...:cat:...

d3g 10. Jan 2003 19:07

Re: randomize result ???
 
Zitat:

Zitat von Hansa
Merke : vor jeder Zufallszahl randomize aufrufen :!: Sonst ist der Zufall ein gespeicherter.

Irgendwie wiedersprichst du dich selber. Erst postest du was aus der OH, in der randomize() nur einmal aufgerufen wird, dann sagst du genau das Gegenteil.

Also: randomize() nur einmal aufrufen. Das hat folgenden Grund: randomize() ermittelt einen Startwert für eine Zufallszahlenfolge. Mit diesem Startwert wird etwas getan, sodass sich eine möglichst nicht vorhersehbare Zahl daraus ergibt, jedoch ist die Operation, die mit dem Startwert getätigt wird, immer die gleiche. Jetzt kommt der Knackpunkt: randomize() ermittelt den Startwert anhand der aktuellen Uhrzeit. Ruft man randomize() schnell mehrmals hintereinander auf, ändert sich die Zeit nur so geringfügig, dass randomize() dies nicht registriert. Das bedeutet, dass man jedes Mal denselben Startwert bekommt, also auch dieselbe "Zufallszahl". Das ist definitiv nicht das, was man will.

MfG,
d3g

Hansa 10. Jan 2003 19:09

hier kriege ich immer unterschiedliche Zahlen, Maximal-Wert 100 !

Code:
procedure TForm1.Label1Click(Sender: TObject);
begin
  randomize;
  Label1.Caption := IntToStr (random (100));
end;
Gruß
Hansa

sakura 10. Jan 2003 19:13

Weil sich in der Zwischenzeit die Uhrzeit "grundlegend" ändert. Randomize wird über den internen Zeitgeber initialisiert. Wenn Du jedoch Randomize 100 Mal direkt nacheinander aufrufst und je eine Zufallszahl aus dem gleichen Bereich holst, dann ist der Zufall weg.
Delphi-Quellcode:
// ein form mit memo und button
procedure TForm1.Button1Click(Sender: TObject);
var
  I: Integer;
begin
  for I := 0 to 99 do
  begin
    Randomize;
    Memo1.Line.Add(IntToStr(Random(100)));
  end;
end;

Hansa 10. Jan 2003 19:21

Re: randomize result ???
 
Hi,

Zitat:

Zitat von d3g
...Also: randomize() nur einmal aufrufen... Jetzt kommt der Knackpunkt: randomize() ermittelt den Startwert anhand der aktuellen Uhrzeit.

Gebe zu, das da könnte so sein ! Zu schnell gelesen. :chat: Obwohl man annehmen sollte, daß die Uhrzeit in Millisekunden mitläuft. Anscheinend ist das "randomize" bei Dir nur an der falschen Stelle. Das random bezieht sich auf das randomize, das ist der Ursprungswert. Aber wenn Du das aufruft, ists auch egal, dann wird eben nur der Startwert geändert. Das reicht doch jetzt ?

Gruß
Hansa

sakura 10. Jan 2003 19:25

Der letzte Beitrag erklärt das Randomize-Problem

http://www.delphipraxis.net/viewtopi...hlight=sekunde

Hansa 10. Jan 2003 19:48

Hi,

auf die Idee zu suchen bin ich noch gar nicht gekommen. :mrgreen: Daß es dazu etwas gibt, liegt fast auf der Hand. Aber das mit den 18tel Sekunden ? Ist das tatsächlich noch so ? Das habe ich noch in Erinnerung aus Urzeiten, 386er oder so. :shock: Sagenhaft! Trotzdem : das randomize steht wahrscheinlich nur an falscher Stelle.

Gruß
Hansa

sakura 10. Jan 2003 19:51

Stimmt, das ist aus den Uhrzeiten, aber nicht bloss 386er, sondern schon die 086er. Aber der Zeitgeber hat sich seit dem gehalten. Basiert glaube ich auf den Schwingungen irgendwelcher Quartze.
...:cat:...

Hansa 10. Jan 2003 20:07

Re: randomize result ???
 
Hi,

@ Sakura : Sagenhaft, wie gesagt :shock: Ich kann es immer noch nicht fassen. Diese Zeittaktung kommt doch tatsächlich noch von dem IPM-Ur-PC (1980 ?? oder wann ?). Hierzu sei noch erwähnt, daß in Geldspielautomaten vielfach 486er CPUs stecken, wobei die Taktung eventuell wichtig ist und auch in DB-Fahrkartenautomaten. In den Spielautomaten hängt tatsächlich ein altes 486er - Motherboard senkrecht drin, der Automat war "Made in USA", typisch!

Zitat:

Zitat von czapie
Diese Funktion wird aus einer anderen mehrmals aufgerufen, aber gibt immer das gleiche result aus :-( .
Ich denke die Zufallsfunktion wird nur einmal ausgeführt und gibt dann immer ihr result zurück, ich brauch es aber unbedingt, dass sie mehrmals ausgeführt wird! Eben für verschiedene Zahlen.

Wer ist in der Lage 18-mal pro Sekunde eine Taste zu drücken ? Schreib das randomize am besten immer direkt dabei und nicht nur einmal im Programm. Das wars dann wohl.

Gruß
Hansa

jbg 10. Jan 2003 20:17

Re: randomize result ???
 
Zitat:

Zitat von Hansa
Schreib das randomize am besten immer direkt dabei und nicht nur einmal im Programm. Das wars dann wohl.

Soll das jetzt ironisch gemeint sein? Randomize sollte am besten einmal im OnCreate Ereignis des Hauptformulars aufgerufen werden und dann nicht mehr.

Daniel 10. Jan 2003 20:17

Re: randomize result ???
 
Hallo,

Zitat:

Zitat von Hansa
[...]Schreib das randomize am besten immer direkt dabei und nicht nur einmal im Programm. Das wars dann wohl[...]


WAAAAAAAHHHH - nein; eben das genau nicht. Es reicht, 'randomize' ein einziges Mal aufzurufen - beispielsweise während des Programmstarts.
Danach musst Du nur noch 'random()' aufrufen, um die gewünschten (Pseudo-)Zufallszahlen zu erhalten.

Hansa 10. Jan 2003 20:25

Re: randomize result ???
 
Hi,

Zitat:

Zitat von Daniel
WAAAAAAAHHHH - nein; eben das genau nicht. Es reicht, 'randomize' ein einziges Mal aufzurufen - beispielsweise während des Programmstarts.

Was solls denn schaden ? Damit Daniel aber nicht unnötig Arbeit hat, die ganzen Threads zu überwachen, klinke ich mich aus diesem aus. Hier ist alles gesagt worden. Der Rest ist wie immer : "selber probieren" :dancer:

Gruß
Hansa

czapie 11. Jan 2003 12:33

!!!
 
Hi Leute,
erst mal danke für die rege Diskussion und die vielen Antworten, bin grad erst nach hause gekommen, werd noch nen bißchen probieren und dann schreiben wie's war, also wie richtig.

Czapie.

czapie 11. Jan 2003 12:40

ok habs
 
Also,
so funktionierts:
In FormCreate, oder OnCreate, wird das randomize eingetragen,
und in der "Zufallsfunktion" dann immer random aufgerufen, and that works!
Danke, schönes Weeki,
Czapie.

d3g 11. Jan 2003 12:53

Hi Hansa,

ich glaube, du hast noch nicht ganz verstanden, was wir meinen. Angenommen, du schreibst (als einfaches Beispiel) ein Programm, das eine Lottoziehung simuliert. Dann brauchst du schnell 6 bzw. 7 Zufallszahlen hintereinander. Ein Code der so aussähe
Delphi-Quellcode:
var
  numbers: arrray[0..6] of Integer;

procedure GetNumbers();
var
  i: Integer;
begin
  for i := 0 to 6 do begin
    Randomize();
    numbers[i] := Random(7) + 1;
  end;
end;
liefert dir sieben mal die gleiche Zufallszahl, weil nämlich in der Regel auf heutigen Prozessoren so wenig Zeit vergeht, dass ein Achzehntelsekundenschritt nicht auftritt (selbst wenn, dann erhältst du zwei unterschiedliche Zahlen, das ist auch nicht, was du willst).

Folgender Code wäre richtiger:
Delphi-Quellcode:
procedure GetNumbers();
var
  i: Integer;
begin
  Randomize();
  for i := 0 to 6 do  
    numbers[i] := Random(49) + 1;
end;
Hier wird Randomize() nur einmal pro Ziehung aufgerufen, das heißt, du bekommst sieben verschiedene Pseudo-Zufallszahlen (die können zwar doppelt vorkommen, aber das Prinzip ist ja wohl klar). Wenn du GetNumbers() nicht oft hintereinander aufrufst, ist das okay.

Der kleine Haken dabei ist nur: Randomize() braucht Rechenzeit - minimal aber trotzdem. Möglicherweise möchtest du aber auch tausend mal hintereinander GetNumbers() aufrufen. Dann musst du das natürlich anders machen:

Delphi-Quellcode:
var
  numbers: array[0..999][0..6] of Integer;

procedure GetNumbers(element: Integer);
var
  i: Integer;
begin
  for i := 0 to 6 do
    numbers[element][i] := Random(49) + 1;
end;

procedure CallGetNumbers();
var
  i: Integer;
begin
  Randomize();
  for i := 0 to 999 do
    GetNumbers(i);
end;
Randomize() wird nur einmal aufgerufen, man bekommt 7000 "ungleiche" Pseudo-Zufallszahlen.

Der Punkt ist, dass die letzte Möglichkeit in jedem Falle die beste ist, da sie am wenigsten rechenzeit braucht (da Randomize() nur einmal aufgerufen wird) und außerdem am wenigsten fehleranflällig ist. Daher ist es sinnvoll, immer diese Möglichkeit zu empfehlen.

Also noch einmal ganz deutlich: Am besten ist es, Randomize() nur einmal im ganzen Programm aufzurufen. Am besten im Project-File (View|Project Source) oder, wenn man nur ein Formular benutzt, im OnCreate-Ereignis.

MfG,
d3g

[edit]Hab ich wohl ein bisschen lange getippt... :mrgreen:[/edit]

Christian Seehase 11. Jan 2003 14:07

Moin Zusammen,

Zitat:

Zitat von Delphi Hilfe Randomize
Kombinieren Sie in einer Schleife nicht den Aufruf von Randomize mit Aufrufen der Funktion Random. Normalerweise wird Randomize vor den Aufrufen von Random nur einmal aufgerufen.

und wenn man sich dann mal in der System.pas ansieht, was Randomize macht, hat das durchaus seine Richtigkeit, denn es wird nichts weiter gemacht, als die aktuelle Systemzeit in ihre Entsprechung in Millisekunden umzurechnen und diese dann in der Variablen RandSeed zu speichern.
Die Zahlenfolge die Random ausgibt hängt direkt mit dem Wert in Randseed zusammen, so dass bei einem gleichen Wert für RandSeed die Zahlenfolge von Random auch immer die gleiche ist.
Wer also immer die gleiche "zufällige" Zahlenfolge braucht setzt RandSeed auf immer den gleichen Wert.
Auf Randomize kann man also im Prinzip verzichten, indem man RandSeed selber setzt.

Mehrfaches Aufrufen von Randomize schadet also nur dann, wenn die Zeitdifferenz zwischen den Aufrufen zu klein ist, wie eben, z.b. in einer Schleife.

Übrigens ist die Auflösung des Timers nicht eine 18tel Sekunde (0,0556 sek) sondern 18 Millisekunden (0,018 Sek).

sakura 11. Jan 2003 14:15

Zitat:

Zitat von Christian Seehase
Übrigens ist die Auflösung des Timers nicht eine 18tel Sekunde (0,0556 sek) sondern 18 Millisekunden (0,018 Sek).

:oops: Stimmt natürlich.

d3g 11. Jan 2003 14:37

@Christian: Hab ich was anderes behauptet? :?

Christian Seehase 11. Jan 2003 15:28

Moin d3g,

falls Du die grundsätzliche Funktionalität von Randomize meintest: Nein, hast Du nicht, ich hab's nur noch mal um das Warum ergänzt.

Was mir gerade noch einfällt:
Um etwas einmal pro Programmstart zu machen gäbe es auch noch die Möglichkeit den Aufruf in den initialization Abschnitt einer Unit zu legen.

sakura 11. Jan 2003 15:41

Zitat:

Zitat von Christian Seehase
Um etwas einmal pro Programmstart zu machen gäbe es auch noch die Möglichkeit den Aufruf in den initialization Abschnitt einer Unit zu legen.

Warum nicht einfach in die DPR Datei, direkt nach dem BEGIN :?:
...:cat:...

d3g 11. Jan 2003 16:13

Irgendwie steht in diesem Thread alles doppelt und dreifach :mrgreen:...

Zitat:

Zitat von d3g
Am besten ist es, Randomize() nur einmal im ganzen Programm aufzurufen. Am besten im Project-File (View|Project Source)


Christian Seehase 11. Jan 2003 16:26

Moin sakura,

es ging mir nur um eine weitere Möglichkeit. ;-)


Alle Zeitangaben in WEZ +1. Es ist jetzt 11:01 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz