Resource icon

Zufallszahlen mit rand() erzeugen und Limit von 32767 umgehen

Programmiersprache(n)
c c++
Betriebssystem(e)
Linux, Windows
Hallo Leute!

Habt Ihr euch schon mal gefragt, wie man die Begrenzung bei der Funktion rand() die bei
manchen Compilern und Betriebssystemen bei 32767 liegt umgeht?

Früher, als ich noch mit MSDOS, Win95, Win98SE, Win2000prf, Windows XP, Windows 7 64 Bit
arbeite hatte ich dieses Problem auch. Aus Kostengründen standen mir für meine ersten
Gehversuche in der Sprache c der Shareware-Compiler Symantec C 6.11 dann QC 25, später
MSVC 1.52, dann MSVC 2.0 zur Verfügung. Mit Borland konnte ich mich damals nicht so
sehr anfreunden, obwohl diese sehr interessante Funktionen wie intr hatten, was die Implementierung
einiger Assembler-Codes erleichterte. Der große Bruder des Shareware-Compilers 6.11, mit Namen
Symantec C++ 7.0 der in einer 16-Bit und in einer 32-Bit-Version zu haben war (ab März 1995)
konnte ich mir damals nicht leisten.

Später nach dem Wechsel auf SUSE Linux hatte ich diese Probleme nicht mehr.

Bevor nun meine alten Arbeiten irgendwo verstauben, möchte ich diese veröffentlichen.

Die größte Zahl welche mit rand() möglich ist, wird mit RAND_MAX begrenzt.
Bei einigen Compilern ist RAND_MAX auf 32767 gesetzt.

Um für mein Verschlüsselungsprogramm Talarius die Zahl der Permutationen zu erhöhen,
entwickelte ich zunächst folgende Lösung:
Code:
int randinitcount = 0;

int getrandom( int min, int max)
{
int zuza, zuza2, zuza3, rewer;
zuza  = rand();
zuza2 = (max - min + 1);
zuza3 = zuza % zuza2;
rewer = zuza3 + min;
return rewer;
}


long getlongrand(long min, long max)
{
long rewer = 0, rest, bereichsfeld;
int bereich, limit = 32767;

bereichsfeld = max / 32767;

bereich = getrandom((int)min, (int)bereichsfeld);
if (bereich > 1) rewer = 32767 * (long)bereich;
rest = max - rewer;
if (rest < 32767) limit = (int)rest;

  rewer += (long)getrandom(0, limit);

return(rewer);
}


void RANDOMIZE(void)
{
long bwer;
srand( (unsigned)(time(&bwer) % 20));
if (randinitcount < 2)
randinitcount++;
}
Damit konnte ich im Versuch eine Zahlenreihe von 0 bis 1048575 (=1048576 Faktorielle)
permutieren. Dieses Versuchsprogramm hier später.
Zunächst aber die Zeiten, welche bei der Permutierung (nur ein Durchgang!) nötig waren:

Faktorielle.............benötigte Zeit
65536.....................10 Sekunden
131072...................33 Sekunden
262144...................2 Minuten, 14 Sekunden
524288...................9 Minuten, 20 Sekunden
1048576.................37 Minuten 0 Sekunden

Der Verlauf der benötigten Zeit ist also exponentiell. Lasst es also lieber gleich sein und versucht
es erst gar nicht mit 2097152 oder höher.

Die hier aufgeführte Version der selbst geschriebenen Funktion getlongrand() lieferte als einzige
die richtigen Ergebnisse bei der Permutierung der Zahlenzeihen.

Nun wie versprochen das Versuchsprogramm:
Zunächst der Header random.h:
Code:
/**-------------------random.h des Versuchsprogramms----------------------------------------------------------------*/
#ifndef RANDOM_H_INCLUDED
#define RANDOM_H_INCLUDED

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <malloc.h>
#include <termios.h> /** wegen getch() */
#include <unistd.h>   /** wegen getch() */

