# Gleichverteilte Zufallsdoubles erstellen.



## rookeenator (7. Nov 2006)

Hi,

ich muss per Zufall doubles generieren zwischen einer Ober- und einer Untergrenze.
Das mache ich zur Zeit wie folgt:

double d = (obereSchranke - untereSchranke) * Math.random() + untereSchranke;

Das funktioniert auch wunderbar. Allerdings nicht für große Schranken.

Angenommen es gilt:
obereSchranke = Double.MAX_VALUE;
untereSchranke = -Double.MAX_VALUE;

Dabei kommen nur riesig-große oder riesig-kleine Werte raus, wobei allerdings auch mal zBsp. 10 oder 0 rauskommen sollte. Das Ergebnis ist also auf gar keinen Fall gleichverteilt!
Das liegt daran, dass Math.random() zwar eine Zahl zwischen 0 und 1 liefert, allerdings ist diese nie "sehr" nah an 1 oder "sehr" nah an 0, sodass diese Zufallszahl keinen wirklichen Einfluss auf den "extremen" Wert in der Klammer hat.
Es kommen ausschliesslich Zahlen der Größenordnung (+/-)10^306 bis (+/-)10^307 heraus, was ja sehr nah an den MAX_VALUE's liegt (10^308).

Gibt es eine Möglichkeit in diesem Wertebereich wirklich gleichverteilte doubles zu erhalten??? Gibt es irgendwelche Generatoren die das wirklich drauf haben? Bzw eine Idee/Vorschlag wie man das mathematisch machen könnte?
Das RNGPack zbsp (http://www.honeylocust.com/RngPack/) scheint das selbe Problem zu haben.

Gruß,
rookeenator


----------



## Wildcard (7. Nov 2006)

Bei deinem 





> extremen" Wert in der Klammer


 kommt für diese Werte 0 raus.  :toll:  :autsch:


----------



## kaie (7. Nov 2006)

Was soll denn Deiner Meinung nach bei Double.MAX_VALUE-(-Double.MAX_VALUE) rauskommen? 2*Double.MAX_VALUE? Was meinst Du, wofür das MAX in MAX_VALUE steht? Bei mir kommt (wie nicht anders erwartet) einfach INFINITY raus - egal, welchen Wert Math.random() liefert...

Vielleicht solltest aus praktischen Überlegungen bei einem Wertebereich bleiben, der nicht die Anzahl der Atome im Universum um einige Hundert Zehnerpotenzen übersteigt...


----------



## rookeenator (7. Nov 2006)

Ja klar, sorry war mein Fehler. Die Berechnung sähe so aus:
double d = ((obereSchranke/2 - untereSchranke/2) * Math.random() + untereSchranke/2) * 2;
Womit das INFINITY-Problem gelöst ist, und ansonsten "richtige" Werte geliefert werden.

Im Moment verwende ich den o.g. RandomGenerator dem ich einfach meine beiden "großen" Schranken übergebe. Dort gibt es allerdings wie gesagt das selbe Problem. Die Formel oben soll also nur zur Illustration des Problems herhalten.

Einfach den Wertebereich weiter einschränken geht leider nicht, da ich auf Zufallszahlen aus diesem riesigen Wertebereich angewiesen bin.

Irgendwelche Ideen?


----------



## SlaterB (7. Nov 2006)

wenn du Random nicht vertraust, dann bau das dir das ganze selber,
anschaulicher aus einfacheren Zufallszahlen:

dann lasse dir 30x eine Zufallszahl von (1 bis einschießlich 10.000.000.000) -1 
oder ähnlich ausgeben (die -1 um auch die 0 zu bekommen),

diese 30 Zahlen füge zusammen, also:
30.ste Zahl + 29.Zahl * 10^10 + ..

dann hast du eine tolle Gleichverteilung

-----------

damit nun eine Zahl wie 5 rauskommt,
muss übrigens der kleine Zufallsalgorithmus 29x 0 ausgeben,
die Wahrscheinlichkeit dazu ist 
(1 zu 10 Milliarden) ^30 oder so 
wenn du eine solche Zahl triffst, dann Hut ab,

-----------

hast du vielleicht eine andere Vorstellung von Gleichverteilung?,
z.B. Gleichverteilung des Exponenten von 0 bis 300?


----------



## kaie (7. Nov 2006)

Dein Ergebnis ist vollkommen korrekt, Deine Zahlen SIND tatsächlich gleichverteilt. Du deutest die Ergebnisse nur falsch!

Hier ein Programm, dass ein paar Verteilungen mit jeweils 10000 Werten erwürfelt und davon je ein Histogramm (mit 10 Unterteilungen) erstellt:

```
public class Zufall
{
	public static int[] verteilung( double min, double max )
	{
		int[] n = new int[10];
		for( int i=0; i<10000; i++ )
		{
			double z = (max-min)*Math.random()+min;
			n[(int)((z/10000-min/10000)*10/(max/10000-min/10000))]++;
		}
		return n;
	}
	
	public static void ausgabe( int[] n )
	{
		for( int i=0; i<n.length; i++ )
		{
			System.out.print( n[i]/100+"%\t" );
		}
		System.out.println();
	}
	
	public static void main( String[] args )
	{
		ausgabe( verteilung(0,10) );
		ausgabe( verteilung(0,10000) );
		ausgabe( verteilung(-10000,10000) );
		ausgabe( verteilung(-Double.MAX_VALUE/2,Double.MAX_VALUE/2) );
	}
}
```
Es können bei Dir durchaus Werte von 5 oder -12 oder so erwürfelt werden; die Wahrscheinlichkeit dafür beträgt nur leider etwas um die 1/(2^300), was in etwa dem Kehrwert eines Gogols entsprechen dürfte! Also: SEEEEEEEEHR unwahrscheinlich!


----------



## SnooP (7. Nov 2006)

Da fragt sich noch... - wer oder was ist Gogol?


----------



## kaie (7. Nov 2006)

Sorry, meinte natürlich Googol: http://de.wikipedia.org/wiki/Googol


----------



## SlaterB (7. Nov 2006)

wenn man es ein bisschen genauer nimmt ist es aber eher in der Region 10^300 oder?
nicht dass es drauf ankäme


----------



## rookeenator (7. Nov 2006)

Danke für die vielen Antworten... nun ja, also scheint es ja doch so in Ordnung zu sein. Allerdings bräuchte ich schon öfter mal Punkte in "günstigeren" Größenordnungen.

Was denkt Ihr über das folgende Beispiel (RanMT ist eine Klasse des o.g. Packs):

```
RanMT r = new RanMT(seed);
double d = r.uniform(-10, 10) * Math.pow(10, r.uniform(0,307));
```

Das liefert mir jedenfalls brauchbarere Ergebnisse. Die Frage ist nun ob das ganze auch annähernd gleichverteilt ist. Für die 0 gillt das auf jeden Fall nicht, da diese wahrscheinlicher ist, als alle anderen Zahlen - das wäre allerdings nicht ganz so tragisch, wenn der Rest wenigstens ungefähr gleichwahrscheinlich ist. Hat für mich erstmal so den Anschein.
Oder übersehe ich da jetzt etwas Kritisches?

PS: Die Rechnung oben mit dem Halbieren der Schranken und dem anschließenden Verdoppeln des Ergebnisses ist übrigens falsch, da so ja nur gerade Zahlen generiert werden.  :applaus:


----------



## SlaterB (7. Nov 2006)

bevor du an Algorithmen und deren Beurteilung denkst,
überlege lieber erstmal ganz genau, welche Zahlen du in welcher Verteilung haben möchtest,

0,1,2,..,9,10,20,30,..100,200,300,..?

bis wohin geht das ganze?
wenn du die Gesamtzahl aller Zahlen hast, z.B. 6000 und die gleichverteilt sein sollen,
dann mach folgendes: mit Wahrscheinlichkeit 1/6000 ist es 0,
ansonsten Zufallszahl 1-9, Zufallsexponent 0-307, Zufallsvorzeichen + oder -


----------



## rookeenator (4. Dez 2006)

SlaterB hat gesagt.:
			
		

> bevor du an Algorithmen und deren Beurteilung denkst,
> überlege lieber erstmal ganz genau, welche Zahlen du in welcher Verteilung haben möchtest,
> 
> 0,1,2,..,9,10,20,30,..100,200,300,..?
> ...




Schon etwas alt das Thema mittlerweile aber vielleicht noch ein paar Worte dazu:
So wie Du das vorgeschlagen hast, dachte ich es mir eben auch - allerdings ist das definitiv nicht gleichverteilt, weil alle Zahlen mit Exponent n genauso wahrscheinlich sind, wie alle Zahlen mit Exponent n+1. Letzterer hat allerdings 10-mal so viele Zahlen, somit ist für diese Zahlen die Wahrscheinlichkeit geringer. Man erhält auf diese Weise eine eckige oder stufenförmige Normalverteilung!
Mein Problem lässt sich also gar nicht lösen: Entweder ich verwende eine Normalverteilung oder ich habe Pech gehabt und muss mit den großen Zahlen leben!   

Viele Grüße...


----------

