Diese Website existiert nur weil wir Werbung mit AdSense ausliefern.
Bitte den AdBlocker daher auf dieser Website ausschalten! Danke.

Java: mehrere Zufallszahlen fast immer gleich?

Alles rund um die verschiedenen Konsolen und shells sowie die Programmierung unter Linux

Moderator: Moderatoren

Antworten
Benutzeravatar
spunti
Hacker
Hacker
Beiträge: 598
Registriert: 6. Mai 2004, 10:49

Java: mehrere Zufallszahlen fast immer gleich?

Beitrag von spunti »

Hallo,

ich brauche in Java mehrere Zufallszahlen hintereinander aber die sind nahezu immer gleich.
Da ich keine Initialisierung von Random() angebe, sollte der eigentlich die Systemzeit benutzen, aber das kann doch nicht sein, daß dann immer dasselbe rauskommt oder nimmt der nicht die Mikrosekundenzeit, sondern die Minuten der Systemzeit? Soll ich da echt per Hand die Mikrosekunden der Systemzeit zum Initialisieren nehmen - das wäre ja ein Witz?

Z.B. will ich so mehrere Zufallszahlen zwischen 0 und 5:

Random random = new Random();
int randomNumber = nextInt(nextInt(5));

Da kommen aber fast immer dieselben raus, wenn ich das mehrmals aufrufe. Und wenn ich nur ein random-Objekt erzeuge und die zweite Zeile mehrmals ausführe, ändert das auch nichts.

spunti
I2ed TigeI2
Newbie
Newbie
Beiträge: 13
Registriert: 28. Aug 2005, 15:45

Beitrag von I2ed TigeI2 »

Das könnte daran liegen dass der Umfang nur 5 Zahlen ist, probiers mal mit meherern Zahlen, normalerweise müsste das mit der Systemzeit funktionieren.
Benutzeravatar
TeXpert
Guru
Guru
Beiträge: 2166
Registriert: 17. Jan 2005, 11:22

Beitrag von TeXpert »

ich denke auch dass das Hauptproblem die 5 Zahlen sind, ansonsten sind die nämlich schön verteilt.

schauen wir doch mal und zählen die Verteilung:

Code: Alles auswählen

import java.util.Random;

class r {
  public static void main(String args[]){
     int collect[] = new int[5];

     java.util.Random rand = new Random();

     for (int i = 0; i < 10000; i++)
	collect[rand.nextInt(5)]++;

     for (int i=0;i<5;i++)
         System.out.println(i + ": " + collect[i]);
  }
}
ergibt:

Code: Alles auswählen

p$ java r
0: 1926
1: 1977
2: 2045
3: 1963
4: 2089
sieht doch fast gleichverteilt aus :)

Code: Alles auswählen

# to resolve all your problems, try this:
HOWTO='pack c5,41*2,sqrt 7056,unpack(c,H)-2,oct 115' && perl -le "print $HOWTO"
Ich beantworte keine Supportfragen per PM!
Benutzeravatar
spunti
Hacker
Hacker
Beiträge: 598
Registriert: 6. Mai 2004, 10:49

Beitrag von spunti »

Hm,
also ich benötige zwingend eine ganze Zahl zwischen 0 und 5. Das ist nicht verhandelbar:-)


@texpert
In deinem Beispiel hast du aber auch den engen Bereich von 0-5 gewählt. Nur die Anzahl der Zufallszahlerzeugungen hast du erhöht. Vielleicht kann ich mit diesem Vorschlag etwas hinfrickeln, allerdings wäre so ein Workaround "böse". Damit will ich sagen, daß man sowas nicht macht, scheint mir einfach keine saubere Lösung für das Problem.

Ich könnte auch den Bereich von 0-50 erweitern und dann wieder künstlich per Hand verkleinern, wäre aber genauso "böse". Stellt euch mal vor, jeder der hintereinander ein paar halbwegs ausgewogene Zufallszahlen zwischen 0 und 5 benötigt, muß solche Sachen anstellen. Das geht doch nicht.

PS:
Texperts Vorschlag muß nicht stimmen. Z.B. könnte das Proggie erst mal das Feld 0 2000 mal hochzählen (weil jedes mal dieselbe Zufallszahl 0 erzeugt wurde) und dann erst das nächste Feld (weil dann die für die Initialisierung benötigte Systemzeit vielleicht irgendwo umspringt - an der ganze Sekundenstelle z.B. oder noch schlimmer).

spunti
Benutzeravatar
TeXpert
Guru
Guru
Beiträge: 2166
Registriert: 17. Jan 2005, 11:22