#ifndef BIG
#define BIG 10
  #if BIG == 10
   #define BITLIMIT  (long)1048576
  #endif
  #if BIG == 9
   #define BITLIMIT  (long)524288
  #endif
  #if BIG == 8
   #define BITLIMIT  (long)262144
  #endif
  #if BIG == 7
   #define BITLIMIT  (long)131072
  #endif
  #if BIG == 6
   #define BITLIMIT  (long)65536
  #endif
  #if BIG == 5
   #define BITLIMIT  (long)32768
  #endif
  #if BIG == 4
   #define BITLIMIT  (long)16384
  #endif
  #if BIG == 3
   #define BITLIMIT  8192
  #endif
  #if BIG == 2
   #define BITLIMIT  4096
  #endif
  #if BIG == 1
   #define BITLIMIT  2048
  #endif
  #if BIG == 0
   #define BITLIMIT  256
  #endif
  #define BYTELIMIT BITLIMIT / 8
#endif


int getrandom( int min, int max);
long getlongrand(long min, long max);
void RANDOMIZE(void);
int setranval(unsigned int (*wert)[300], int wertebereich);
long TellyDec(long wert[], long grenze, long (*quersumme), long (*tstwrt) );
int SetRanValNoLimit (long *wert[]);
int getch();
void ShowReihe(long wert[], long anzahl);


#endif // RANDOM_H_INCLUDED


/** selbstgeschriebener Header random.h fuer die Funktion random und
* getrandom . Wenn RANDOMIZE verwendet wird, wird bei einer
* Schleifenanweisung zur Erzeugung von Zufallsdatenfeldern diese
* Anweisung nur einmal benoetigt, sonst werden immer die gleichen Zahlen
* erzeugt
* Beispiel:
* #include <random.h>
* void setranval(int (*wert)[16])
* {
* int sleia, sleib;
* for (sleia = 0; sleia <= 15; sleia++)
*  {
*   numal: (*wert)[sleia] = getrandom( 0, 15 );
*         if (sleia > 0)
*          for (sleib = 0 ; sleib <= (sleia - 1); sleib++)
*         if ((*wert)[sleib] == (*wert)[sleia])
*          goto numal;
*  }
*
* }
*
* void main(void)
* {
* int sleia, sleib, zuzko[16], zko[16];
* RANDOMIZE();
* for (sleib = 0; sleib  <= 15; sleib++)
*  {
*  setranval(&zuzko);
*  printf("\n");
*   for (sleia = 0; sleia <= 15; sleia++)
*    printf("%d ", (zuzko)[sleia]);
*  }
* }
* ----------------------------------------------------------- Beispielende---Ende Header Versuchsprogramm-------------------------------------- */
nun die dazugehörige Dabei random.c:
Code:
/**----------------Beginn random.c des Versuchsprogramms--------------------------------------*/
#include "random.h"

/** dient zur Überprüfung, ob RANDOMIZE mehr als einmal
  * bei Programmablauf aufgerufen wurde  */
int randinitcount = 0;



/// reads from keypress, doesn't echo
int getch(){
    struct termios oldt, newt;
    int ch;
    tcgetattr( STDIN_FILENO, &oldt );
    newt = oldt;
    newt.c_lflag &= ~( ICANON | ECHO );
    tcsetattr( STDIN_FILENO, TCSANOW, &newt );
    ch = getchar();
    tcsetattr( STDIN_FILENO, TCSANOW, &oldt );
    return ch;
}

int getrandom( int min, int max)
{
int zuza, zuza2, zuza3, rewer;
zuza  = rand();
zuza2 = (max - min + 1);
zuza3 = zuza % zuza2;
rewer = zuza3 + min;
return rewer;
}

long getlongrand(long min, long max)
{
long rewer = 0, rest, bereichsfeld;
int bereich, limit = 32767;

bereichsfeld = max / 32767;

bereich = getrandom((int)min, (int)bereichsfeld);
if (bereich > 1) rewer = 32767 * (long)bereich;
rest = max - rewer;
if (rest < 32767) limit = (int)rest;

  rewer += (long)getrandom(0, limit);

return(rewer);
}

