delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp/2000/05/25/07:31:15

From: buers AT gmx DOT de (Dieter Buerssner)
Newsgroups: comp.os.msdos.djgpp
Subject: Re: Random numbers
Date: 25 May 2000 11:27:09 GMT
Lines: 61
Message-ID: <8gja2u.3vvquht.0@buerssner-17104.user.cis.dfn.de>
References: <392CB951 DOT 34B432E6 AT chemistry DOT uq DOT edu DOT au>
NNTP-Posting-Host: pec-1-228.tnt1.s2.uunet.de (149.225.1.228)
Mime-Version: 1.0
X-Trace: fu-berlin.de 959254029 1514814 149.225.1.228 (16 [17104])
X-Posting-Agent: Hamster/1.3.13.0
User-Agent: Xnews/03.02.04
To: djgpp AT delorie DOT com
DJ-Gateway: from newsgroup comp.os.msdos.djgpp
Reply-To: djgpp AT delorie DOT com

Chris Miller wrote:

>Ideally, I am attempting to generate a random integer between 0 and
>1,000,000.

If you want to be portable, you have to be very careful with such
a large range. RAND_MAX can be as small as 32767 (and often is).
Depending on your problem, I can suggest two solutions. If you
do not need "high-quality" random numbers, you can shift together
two return values of rand(). Of course, much care has to be taken,
because RAND_MAX+1 is not guaranteed to be a power of two.
The other solution is to write your own PRNG or load it from the
net. (You could do a web-search for Mersenne Twister.)

A not too bad and portable PRNG is the following, originally
suggested by George Marsaglia. It will return pseudo random numbers
between 0 and 0xffffffffUL (both inclusive).

static unsigned long zs = 1234567UL;
static unsigned long ws = 7654321UL;

/* Combine two multiply with carry PRNGs */
unsigned long mwc1616(void)
{
  unsigned long t = zs;
  zs = 30903*(t&0xffffUL)+(t>>16);
  t = ws;
  ws = 18000*(t&0xffffUL)+(t>>16);
  return ((ws<<16)&0xffffffffUL) + (zs&0xffffUL);
}

void seed_mwc1616(unsigned long s)
{
  s &= 0xffffffffUL; /* Mask for portablity to 64bit long */
  if (s == 0)
    s = 1234567UL;
  zs = s;
  ws = 7654321UL;
}

Then your random number between 0 an 1,000,000 (inclusive) would be

  unsigned long r = (unsigned long)((mwc1616()/4.294967296e9) * 1000001.0);
  /* or   mwc1616() * 2.3283064365386962890625e-10 * 1000001.0 */
  /* or   mwc1616() * 2.3283087648451328277587890625e-4 */

Note, that this method won't generalize to a larger range. Then
more sophisticated methods would be needed. For your special
problem, the method will return some numbers with a probability
of floor(2^32/1000001)/2^32 = 0.9997748e-6 and the other numbers with a 
probability of ceil(2^32/1000001)/2^32 = 1.0000076e-6. This small
difference should be ok for many purposes. In general, the larger
the range, the larger will be the difference in the probabilities
(unless the range is a power of two).

Of course, when you are interested in DJGPP only, you can write

  int r = (int)(rand() * 1000001.0)/(RAND_MAX+1.0);

-- 
Regards, Dieter Buerssner

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019