Beitrag von TeXpert »

spunti hat geschrieben: @texpert
In deinem Beispiel hast du aber auch den engen Bereich von 0-5 gewählt. Nur die Anzahl der Zufallszahlerzeugungen hast du erhöht. Vielleicht kann ich mit diesem Vorschlag etwas hinfrickeln, allerdings wäre so ein Workaround "böse". Damit will ich sagen, daß man sowas nicht macht, scheint mir einfach keine saubere Lösung für das Problem.
richtig, aber um eine statistische Aussage treffen zu können, ob die Pseudozufallszahlen (es handelt sich schließlich immer um Pseudo-Randomness) gleichverteilt sind (zumindest annhähern) kannst Du nicht nur mit 3 oder 4 Stichproben arbeiten. Wenn das Verfahren korrekt ist, dann sollte die Gleichverteilung ein Fixpunkt der Reihenentwicklung werden.

Wenn Du nur ein paar Zahlen brauchst, kannst Du davon ausgehen, dass das dann auch funktioniert. Zusätzlich, Nehmen wir 5 Zahlen aus 0-4. Wenn Du Dir eine in Deinen Augen 'optimale' Zufallsverteilung vorstellst dann ist die unter allen möglichen permutationen um "unwahrscheinlichsten", insbesondere sind Häufungen von einzelnen Zahlen sehr wahrscheinlich. Nimm z.B. eine Münze und 3 Würfe:

Code: Alles auswählen

K K K
K K Z
K Z K
K Z Z
Z K K
Z K Z 
Z Z K
Z Z Z
dann gibts nur 2 Alternierende Folgen, d.h. die "menschlisch-optimal-erkannte" Zufälligkeit ist relativ unwahrscheinlich ;)

Code: Alles auswählen

# to resolve all your problems, try this:
HOWTO='pack c5,41*2,sqrt 7056,unpack(c,H)-2,oct 115' && perl -le "print $HOWTO"
Ich beantworte keine Supportfragen per PM!
Benutzeravatar
robi
Moderator
Moderator
Beiträge: 3202
Registriert: 25. Aug 2004, 02:13

Beitrag von robi »

wenn du meinst die Zahlen seinen nicht zufällig genug, dann versuch doch mal zB nach der Formel "x = random(1000) % 6" zu arbeiten, das sollte eine brauchbare zufällige Verteilung zwischen 0 und 5 geben.

robi
Benutzeravatar
sparrow
Member
Member
Beiträge: 248
Registriert: 1. Mär 2005, 01:03
Wohnort: /home/sparrow

Beitrag von sparrow »

Hallo,
folgendes funktioniert sehr gut zur Erzeugung von Zufallszahlen:

Code: Alles auswählen

Random r = new Random();
int num = 1 + Math.abs(r.nextInt()) % 49;
num ist dann eine Zufallszahl >=1 <=49.

Der Code stammt aus dem http://www.javabuch.de

Noch ein Tipp:
Manchmal hilft es
Random r = new Random();
vor dem erneuten ermitteln einer Zufallszahl neu zu instanzieren.
Zuhause in der Linux-Familie mit openSUSE 10.2 und Kubuntu 06.10
Benutzeravatar
TeXpert
Guru
Guru
Beiträge: 2166
Registriert: 17. Jan 2005, 11:22

Beitrag von TeXpert »

mal was ganz anderes: Ich würde dem Java-random-Algo vertrauen, wenn ein Bug drin wäre wäre der mit sehr hoher WKeit schon gefunden worden und der Algo basiert
Java Doku hat geschrieben: This is a linear congruential pseudorandom number generator, as defined by D. H. Lehmer and described by Donald E. Knuth in The Art of Computer Programming, Volume 2: Seminumerical Algorithms, section 3.2.1.
und den Algos von DEK vertraue ich mittlerweile blind ;)

Code: Alles auswählen

# to resolve all your problems, try this:
HOWTO='pack c5,41*2,sqrt 7056,unpack(c,H)-2,oct 115' && perl -le "print $HOWTO"
Ich beantworte keine Supportfragen per PM!
Mumie
Hacker
Hacker
Beiträge: 274
Registriert: 4. Jan 2005, 18:50
Wohnort: bei Hannover

Beitrag von Mumie »

Hallo,
ich habe hier einen Würfel! Allerdings in C.

====================================
/* Wuerfel.c */

#include <stdio.h>
#include <stdlib.h>
#include <tgmath.h>
#include <time.h>

int i, Augenzahl; /* i wird nur als Zählvariable in der Schleife gebraucht */
double rechteck01;
int Zufall;


