random float



  • Ermittel Dir mit rand() einfach zwei Integer-Werte, dividiere sie durcheinander, und Du hast einen float - Wert.



  • 4 Byte-Zahl ( Vorzeichen, Mantisse ) und Exponenten getrennt erzeugen,
    dann den Exponenten ( -125...128 ) in die Zahl einfügen, könnte es so gehen?



  • Naja, so schlecht war die Ursprungsidee gar nicht, Vor- und Nachkommateil getrennt zu erzeugen:

    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    
    float GiveMeFloat()
    {
    	float f, tmp;
    
    	f = rand();
    	tmp = rand();
    	f = f + tmp / log10(tmp);
    
    	return f;
    }
    
    int main()
    {
    	int i;
    
    	srand (time(NULL));
    
    	for(i = 0; i < 10; ++i)	
    	{
    		printf("Mein Zufallsfloat ist %f\n", GiveMeFloat());
    	}
    }
    


  • @belli

    danke für die hilfe, aber leider ist das hauptproblem noch immer nicht gelöst:
    die floats sollen auch wirklich den gesamten wertebereich
    (1.2E-38 bis 3.4E+38) bzw. FLT_MIN bis FLT_MAX aus <float.h> abdecken.
    außerdem sollten die zufallszahlen über den bereich gleichmäßig verteilt sein.

    mfg Christoph



  • Wenn Dir egal ist, wie die Zahlen entstehen (Du schriebst ja, dir soll jemand fertige Zahlen hochladen), dann nimm doch meinen C++-Code von oben, ersetze die Grenzen durch FLT_MIN und FLT_MAX, jage das ganze durch den Compiler und fertig.

    Oder nimm eine Skriptsprache wo das ganze schon eingebaut ist. Z.B. Python.

    Wenn Du trotzdem eine gute Lösung in C habe willst und unbedingt alles von FLT_MIN bis FLT_MAX abgedeckt haben willst, dann musst Du Dir die Arbeit machen und dich um eine Bibliothek bemühen.



  • Okay, eine Idee hätte ich noch:
    Mach eine UNION aus einem float und einem int -- die belegen beide 32 Bit. Nun ermittel 32 Zufallszahlen zwischen 0 und 1 und weise sie den einzelnen Bits zu. So sollten eigentlich alle möglichen floats erzeugt werden können.



  • Hallo,

    Danke für die gute Idee.
    Leider bin ich in C noch nicht wirklich gut.
    Ich kann zwar die einzelnen "bits" (zufalls01) erzeugen, weiß aber nicht wie ich die beschriebene "union" codiere. kannst du mir ein beispiel geben?!

    mfg Christoph



  • Damit läufst du gefahr, ungültige floats zu erzeugen, weil der Exponent nicht kleiner als -125 sein darf. Daher meine Idee, den Exponenten getrennt zu erzeugen.



  • Also, ich habe mir das in etwa so vorgestellt:

    // Erzeugt eine zufällige 32 Bit Integer Zahl
    unsigned random_integer32bit ()
    {
    	unsigned num = 0;
    	int i;
    
    	for ( i=0; i<32; i++ )
    	{
    		num <<= 1;
    	 	if ( rand() % 2 ) 
    			num |= 1;
    	}
    	return num;
    }
    
    // Liefert einen zufälligen Exponenten von FLT_MIN_EXP bis FLT_MAX_EXP 
    // FLT_MIN_EXP -125
    // FLT_MAX_EXP 128 
    signed char random_exponent () 
    {
    	float r = FLT_MAX_EXP - FLT_MIN_EXP; 
    	return (signed char) ( FLT_MIN_EXP + (int)(r * rand()/(RAND_MAX))) ; 
    }
    
    int main ( )
    {
    	int i;
    	unsigned num, exp;
    	float fnum = -FLT_MAX;
    
    	//memcpy(&num, &fnum, 4);
    	//bin_view(num);
    	srand( (unsigned)time(NULL) );
    
    	// 4 Byte Zufallszahl erzeugen.
    	num = random_integer32bit ();
    	// Zufallszahl könnte NaN sein, wenn Exponent < -125
    	// Exponenten 0 setzen, UND-verknüpfen mit der Zahl
    	// 0x807FFFFF hex =  10000000011111111111111111111111 bin
    	num &= 0x807FFFFF;
    
    	// Zufälligen Exponenten im Bereich -125 ... 128 erzeugen.	
    	exp = random_exponent ();
    
    	// Exponent ist in der Form
    	// 000000000000000000000000xxxxxxxx
    	// Exponenten um 23 Bit nach links verschieben
    	exp <<= 23;
    	// Jetzt sollte der Exponent an der richtigen Position sein
    	// 0xxxxxxxx00000000000000000000000
    
    	// Überflüssige FFs entfernen
    	exp &= 0x7F800000;
    	//	0x7F800000 hex =  01111111100000000000000000000000 bin
    
    	// Exponenten in die Zahl per ODER-Verknüpfung einfügen.
    	num = num|exp;
    	// Die float-Version ist fertig.
    	memcpy( &fnum, &num, sizeof(float));
    
    	printf("%f\n", fnum );
    
    	return 0;
    }
    

    Das Dingen erzeugt auch negative Werte. Wenn du nur positive willst, setze das MSB auf 0.
    Auf manchen Maschinen ist RAND_MAX laut http://mail.gnome.org/archives/gtk-devel-list/2000-February/msg00219.html 2^32-1 groß.
    In dem Fall vereinfacht sich die Funktion random_integer32bit auf einen rand() Aufruf.



  • Hallo,

    Ich hab jetzt einfach mittels bitshift 32bit in einem integer zufällig gesetzt.
    jetzt möchte ich die adresse des int auf einem float zuweisen.
    Leider funktioniert das nicht so wie ich mir das vorstelle:

    int main()
    {
    	srand(time(NULL));
    	char bit;
    	int x,i;
    	float*f;
    
    	for(bit=0,x=0,i=0;i<32;i++)
    	{
    	bit=rand()%2;
    	x|=bit<<i;
    	}
    	f=&x; //Hier möchte ich, dass f die selbe Adresse wie x erhält
    	return 0;
    }
    


  • Mhm, ja, das ist ja so ähnlich, wie ich es mit der UNION vorgeschlagen hatte ...
    Was genau funktioniert denn nicht?
    Wenn Du ungültige Werte bekommst, kann das evtl. daran liegen, daß es Bitmuster gibt, die kein gültiges float sind, wie mathematikpraktikant sagte ...
    Mir war das gar nicht klar; ich war davon ausgegangen, daß alle Bitmuster erlaubt sind, und jeweils einen float - Wert repräsentieren.



  • Ich habs jetzt auch mal so probiert, das Ergebnis sieht erst mal ganz gut aus:

    #include <stdio.h>
    #include <time.h>
    #include <stdlib.h>
    
    union convert
    {
    	int i;
    	float f;
    };
    
    int main()
    {
    	int i;
    	union convert c;
    	srand(time(0));
    
    	for(i = 0; i < 10; ++i)
    	{
    		c.i = rand();
    		c.i = c.i << 16;
    		c.i = c.i + rand();
    		printf("Int = %d Float = %e\n", c.i, c.f);
    	}
    }
    

    Ein Problem ist, daß der größte von rand() erzeugte Wert (32767) auf meinem System immer eine 0 im MSB hat. Dieses Bit müsste man also jeweils noch einmal gesondert ermitteln/setzen.
    Ein anderes Problem ist wie erwähnt, daß ich nicht weiß, ob es auch ungültige Bitmuster gibt, die dann keinen gültigen float-Wert repräsentieren.



  • Hier wären nun alle Bits drin, wenn ich mich nicht irre:

    for(i = 0; i < 10; ++i)
    	{
    		c.i = rand();
    		c.i = c.i << 17;
    		c.i = c.i | (rand() << 1);
    		c.i = c.i | (rand() % 2);
    		printf("Int = %d Float = %e\n", c.i, c.f);
    	}
    


  • Belli schrieb:

    Ein anderes Problem ist wie erwähnt, daß ich nicht weiß, ob es auch ungültige Bitmuster gibt, die dann keinen gültigen float-Wert repräsentieren.

    Ein NaN ( not a number ) ist keine Zahl. Die Bitmuster von NaN stecken in den 4 Byte des float-Typen mit drin.



  • Ja, schon klar, aber wo? Soweit ich bisher durch Ausprobieren (und Wikipedia-Lesen) festgestellt habe, ist ein Wert untauglich, wenn der Exponent 255 ist. Wenn das tatsächlich die einzige untaugliche Kombination sein sollte, könnte man bei Auftreten zufällig eines der 8 Bits (des Exponenten) wieder löschen und hätte dann wieder einen float ...



  • Hallo,

    Bei deinem Code erhalte ich das gleiche Ergebnis wie bei meinem:
    Es werden zwar (haupsächlich) gültige floats ausgegeben.
    Leider stimmt aber die verteilung nicht.
    man müsste die bits im exponententeil so setzen. Dass die exponenten im verhältnis 10:1 zum vorigen auftreten:
    e038 soll 10 mal häufiger auftreten als e037 und 100mal öfter als e036

    mein ansatz wäre dafür:

    #include <stdio.h>
    #include <time.h>
    #include <stdlib.h>
    #include <math.h>
    
    int main()
    {
    	srand(time(NULL));
    	char bit,bitr;
    	int x,i,j,k,l;
    	float*f;
    
    	for(x=0,i=0;i<5;i++)
    	{
    		bit=rand()%2;
    		x|=bit<<31;
    		for(bit=0,j=0,k=7;j<8;j++,k--)
    		{
    			for(bit=0,l=0;l<pow(2,k);l++) 
    //rand() muss 2^k mal 0 sein damit das bit auch 0 gesetzt wir
    			{
    				bitr=rand()%2;
    				if(bitr==1)
    					bit=1;
    			}
    				x|=bit<<(j+22);
    		}
    		for(j=0;j<23;j++)
    				{
    					bit=rand()%2;
    					x|=bit<<j;
    				}
    		f=&x;
    		printf("%f\n",*f);
    	}
    	return 0;
    }
    

    ich hab also nur die bits logarithmiert (bit8 wird 2^8 mal öfter gesetzt als bit1)
    das müsste man jetzt aber eben so umformen, dass es nicht für die einzelnen bits, sondern für die codierten dezimalzahlen gilt.

    Ich hoffe das war nicht zu verwirrend.

    mfg Christoph



  • Belli schrieb:

    Ja, schon klar, aber wo? Soweit ich bisher durch Ausprobieren (und Wikipedia-Lesen) festgestellt habe, ist ein Wert untauglich, wenn der Exponent 255 ist. Wenn das tatsächlich die einzige untaugliche Kombination sein sollte, könnte man bei Auftreten zufällig eines der 8 Bits (des Exponenten) wieder löschen und hätte dann wieder einen float ...

    Also hier weiter unten
    http://de.wikipedia.org/wiki/NaN
    steht, das es 223 NaNs gibt 😮



  • mathematikpraktikant schrieb:

    Also hier weiter unten
    http://de.wikipedia.org/wiki/NaN
    steht, das es 223 NaNs gibt 😮

    Tja, dann weiß ich auch nicht mehr weiter. Bisher bin ich davon ausgegangen, daß alle Werte mit 0xFF im Exponenten NaN sind, das müssten dann aber meiner Meinung 224 sein ... 😕
    @Symbian:
    Also die bei mir bisher auftretenden ungültigen floats konnte ich wie beschrieben dadurch 'reparieren', daß ich ein zufällig gewähltes Bit aus dem Exponenten gelöscht habe.
    Wie das nun mit der Verteilung aussieht, da bin ich völlig überfragt, das wird mir zu mathematisch.
    Ich kann mir nicht vorstellen, wie ich einerseits auf die Verteilung Einfluss nehmen soll, andererseits aber von rand() gelieferte Zufallswerte verwenden soll.
    Sorry, aber hier ist mein Latein zu Ende.


Anmelden zum Antworten