Problem mit rand()...



  • Hallo,

    habe hier ein Problem und würde mich freuen, wenn mir jemand helfen könnte.

    mein Vorahaben:

    für den TCP-Header benötige ich einen 4 Byte (32 bit) große positive Zufallszahl(Sequenznummer). Hier im Forum habe ich gelesen, dass rand() nur Zufallszahlen bis max 32767 (15 bit) generiert.
    Gibt es eine Alternative zu Rand, die es erlaubt 32bit große Zufallszahlen zu generieren oder muss ich mir das aus mehreren rand() selber zusammenschustern?

    Wie oben erwähnt, arbeite ich mit einer 4 Byte großen Sequenznummer. Ich empfange die Bytes der Sequenznummer einzeln (also 4 seperate Bytes (unsigned char)).
    Diese Sequenznummer muss ich dann erhöhen:

    **Was meint ihr, ist es sinnvoller die vier Byte der Sequenznummer zu einer Zahl zusammenfassen -> sie erhöhen -> und dann wieder in die 4 Byte aufzuteilen?

    Oder ist es sinnvoller die Bytes einzel zu lassen und mit "Überträge" zu arbeiten?**

    Freu mich über jeden Tipp, Info...
    vielen Dank im voraus Gruß
    Tupo13



  • 1. Ich wäre für selber schreiben (google mal nach Zufallszahlen, da gibt es bestimmt etwas passendes). Im Notfall kannst du dir die Zahl auch aus zwei rand()-Aufrufen zusammenbauen:

    lonq num=rand();
    num=num<<16+rand();
    

    2. Ich würde integer-Arithmetik verwenden (notfalls nimmst du eine union{long;char[4];} dafür).



  • bei 1.) kann man statt + auch | nehmen:

    #include <iostream>
    #include <ctime>
    #include <cmath>
    using namespace std;
    
    int rand32()
    {
        return (rand()<<16) | rand();
    }
    
    int main()
    {
        srand(time(0));
        cout << rand32() << endl;
        cin.get();
    }
    


  • @ CStoll
    @ Schorsch

    Danke für eure schnellen Antworten, werde es sofort ausprobieren

    Gruß Tupo13



  • Tupo13 schrieb:

    [b]Gibt es eine Alternative zu Rand, die es erlaubt 32bit große Zufallszahlen zu generieren

    ja. ich empfehle den multiply-with-carry-generator.

    oder muss ich mir das aus mehreren rand() selber zusammenschustern?

    geht auch. zeitkritisch dürfte bei dir ja nix sein.

    Oder ist es sinnvoller die Bytes einzel zu lassen und mit "Überträge" zu arbeiten?

    di erhöhst immer um 1? die wahrscheinlichkeit, einen übertrag zu kriegen, ist nur 1/256. also laß das zusammenfassen bleiben.



  • @ volkrad
    Danke, dein Tipp hört sich auch gut an werde mir es mal anschauen.

    Die Sequenznummer wird allerdings nicht um eins erhöht, sondern um die Anzahl der bereits gesendeten Bytes.
    (Da kommt es leider öfters zu überträgen)

    Gruß Tupo13



  • //multiply-with-carry prng
    //quelle
    //http://cliodhna.cop.uop.edu/~hetrick/na_faq.html
    //TODO: testen, ob alle seeds!=0 gute seeds sind
    class Random{
    private:
    	u64 x;
    public:
    	Random(u64 seed){
    		x=seed|(u64(1)<<32);
    	}
    	u32 operator()(){
    		x=1967773755*(x&0xffffffff)+(x>>32);
    		return x;
    	}
    };
    


  • Ok, danke euch - habe es jetzt mal vorerst so gelöst.

    Da es mit der 32bit Zufallszahl doch etwas kompilizierter (trotzdem vielen dank für die Lösungsvorschläge) ist habe ich pro Byte eine Zufallszahl errechnet.

    void CCommunikation::fGetInitSequezNr(u_char bytSeqNr[])
    {
    	srand(time(NULL));		// Initialisierung mit der aktuellen Zeit
    
    	for (int i=0; i<4; i++)
    	{	
    		bytSeqNr[i]=rand() % 255;
    	}
    }
    

    Das mit dem erhöhen habe ich so gelöst. Ist zwar nicht sonderlich schön, funktioniert aber:

    void CCommunikation::fAddSequenceNr(u_char bytSeqNr[],int nCountAddBytes)
    {
    
    int aiSeqNrBuffer[4];
    bool bBreakLoop = false;
    
    aiSeqNrBuffer[0]=bytSeqNr[0] + nCountAddBytes;
    
    do
    {
    
    // Byte 0
    if (aiSeqNrBuffer[0] > 255)
    {
    aiSeqNrBuffer[1]=bytSeqNr[1] + (aiSeqNrBuffer[0] / 0xff);
    aiSeqNrBuffer[0]=(aiSeqNrBuffer[0] % 0xff);
    bytSeqNr[0]=aiSeqNrBuffer[0];
    }
    else
    {
    bytSeqNr[0]=aiSeqNrBuffer[0];
    return;
    }
    
    // Byte 1
    if (aiSeqNrBuffer[1] > 255)
    {
    aiSeqNrBuffer[2]=bytSeqNr[2] + (aiSeqNrBuffer[1] / 0xff);
    aiSeqNrBuffer[1]=(aiSeqNrBuffer[1] % 0xff);
    bytSeqNr[1]=aiSeqNrBuffer[1];
    }
    else
    {
    bytSeqNr[1]=aiSeqNrBuffer[1];
    return;
    }
    
    // Byte 2
    if (aiSeqNrBuffer[2] > 255)
    {
    aiSeqNrBuffer[3]=bytSeqNr[3] + (aiSeqNrBuffer[2] / 0xff);
    aiSeqNrBuffer[2]=(aiSeqNrBuffer[2] % 0xff);
    bytSeqNr[2]=aiSeqNrBuffer[2];
    }
    else
    {
    bytSeqNr[2]=aiSeqNrBuffer[2];
    return;
    }
    
    // Byte 3
    if (aiSeqNrBuffer[3] > 255)
    {
    aiSeqNrBuffer[0]=bytSeqNr[0] + (aiSeqNrBuffer[3] / 0xff);
    aiSeqNrBuffer[3]=(aiSeqNrBuffer[3] % 0xff);
    bytSeqNr[3]=aiSeqNrBuffer[3];
    }
    else
    {
    bytSeqNr[3]=aiSeqNrBuffer[3];
    return;
    }
    
    // Byte 0
    if (aiSeqNrBuffer[0] > 255)
    {
    	bBreakLoop=true;
    }
    else
    {
    bytSeqNr[0]=aiSeqNrBuffer[0];
    return;
    }
    
    }while (!bBreakLoop);
    
    }
    

    Falls jemand noch einen Tipp... hat wie man das ganze besser Lösen, Strukturieren kann - würde mich freuen

    Gruß Tupo13



  • Tupo13 schrieb:

    Falls jemand noch einen Tipp... hat wie man das ganze besser Lösen, Strukturieren kann - würde mich freuen

    srand(time(NULL));
    darfst nur einmal machen, am besten am anfang der main(). sonst bringt's nix.



  • Tupo13 schrieb:

    Falls jemand noch einen Tipp... hat wie man das ganze besser Lösen, Strukturieren kann - würde mich freuen

    Hallo Tupo,

    Wenn das so ist:

    Tupo13 schrieb:

    Die Sequenznummer wird allerdings nicht um eins erhöht, sondern um die Anzahl der bereits gesendeten Bytes.

    dann darfst Du nicht durch 0xff teilen sondern durch 0x100. Denn jedes u_char kann 0x100 Zahlenwerte darstellen - die 0 zählt mit.
    Weiter kannst Du die 4 identischen Programm-Stücke in eine Schleife stecken. Das Array 'int aiSeqNrBuffer[4];' benötigst Du nicht, die Ergebnisse werden später nicht wieder verwendet.

    Alles zusammen könnte Dein Code so aussehen:

    void CCommunikation::fAddSequenceNr( u_char bytSeqNr[],int nCountAddBytes )
    {
        for( int i = 0 ; i<4; ++i )
        {
            nCountAddBytes += bytSeqNr[i];
            bytSeqNr[i] = u_char( nCountAddBytes % 0x100 );
            nCountAddBytes /= 0x100;
        }
    }
    

    Die äußere Schleife habe ich jetzt einfach weggelassen. Angenommen in bytSeqNr[] steht der Wert { 0xff, 0xff, 0xff } und 'nCountAddBytes' sei gleich 2; soll dann der neuen bytSeqNr[] { 0x01, 0, 0, 0 } sein oder { 0x02, 0, 0,0 }? Ich meine, ersteres ist sinnvoll.

    Weiter kannst Du nochmal überlegen, ob das eine Methode von CCommunikation sein muss; es werden keine Member geschrieben oder gelesen. Eine Funktion würde also reichen.

    Zum Thema Zufallszahlen sollte man noch diesen Link beachten http://www.boost.org/libs/random/index.html

    Gruß
    Werner



  • rand() generiert Zufallszahlen bis RAND_MAX, das ist je nach System unterschiedlich. Gängig sind im Moment 2^31 - 1, auf uralten Systemen 2^15 - 1.

    Wo das nicht reicht, schau dir mal http://www.boost.org/libs/random/index.html an, da gibts Zufallszahlengeneratoren in allen Farben, Formen und Variationen.


Anmelden zum Antworten