int main(void)
{
srand ((unsigned) time (NULL)); /* Initialisierung des Zufalls*/

for (i = 1; i <=10; i++)
{
Zufall = rand();
rechteck01 = (double) Zufall / (RAND_MAX); /* so das 0 <= rechteck01 < 1 */
rechteck01 = rechteck01 * 6; /* Jetzt ist 0 <= rechteck01 < 6 */
Augenzahl = floor(rechteck01); /* Augenzahl = {0,1,2,3,4,5} */
Augenzahl = Augenzahl +1; /* Augenzahl = {1,2,3,4,5,6} */
printf("\nAugenzahl = %d ", Augenzahl);
}

return 0;
}
====================================

Der muß mit der folgenden Zeile kompiliert werden:
gcc -Wall Wuerfel.c -lm -o Wuerfel

Das -lm ist wichtig!

Ich hoffe, der würfelt niemals die 7.

Falls die Zufallszahlen von 0 bis 5 gehen sollen, dann muß man
die Augenzahl eben wiede um 1 verringern.

Viele Grüsse
Mumie
Benutzeravatar
TeXpert
Guru
Guru
Beiträge: 2166
Registriert: 17. Jan 2005, 11:22

Beitrag von TeXpert »

Mumie hat geschrieben:Hallo,
ich habe hier einen Würfel! Allerdings in C.
Sorry, aber: Und? Was sagt das bitte über die Qualtiät des Pseudorandom-Algos von Java aus? Spunti machts ja richtig, er hat sich nur über die Verteilung gewundert (wobei die i.O. ist ;))...

Code: Alles auswählen

# to resolve all your problems, try this:
HOWTO='pack c5,41*2,sqrt 7056,unpack(c,H)-2,oct 115' && perl -le "print $HOWTO"
Ich beantworte keine Supportfragen per PM!
Mumie
Hacker
Hacker
Beiträge: 274
Registriert: 4. Jan 2005, 18:50
Wohnort: bei Hannover

Beitrag von Mumie »

Ja, natürlich. Der Algorithmus ist bestimmt gut. Aber warum gibt Spunti keine Initialisierung von Random an? Bei meinen ersten Versuchen den Würfel zu programmieren habe ich gemerkt, das dann immer die gleiche Reihenfolge von Zufallszahlen kommt.

Ich selbst bin gerade beim 8. Tag von diesem C-Kurs. Es geht um Zeiger und um Adressen. Diese Adressen sind bei jedem Programmstart neu. Irgendwie "zufällig". Vielleicht kann man auch diese Adressen als Initialisierung verwenden? - Nur so eine Idee von mir. Oder kann man die Adressen selber verwenden? Es handelt sich um Zahlen von 0 bis 9. Man könnte die einzelnen Ziffern auslesen. Alle die nicht passen kann man verwerfen. Und übrig bleibt eine zufällige Zahlenfolge.

Ich habe übrigens eine neue Version von meinem Würfel. Ich habe den Tip von robi verwendet:
=====================================

/* Würfel2 */

#include <stdio.h>
#include <stdlib.h>
#include <tgmath.h>
#include <time.h>



int i, Augenzahl; /* i wird nur als Zählvariable in der Schleife gebraucht */


int main(void)
{
srand ((unsigned) time (NULL)); /* Initialisierung des Zufalls*/

for (i = 1; i <=10; i++)
{
Augenzahl = (rand() % 6); /* Augenzahl = {0,1,2,3,4,5} */
Augenzahl = Augenzahl +1; /* Augenzahl = {1,2,3,4,5,6} */
printf("\nAugenzahl = %d ", Augenzahl);
}

return 0;
}
======================================

Das ist viel kürzer. Da bin ich auch ganz stolz drauf.

Viele Grüsse
Mumie
Benutzeravatar
TeXpert
Guru
Guru
Beiträge: 2166
Registriert: 17. Jan 2005, 11:22

Beitrag von TeXpert »

Mumie hat geschrieben:Ja, natürlich. Der Algorithmus ist bestimmt gut. Aber warum gibt Spunti keine Initialisierung von Random an? Bei meinen ersten Versuchen den Würfel zu programmieren habe ich gemerkt, das dann immer die gleiche Reihenfolge von Zufallszahlen kommt.
Dir ist klar, dass Du Dich gerade etwas blamierst?
JAVA Doku hat geschrieben:public Random()

Creates a new random number generator. Its seed is initialized to a value based on the current time:

public Random() { this(System.currentTimeMillis()); }