/*
long getlongrand(long min, long max)
{
long rewer = 0;

union zufallsnummer
{
  unsigned int intzu[2];
  unsigned long longzu;
}zunum;

if (max > 65535)
  {
   zunum.intzu[0] = getrandom(0, 65535);
   zunum.intzu[1] = getrandom(0, 65535);
  }
   else  zunum.longzu = getrandom(0, 65535);

   rewer = (long)zunum.longzu;

return(rewer);
}
*/

#define random(max ) getrandom(0, max)

void RANDOMIZE(void)
{
long bwer;
srand( (unsigned)(time(&bwer) % 20));
if (randinitcount < 2)
randinitcount++;
}

/* Rückgabewert ist der tatsächlich verwendete Wertebereich (Parameter 2)
* Aufruf Parameter 1: &Arrayname  */

int setranval(unsigned int (*wert)[300], int wertebereich)
{
int maxi = 255;  /* Legt den Arbeitsbereich von 0 bis 255 fest */
int slei, a, sleia,  zuze, maxgre, szahl, zahl, fiwer[300], zuza[300];
if ((wertebereich <= 255) && (wertebereich >1))
maxi = wertebereich;
zuze = 0;
maxgre = maxi;
/* Initialisieren des Arrays "fiwer" mit Werten von 0 bis 255 */
for (slei = 0; slei <= maxi; slei++)
fiwer[slei] = slei;
/** Aufruf von RANDOMIZE nur einmal bei Programmablauf, sonst
  * kommen pro "Würfelrunde" immer nur die gleichen Zahlen  */
if (randinitcount == 0)
{
RANDOMIZE();
randinitcount++;
}
for (a = 0; a <= maxgre; a++)
{
  szahl =  getrandom( 0, maxi);   /* generiert Zufallszahl "szahl" von 0 bis maxi  */
  zahl = fiwer[szahl];

   for (sleia = 0; sleia <= maxi; sleia++)
    if (fiwer[sleia] == zahl)
    {
      --maxi;
      for (slei = sleia; slei <= maxi; slei++)  fiwer[slei] = fiwer[slei + 1];
       zuza[zuze] = zahl;
      ++zuze;
     }
}

/* Übertrag der Werte des lokalen Arrays zuza in das Array wert */
for (slei = 0; slei <= maxgre; slei++)
(*wert)[slei] = zuza[slei];

return(maxgre);
}

/* Ueberprueft ob die Permutationsreihe fehlerfrei ist.
* Aufruf: Differenz_bei_Fehler =  TellyDec(long_huge_array, Arraygroesse, &Pruefsumme), &Istwert);
*
*/
long TellyDec(long wert[], long grenze, long (*quersumme), long (*tstwrt) )
{
long slei, rewer = 0;
(*tstwrt) = (*quersumme) = 0;

for (slei = 0; slei < grenze; slei++)
{
  (*quersumme) += slei;     //printf("\nquersumme%ld tstwert[slei]%ld", quersumme, tstwrt);
  (*tstwrt)    += wert[slei];  //printf("\ntstwrt%ld wert[slei]%ld", tstwrt, wert[slei]);
}

rewer = (*quersumme) - (*tstwrt);

return(rewer);
}