Two Random objects created within the same millisecond will have the same sequence of random numbers.
er legt ein neues Objekt an und das reicht.
Ich selbst bin gerade beim 8. Tag von diesem C-Kurs. Es geht um Zeiger und um Adressen. Diese Adressen sind bei jedem Programmstart neu. Irgendwie "zufällig". Vielleicht kann man auch diese Adressen als Initialisierung verwenden?
nein, sie sind nur scheinbar zufällig, denn es ist trivial ein Konstruk zu produzieren, in dem sie nicht mehr zufällig sind.

Code: Alles auswählen

#include <iostream>

class foo {
  public:
   foo() : a(4), b(6) {};
  private:
   int a;
   int b;
};

int main() {

    foo *fooptr;

    for (int i=0; i<25; i++){
        fooptr = new foo();
        std::cout << fooptr << std::endl;
        delete fooptr;
    }
}
(c++ mit g++ -o foo foo.cpp kompileren)
Alle die nicht passen kann man verwerfen. Und übrig bleibt eine zufällige Zahlenfolge.
zufällige Folgen sind im rechner nicht möglcih, und über pseudozufallszahlen sind schon viele Artikel geschrieben worden, ich empfehle wirklich ienen Blick in die Bücher von DEK.
Ich habe übrigens eine neue Version von meinem Würfel. Ich habe den Tip von robi verwendet:
=====================================

Augenzahl = (rand() % 6); /* Augenzahl = {0,1,2,3,4,5} */
Augenzahl = Augenzahl +1; /* Augenzahl = {1,2,3,4,5,6} */
nimm doch bitte mal den Code-Block...

dann

Code: Alles auswählen

Zahl = (rand() % 6) +1;
ist noch kürzer ;)[/code]

Code: Alles auswählen

# to resolve all your problems, try this:
HOWTO='pack c5,41*2,sqrt 7056,unpack(c,H)-2,oct 115' && perl -le "print $HOWTO"
Ich beantworte keine Supportfragen per PM!
Benutzeravatar
spunti
Hacker
Hacker
Beiträge: 598
Registriert: 6. Mai 2004, 10:49

Beitrag von spunti »

An sich sehe ich das wie Texpert, wenn es eine bessere Möglichkeit für Zufallszahlen gäbe, hätte man das auch so implementiert.
Gut, der nimmt zum Initialisieren in Java also tatsächlich Milisekunden. Und ich werd es erst mal so lassen, denn es wird bald einen größeren Bereich geben aus dem Zufallszahlen ermittelt werden.

Auf jeden Fall sollte ich nicht immer ein neues random-Objekt erzeugen (ob tatsächlich ein neues erzeugt oder initialisiert wird, weiß ich gar nicht), sondern nur die Generierung mit nextInt wiederholen. Das sieht optisch schon mal etwas besser aus bilde ich mir ein:-)


@sparrow
Steht in dem Javabuch auch, warum das Beispiel da so angegeben wurde? (Also ob er die andere Art, ganze Zufallszahlen in einem Bereich zu erzeugen, nur nicht kennt oder da auch irgendwelche Schwächen ausgemacht hat? Ich hab hier Auflage 3 des Buches, da ist das Beispiel noch nicht drin.)
Mumie
Hacker
Hacker
Beiträge: 274
Registriert: 4. Jan 2005, 18:50
Wohnort: bei Hannover

Beitrag von Mumie »

Hallo TeXpert,
ich habe foo kompiliert. Wenn es läuft, kommt immer das gleiche Ergebnis:
0x804a008
0x804a008
0x804a008
und so weiter. Und das bei jedem Neustart. War das so geplant?

Ich habe noch eine Idee. Eine ganze Reihe von Dingen auf dem Computer werden ja vom Anwender "zufällig" verursacht. So auch der Wert, den eine bestimmte Adresse hat. Man könnte vielleicht eine "zufällige" Adresse nehmen. Und den Wert auslesen.
Ich finde das Thema Zufallszahlen sehr interessant. Ich werde trotzdem im Moment keine weiteren Bücher lesen. Auch nicht von DEK. Zuerst kommt der C-Kurs drann.

Viele Grüsse
Mumie
Benutzeravatar
TeXpert
Guru
Guru
Beiträge: 2166
Registriert: 17. Jan 2005, 11:22

Beitrag von TeXpert »

Mumie hat geschrieben:Hallo TeXpert,
ich habe foo kompiliert. Wenn es läuft, kommt immer das gleiche Ergebnis:
0x804a008
0x804a008
0x804a008
und so weiter. Und das bei jedem Neustart. War das so geplant?
genau :) und wenn Du jetzt noch überlegst was ich Dir damit sagen will ... (hint: nein, Zeiger sind nicht als Zufallsgenerator geeignet...)