/** Im Gegensatz zu WORD-Variante muss die DWORD-Variante mit nur 2 Arrays
* auskommen. Diese muessen  von Aussen erst mit "halloc" Allokiert werden.
* Parameter eins ist dabei das Array, indem das Ergebnis nach abarbeiten
* der Funktion stehen soll. Parameter 2 ist dabei das Hilfsarray.
* Die Groesse der Arrays muß explizit in Parameter 3 angeben werden
* Aufruf: Arraygroesse-1 =  SetRanValNoLimit(ErgebnisArray, Hilfsarray, Groesse_der_einzelnen_Arrays )
*/
int SetRanValNoLimit (long *wert[])
{
int rewer;
long maxi = BITLIMIT - 1;  /** Legt den Arbeitsbereichfest */
long slei, a, sleia,  zuze, szahl, zahl;
long *zuza, *fiwer;
zuze = 0;
fiwer  = (long *)malloc(((BITLIMIT + 10) * sizeof(long))  );
if (fiwer == 0)
{
  rewer = -1;
  return rewer;
}
zuza  = (long *)malloc(((BITLIMIT + 10) * sizeof(long))  );
if (fiwer == 0)
{
  rewer = -2;
  return rewer;
}
/** Initialisieren des Arrays "fiwer" mit Werten */
printf("Hilfsarreale allokiert\n");

for (slei = 0; slei <= BITLIMIT; slei++)
{
fiwer[slei] = slei;
//printf("\n %ld ", slei);
}
printf("Arreal fiwer initialisiert\n");

/** Aufruf von RANDOMIZE nur einmal bei Programmablauf, sonst
  * kommen pro "Würfelrunde" immer nur die gleichen Zahlen  */
if (randinitcount == 0)
{
RANDOMIZE();
randinitcount++;
}

for (a = 0; a < BITLIMIT; a++)
{
  szahl =  getlongrand( 0, maxi);   /* generiert Zufallszahl "szahl" von 0 bis maxi  */
  zahl = fiwer[szahl];

   for (sleia = 0; sleia <= maxi; sleia++)
    if (fiwer[sleia] == zahl)
    {
      --maxi;
      for (slei = sleia; slei <= maxi; slei++) fiwer[slei] = fiwer[slei + 1];
       zuza[zuze] = zahl;
      ++zuze;
     }

}

/** Übertrag der Werte des lokalen Arrays zuza in das Array wert */
for (slei = 0; slei < BITLIMIT; slei++)
(*wert)[slei] = zuza[slei];
rewer = BITLIMIT -1;

return(rewer);
}

/** nur bei kleinen Werten von BITLIMIT sinnvoll */
void ShowReihe(long wert[], long anzahl)
{
long slei;
printf("\n");
for (slei = 0; slei < anzahl; slei++)
  printf("%ld ", wert[slei] );
}
/**--------------------------------------------------------Ende random.c des Versuchsprogramms------------------------------------*/
Jetzt die Hauptfunktion des Versuchsprogramms:
Code:
/**---------------Beginn Hauptfunktion main.c des Versuchsprogramms-------------------------------------------*/
#include "random.h"