Du siehst, die Speicheradresse liegt immer auf der gleichen Stelle. Jetzt nehmen wir ein kleines Speicherleck in Kauf:

Code: Alles auswählen

#include <iostream>

class foo {
  public:
   foo() : a(4), b(6) {};
  private:
   int a;
   int b;
};

int main() {

    foo *fooptr;
    foo *fooptr2;
    for (int i=0; i<25; i++){
        fooptr = new foo();
        std::cout << fooptr << std::endl;
        if (0==(i %2))
            delete fooptr;

    }
}
und löschen nur jeden 2. Zeiger Du siehst, dass die neuen Speicheradressen _sehr_ vorhersagbar sind.

Ich habe noch eine Idee. Eine ganze Reihe von Dingen auf dem Computer werden ja vom Anwender "zufällig" verursacht. So auch der Wert, den eine bestimmte Adresse hat. Man könnte vielleicht eine "zufällige" Adresse nehmen.
die Adressen werden fortlaufen vergeben... und wo nimmst Du die zufällige Adresse her?

Die einzige Möglichkeit ist den Menschen hinzuzunehmen, also z.B. einen ton über ein Mikro aufnehmen, oder wie es bei manchen Keygeneratoren gemacht wird, zufälliges Tippen (evtl. den Rythmus)... oder wilde Mausbewegungen...

das können aber allesnur Parameter für die Kongruenzfunktion sein, mit der dann der Generator arbeitet. Ad definitionem kann ein Computer nur Pseudozufallszahlen generieren, d.h. bei gleichen Parametern und gleichem Seed kommt die gleiche Folge raus (das ist sinnvoll beim Debuggen...)

Ich werde trotzdem im Moment keine weiteren Bücher lesen. Auch nicht von DEK. Zuerst kommt der C-Kurs drann.
:) sorry ich bin bei sowas erher der anderen Meinung, eine Programmier-Sprache lernt sich relativ schnell das größere Problem sind die zugrundeliegenden Algorithmen, wenn Du hier mit Pseudocode "programmieren" kannst ist der Transfer relativ einfach.

Code: Alles auswählen

# to resolve all your problems, try this:
HOWTO='pack c5,41*2,sqrt 7056,unpack(c,H)-2,oct 115' && perl -le "print $HOWTO"
Ich beantworte keine Supportfragen per PM!
Snubnose
Hacker
Hacker
Beiträge: 410
Registriert: 18. Feb 2004, 19:19
Wohnort: Schwabenland

Beitrag von Snubnose »

spunti, was meist du eigentlich mit 'nahezu immer gleich' ?
Mach mal ein Beispiel...

und poste am besten gleich mal deinen Code zu deinem Proggi
Benutzeravatar
spunti
Hacker
Hacker
Beiträge: 598
Registriert: 6. Mai 2004, 10:49

Beitrag von spunti »

Es geht jetzt und lag da ran:

"Auf jeden Fall sollte man NICHT immer ein neues random-Objekt erzeugen pro Zufallszahl."

(daneben hatte ich mich nat. auch noch selbst etwas ausgetrickst, so daß die letzte zahl seltener gefunden wurde)

spunti
Benutzeravatar
TeXpert
Guru
Guru
Beiträge: 2166
Registriert: 17. Jan 2005, 11:22

Beitrag von TeXpert »

spunti hat geschrieben:Es geht jetzt und lag da ran:

"Auf jeden Fall sollte man NICHT immer ein neues random-Objekt erzeugen pro Zufallszahl."
das ist doch klar ;) überleg mal wie ein Pseudorandomgenerator funktioniert:

:arrow: Init mit einem Wert X0
:arrow: Berechne Xn+1 durch Abbildungsvorschrift aus Xn

Wenn sich der Seed dann kaum Unterscheidet ist die erste Zufallszahl auch recht ähnlich

Code: Alles auswählen

# to resolve all your problems, try this:
HOWTO='pack c5,41*2,sqrt 7056,unpack(c,H)-2,oct 115' && perl -le "print $HOWTO"
Ich beantworte keine Supportfragen per PM!
Braslett
Newbie
Newbie
Beiträge: 4
Registriert: 16. Sep 2005, 09:58
Wohnort: Bielefeld

Beitrag von Braslett »

Man kann auch zwischen den 'nextInt(5)' zufällig lang rechnen mit z.B. 'nextInt(1000)' aus einem zweiten Random.

Braslett
Antworten