int main(void)
{
int rewer;
long rew, pruefsumme, istwert;
long *wert;

time_t encoded_time;
struct tm *decoded_time;


printf("Permutationstest\n");
printf("Permutiert eine Zahlenreihe von 0 bis %ld\n", BITLIMIT);
printf("Versuche Haupt-Array zu allokieren...\n");
wert = (long *)malloc(((BITLIMIT +10)* sizeof(long)));


if( wert == NULL)
{
  printf("\nKeine Allokierung fuer Zeichenpeicher moeglich.\n");
  return 0;
}
else
  printf("Speicherallokierung erfolgreich\n");

printf("Permutiere die Zahlenreihe. Dies kann mehrere Minuten dauern!\n");

encoded_time = time(NULL);
decoded_time = localtime(&encoded_time);
printf("%d:%d:%d Uhr\n", decoded_time->tm_hour, decoded_time->tm_min, decoded_time->tm_sec);

rewer = SetRanValNoLimit(&wert);

/** Testet ob die Zahlenreihe richtig permutiert wurde */
rew = TellyDec(wert, BITLIMIT, &pruefsumme, &istwert);

printf("\nPruefsumme: %ld istwert:%ld", pruefsumme, istwert);
if (rew != 0)
  printf("\nZahlenreihe unvollstaendig");
printf("\nrew: %ld", rew);

printf("\nLaenge int: %ld   Laenge Long %ld\n", sizeof(int), sizeof(long));

encoded_time = time(NULL);
decoded_time = localtime(&encoded_time);
printf("%d:%d:%d Uhr\n", decoded_time->tm_hour, decoded_time->tm_min, decoded_time->tm_sec);
getch();
getch();
    free(wert);

return 0;
/**---------------Ende Hauptfunktion main.c des Versuchsprogramms-------------------------------------------*/

Hier noch ein code, der bei mir zum gernerieren größerer Zufallszahlen gut geklappt hat:
Zunächst wie immer der Header random.h:
Code:
#ifndef RANDOM_H_INCLUDED
#define RANDOM_H_INCLUDED
#include <time.h>

#define TRUE    1
#define FALSE   0

void sow(int *seed1, int *seed2);
int rmarin(void);
float ranmar(void);


int getrand(int min, int max);

class Zufall
{
public:
Zufall(void);
~Zufall();
int getrand(int min, int max);
void sow( int *seed1, int *seed2 );
int rmarin(void);
float ranmar(void);

private:
  int initrandom;
  float u[97], c, cd, cm;
  int i97, j97, test;
};

#endif // RANDOM_H_INCLUDED



Code:
/**-------------------------Beginn random.cpp------------------------------------------------------*/

#include <iostream>

//using namespace std;

#include <math.h>
#include "random.h"

//Erzeugt Zufallszahlen von >=min bis < max
int Zufall::getrand(int min, int max)
{
int zuza, zuza2, zuza3, rewer;
// bis 32767
//srand (time (NULL));
if (initrandom == 0)
  {
  rmarin();
  initrandom = 1;
  }

zuza  = (int)ranmar();
zuza2 = (max - min); // + 1);
zuza3 = zuza % zuza2;
rewer = zuza3 + min;
return rewer;
}
Zufall::Zufall()
{
initrandom = 0;
};


Zufall::~Zufall(){};

/* I use the following procedure in TC to generate seeds:

  The sow() procedure calculates two seeds for use with the random number
  generator from the system clock.  I decided how to do this myself, and
  I am sure that there must be better ways to select seeds; hopefully,
  however, this is good enough.  The first seed is calculated from the values
  for second, minute, hour, and year-day; weighted with the second most
  significant and year-day least significant.  The second seed weights the
  values in reverse.
*/

void Zufall::sow( int *seed1, int *seed2 )
{
        struct tm *tm_now;
        float s_sig, s_insig, maxs_sig, maxs_insig;
        long secs_now;
        int s, m, h, d, s1, s2;

        time(&secs_now);
        tm_now = localtime(&secs_now);

        s = tm_now->tm_sec + 1;
        m = tm_now->tm_min + 1;
        h = tm_now->tm_hour + 1;
        d = tm_now->tm_yday + 1;

        maxs_sig   = 60.0 + 60.0/60.0 + 24.0/60.0/60.0 + 366.0/24.0/60.0/60.0;
        maxs_insig = 60.0 + 60.0*60.0 + 24.0*60.0*60.0 + 366.0*24.0*60.0*60.0;

        s_sig      = s + m/60.0 + h/60.0/60.0 + d/24.0/60.0/60.0;
        s_insig    = s + m*60.0 + h*60.0*60.0 + d*24.0*60.0*60.0;

        s1 = s_sig   / maxs_sig   * 31328.0;
        s2 = s_insig / maxs_insig * 30081.0;

        *seed1 = s1;
        *seed2 = s2;
}


/************************************************************************
This is the initialization routine for the random number generator RANMAR()
NOTE: The seed variables can have values between:    0 <= IJ <= 31328
                                                      0 <= KL <= 30081
The random number sequences created by these two seeds are of sufficient
length to complete an entire calculation with. For example, if several
different groups are working on different parts of the same calculation,
each group could be assigned its own IJ seed. This would leave each group
with 30000 choices for the second seed. That is to say, this random
number generator can create 900 million different subsequences -- with
each subsequence having a length of approximately 10^30.

Use IJ = 1802 & KL = 9373 to test the random number generator. The
subroutine RANMAR should be used to generate 20000 random numbers.
Then display the next six random numbers generated multiplied by 4096*4096
If the random number generator is working properly, the random numbers
should be:
           6533892.0  14220222.0   7275067.0
           6172232.0   8354498.0  10633180.0
************************************************************************/

int Zufall::rmarin(void)
{

        int ij, kl;
        float s, t;
        int i, j, k, l, m;
        int ii, jj;

        sow(&ij, &kl);

        /* Change FALSE to TRUE in the next statement to test the
           random routine.*/

        test = TRUE;

        if ( ( ij < 0 || ij > 31328 ) ||
                ( kl < 0 || kl > 30081 ) )
         {
           std::cout << "\nRMARIN: The first random number seed must have a value between 0 and 31328\n";
           std::cout << "\nThe second random number seed must have a value between 0 and 30081";
           return 1;
         }

        i = fmod(ij/177.0, 177.0) + 2;
        j = fmod(ij      , 177.0) + 2;
        k = fmod(kl/169.0, 178.0) + 1;
        l = fmod(kl      , 169.0);

        for ( ii=0; ii<=96; ii++ )
        {
                s = 0.0;
                t = 0.5;
                for ( jj=0; jj<=23; jj++ )
                {
                        m = fmod( fmod(i*j,179.0)*k , 179.0 );
                        i = j;
                        j = k;
                        k = m;
                        l = fmod( 53.0*l+1.0 , 169.0 );
                        if ( fmod(l*m,64.0) >= 32)
                                s = s + t;
                        t = 0.5 * t;
                }
                u[ii] = s;
        }

        c  =   362436.0 / 16777216.0;
        cd =  7654321.0 / 16777216.0;
        cm = 16777213.0 / 16777216.0;

        i97 = 96;
        j97 = 32;

        test = TRUE;

        return 0;
}

float Zufall::ranmar(void)
{
float uni;

     uni = u[i97] - u[j97];
     if ( uni < 0.0 )
      uni = uni + 1.0;
     u[i97] = uni;
     i97--;
     if ( i97 < 0 )
      i97 = 96;
     j97--;
     if ( j97 < 0 )
      j97 = 96;
     c = c - cd;
     if ( c < 0.0 )
     c = c + cm;
     uni = uni - c;
     if ( uni < 0.0 )
      uni = uni + 1.0;
     //*rewer = uni;
     uni *= 4096 * 4096;

  return uni;
}
/**---------------------------Ende random.cpp------------------------------------------------------------------*/
Jetzt die Hauptfunktion main.cpp:
Code:
/**----------------------Beginn Hauptfunktion main.cpp-----------------------------------*/
#include <iostream>

//using namespace std;

/************************************************************************
This random number generator originally appeared in "Toward a Universal
Random Number Generator" by George Marsaglia and Arif Zaman.
Florida State University Report: FSU-SCRI-87-50 (1987)

It was later modified by F. James and published in "A Review of Pseudo-
random Number Generators"

Converted from FORTRAN to C by Phil Linttell, James F. Hickling
Management Consultants Ltd, Aug. 14, 1989.

THIS IS THE BEST KNOWN RANDOM NUMBER GENERATOR AVAILABLE.
       (However, a newly discovered technique can yield
         a period of 10^600. But that is still in the development stage.)

It passes ALL of the tests for random number generators and has a period
   of 2^144, is completely portable (gives bit identical results on all
   machines with at least 24-bit mantissas in the floating point
   representation).

The algorithm is a combination of a Fibonacci sequence (with lags of 97
   and 33, and operation "subtraction plus one, modulo one") and an
   "arithmetic sequence" (using subtraction).

On a Vax 11/780, this random number generator can produce a number in
    13 microseconds.
************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include "random.h"

int main()
{
Zufall zuf;
int temp, i, groesste = 0, kleinste = 2000000;
std::cout << "Generiere Zufallszahlen" << std::endl;

       /*Generate 20000 random numbers*/
         for ( i=0; i<=40000 ; i++)
         {
          temp = zuf.getrand(0,2000000);
          //cout << temp << ", ";
          if (temp > groesste) groesste = temp;
          if (temp < kleinste) kleinste = temp;
         }
std::cout << "\nGroesste generierte Zahl:" << groesste << std::endl;
std::cout << "\nkleinste:" << kleinste << std::endl;

  return 0;
/**---------------------Ende Hauptfunktion main.cpp--------------------------------*/
}
Anzumerken ist, das der code 1989 geschrieben wurde. In dieser Zeit waren die Prozessoren noch nicht so
weit entwickelt. Die Angaben mit 10^600 und 2^144 dürfen also nicht mehr ganz so hoch sein.
Trotz dem sieht man hier, was einen guten code ausmacht:
Dessen Portabilität.
Folgende weitere Funde möchte ich euch nicht vorenthalten:
Code:
/********************************************************************
          The McGill Super-Duper Random Number Generator
             G. Marsaglia, K. Ananthanarayana, N. Paul

    Incorporating the Ziggurat method of sampling from decreasing
              or symmetric unimodal density functions.
                      G. Marsaglia, W.W. Tsang

                 Rewritten into C by E. Schneider
*********************************************************************/

static unsigned long mcgn, srgn;

#define MULT 69069L

void rstart (i1, i2)
long i1, i2;

{ mcgn = (i1 == 0) ? 0 : i1 | 1;
   srgn = (i2 == 0) ? 0 : (i2 & 0x7FF) | 1;
  }

long uni()
{ unsigned long r0, r1;
   r0 = (srgn >> 15);
   r1 = srgn ^ r0;
   r0 = (r1 << 17);
   srgn = r0 ^ r1;
   mcgn = MULT * mcgn;
   r1 = mcgn ^ srgn;
   return (r1 >> 1);  }

long vni()
{ unsigned long r0, r1;
   r0 = (srgn >> 15);
   r1 = srgn ^ r0;
   r0 = (r1 << 17);
   srgn = r0 ^ r1;
   mcgn = MULT * mcgn;
   r1 = mcgn ^ srgn;
   return r1;  }
/*
"Anyone who consider arithmetic means of producing random number is,
of course, in a state of sin" - John Von Neumann
*/
Den letzten Kommentar sollte man sich zu Gemüte führen!
und noch
Code:
/**------------------------Das kuerzeste Beispiel, ungetestet----------------------------------------------------*/
/*
This type of random generators originate in early 1950's, and their
good properties were well known by late 50's (cf. D.Knuth 2nd ed.,
vol 2, section 3.2.2). A table of 90 different "magic pairs" like (97,23)
is also given in Knuth, as well as generalizations of the simple add to
primitive polynomials as suggested in your message.

As for practical implementations on a micro, the floating point version
will be very slow compared to integer version (even with 8087). I've
actually used exactly the same pair (97,23) combined with lookup based
CRC-16 instead of an add to obtain very fast and practically unlimited
source for random numbers. One should note that to obtain floating point
sequence, it is not enough to concatenate succesive random numbers from
the say 16-bit integer generator. Instead one should use 32-bit integers
or 64-bit integers for float/double (best done in assembler), with proper
range reduction on the exponent part (usually just an AND/OR mask). As to
seeding of the array[97], one can use rand() coupled with time/date
functions as suggested in several other responses. I've used PC timer
8253 directly which runs at 1.19 Mhz, coupled with date and keyboard
interrupt, the array is re-seeded by adding new-seed-rand() values to
the existent ones whenever a key was struck. Also, the random numbers
are continuously generated in any program-idle state.

The core of the algorithm (without CRC and seed generator) is:
*/
/********************************************************************
  Random Array ra[] is initialized to not-all-even, with e.g. rand()
  coupled with time/date. Before using the numbers, few thousands
  (+/-  random number) should be generated and discarded.
********************************************************************/

typedef unsigned int rn;
#define RA_TOP (ra+96)

rn ra[97];
rn *p97=RA_TOP, *p23=ra+22;

rn fast_rnd()
{ rn r;
     r = (*p97-- += *p23--);
     if (p97 < ra) p97=RA_TOP;
       else if (p23 < ra) p23=RA_TOP;
     return(r);
}
Der letzte code ist noch in der alten Syntax gehalten.

Daran wird auch klar, welche Dynamik in der Entwicklung der Sprachen c und c++ stecken.

euer rustyoldguy
Autor
rustyoldguy
First release
Last update
Bewertung
0,00 Stern(e) 0 Bewertungen
Oben