[comp.sys.amiga.tech] rand

martens@python.cis.ohio-state.edu (Jeff Martens) (12/03/90)

In article <37886@nigel.ee.udel.edu> AAW151%URIACC.BITNET@brownvm.brown.edu (Andy Patrizio) writes:
>In going through ANSI C, one of umpteen books on C programming, reference is
>made to a command called rand() that will generate random numbers.

>First off, is this possible under Lattice C? And second, how exactly is it
>done? The book doesn't elaborate.

Lattice C, except for the possibility of running out of memory, is
turing complete.  So you can certainly do it in Lattice C.  Most
programming languages come with random number generators as part of
the language or in a library, but many are garbage (e.g. unix rand()
or the random # function that TDI distributed with their Modula 2).
If you need a good random number generator, you might want to read
this article:

@article{ParMil:88,
	author = {Stephen K. Park and Keith W. Miller},
	title = {Random Number Generators:  Good Ones are Hard to Find},
	journal = {CACM},
	year = {1988},
	month = {October},
	volume = {31},
	number = {10},
	pages = {1192 -- 1201}
}


Of course, if you're just writing a game it doesn't probably matter.

Please note that I've redirected followups to c.s.a.tech.
--
-- Jeff (martens@cis.ohio-state.edu)

	"Until you stalk and overrun, you can't devour anyone" -- Hobbes.

737104@sheoak.bcae.oz (David Thiele) (12/04/90)

Is there a way to generate random numbers within a certain range in 
Lattice C??. Ive done it with the following code but it's not very
elegant (or fast!),

Random(range,seed)
int range,seed;
{
	srand(seed);
	if range = 0
		return(0);
	else{
		do
			seed = rand() / 10000000;
		while (seed >= range);
		return(seed);
	}
}

urrgghh! help 

Dave

dolf@idca.tds.PHILIPS.nl (Dolf Grunbauer) (12/05/90)

In article <666@sheoak.bcae.oz> 737104@sheoak.bcae.oz (David Thiele) writes:
>Is there a way to generate random numbers within a certain range in 
>Lattice C??. Ive done it with the following code but it's not very
>elegant (or fast!),
>
>Random(range,seed)
>int range,seed;
>{
>	srand(seed);
>	if range = 0
>		return(0);
>	else{
>		do
>			seed = rand() / 10000000;
>		while (seed >= range);
>		return(seed);
>	}
>}
>

How about:
Random(range,seed)
int range,seed;
{
	srand(seed);
	if range = 0
		return(0);
	else	return (((seed = rand()) / 10000000) % range);
}

By the way: why do you want to set seed explicitly before each rand call ?
Propably what will do also is:

Random(range)
int range;
{
	if range = 0
		return(0);
	else	return (rand() % range);
}

and call 'srand' only in some initialisation function or main.
-- 
   _ _ 
  / U |  Dolf Grunbauer  Tel: +31 55 433233 Internet dolf@idca.tds.philips.nl
 /__'<   Philips Information Systems        UUCP     ...!mcsun!philapd!dolf
88  |_\  If you are granted one wish do you know what to wish for right now ?

hclausen@adspdk.UUCP (Henrik Clausen) (12/06/90)

In article <666@sheoak.bcae.oz>, David Thiele writes:

> Is there a way to generate random numbers within a certain range in 
> Lattice C??. Ive done it with the following code but it's not very
> elegant (or fast!).

   You said it :-)

   Try something like:

int Random(int Range)
{
	return((int)(Range * drand48()));
}


   Add offsets at your desire. Seed from the timer with srand48().
drand48() returns a double, and is supposed to be quite good.

   BTW, this stuff is in your manual.


                                   -Henrik

| Henrik Clausen, Graffiti Data | If the Doors of Perception where cleansed, |
| ...{pyramid|rutgers}!cbmvax!  | Man would see Reality as it is - Infinite. |
\______cbmehq!adspdk!hclausen___|_________________________________W. Blake___/

aaronf@hpfcbig.SDE.HP.COM (Aaron Friesen) (12/06/90)

sheoak.bcae.oz (David Thiele) /  4:20 pm  Dec  3, 1990 /
> Is there a way to generate random numbers within a certain range in 
> Lattice C??. Ive done it with the following code but it's not very
> elegant (or fast!),

[ Code Deleted... ]

Simply taking

	rand() % range

or something similar should give you what you want.  This will be fast and
about as "random" as the code you are currently using.

xanthian@zorch.SF-Bay.ORG (Kent Paul Dolan) (12/06/90)

dolf@idca.tds.philips.nl (Dolf Grunbauer) writes:
> 737104@sheoak.bcae.oz (David Thiele) writes:

>> Is there a way to generate random numbers within a certain range in
>> Lattice C??. Ive done it with the following code but it's not very
>> elegant (or fast!),

> By the way: why do you want to set seed explicitly before each rand
> call ? Probably what will do also is:

> Random(range)
> int range;
> {
>	if range = 0
>		return(0);
>	else	return (rand() % range);
> }

> and call 'srand' only in some initialisation function or main.

Nope.  You don't want to do that; it gives you a biased sample.  To see
the worst case, suppose, where MAXINT is the largest possible output of
rand(), that range is approximately 2*MAXINT/3.  Then you're going to
get about twice as many samples in the interval from zero to range/2 -1,
as in range/2 to range -1.

In psuedocode, you want:

#define MAXINT /* as whatever 2^31-1 is, assuming 32 bit integers */
Random(int range)
{
int limit, work1, work2, work3;

/*

Goal: Use as much of the possible returned range 0 to MAXINT as possible
(to minimize the number of wasted, expensive calls to rand()), without
biasing the sample.

Method: Find the biggest number of copies of 0 to range - 1 that will
fit in 0 to MAXINT; this will cover some, perhaps equal, interval 0 to
limit. If the call to rand() falls in 0 to limit, take the modulus with
range as the returned value. If not, throw away the result and try
again.

Discussion: It is desired that the value returned fall in the interval 0
to range - 1. What you want to know is how many copies of range will fit
in the interval 0 to MAXINT, or, more important, 1 to MAXINT + 1, so we
can divide to get the answer. This gets messy because you can't
represent MAXINT + 1 directly, and range might be an exact divisor of
MAXINT + 1.

*/

work1 = MAXINT/range;    /* integer number of ranges that fit in MAXINT */

         /* in case what was left, + 1, will hold one more copy of range */
work2 = (MAXINT - (work1 * range) + 1) / range ;

    /* the "-1" has to go here to avoid overflow in the next calculation */
    /* in case range is an exact divisor of MAXINT + 1 */
limit = range * work1 - 1;

     /* add in zero or one more range interval */
limit = limit + range * work2;

/* limit is now the biggest usable return value from rand() */

while ((work3 = rand()) > limit) /* iterate*/ ;

return (work3 % range);

}

If only one value of range is being used, or if the programmer is
willing to do the work in the calling routine for each different value,
the calculation of limit should be moved out to the calling routine and
the calculated value passed in for efficiency. You still have to do the
seed call to srand() once somewhere, preferably near the top of your
main routine.

If that constitutes code (doubtful) then it is public domain. The idea
is yours in any case, it sure isn't original with me. Forgive bugs, I
haven't been well enough to light off a compiler since June. Modulo
possible bugs, that is the "standard" way to do the job right.

Kent, the man from xanth.
<xanthian@Zorch.SF-Bay.ORG> <xanthian@well.sf.ca.us>

nj@magnolia.Berkeley.EDU (Narciso Jaramillo) (12/07/90)

In article <1990Dec6.033145.22855@zorch.SF-Bay.ORG> xanthian@zorch.SF-Bay.ORG (Kent Paul Dolan) writes:

   dolf@idca.tds.philips.nl (Dolf Grunbauer) writes:
   > 737104@sheoak.bcae.oz (David Thiele) writes:

   >> Is there a way to generate random numbers within a certain range in
   >> Lattice C??. Ive done it with the following code but it's not very
   >> elegant (or fast!),

   >	return (rand() % range);

   Nope.  You don't want to do that; it gives you a biased sample.  To see
   the worst case, suppose, where MAXINT is the largest possible output of
   rand(), that range is approximately 2*MAXINT/3.  Then you're going to
   get about twice as many samples in the interval from zero to range/2 -1,
   as in range/2 to range -1.

If you're willing to do some floating-point arithmetic, you
can also do

return ((int)floor((double)(rand())/MAXINT * high));

or

return ((int)floor(drand48() * high));

Since rand() returns values that are (presumably evenly) distributed
over the range [0, MAXINT), (double)(rand())/MAXINT should return
floating point values that are evenly distributed over the range [0.0,
1.0).  Since drand48() also returns values in [0.0, 1.0), both of
these should return unbiased values in the range [0, high).  Slightly
expensive because of the floating-point operations, but you don't have
to go through the (admittedly fast, though not necessarily faster)
contortions of Kent's algorithm.



nj

barrett@jhunix.HCF.JHU.EDU (Dan Barrett) (12/08/90)

I tried e-mail but it bounced.

In article <666@sheoak.bcae.oz> 737104@sheoak.bcae.oz (David Thiele) writes:
>Is there a way to generate random numbers within a certain range in
>Lattice C??

	It can be done in ANY language -- there is a mathematical formula
for it.  All you need is a function Rand() that returns a random real number
between 0 and 1 (not including 1).  This is commonly supplied by your
compiler company.

To generate a random integer between integers A and B, with A < B:

(1)	Figure out the distance between A and B:

		distance = B - A + 1;

(2)	Multiply a random number by the distance, and truncate the
	remainder.  This gives you a random integer between 0 and
	(distance - 1):

		first = floor(distance * Rand());

(3)	Now increase this number by A, to give you an integer between
	A and (A + distance - 1).  But remember:

		A + distance - 1
			= A + (B - A + 1) - 1
			= B

	So you have a random integer between A and B:

		answer = first + A;

Here is the final formula:

		answer = floor((B - A + 1) * Rand()) + A;

                                                        Dan

 //////////////////////////////////////\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
| Dan Barrett     -      Systems Administrator, Computer Science Department |
| The Johns Hopkins University, 34th and Charles Sts., Baltimore, MD  21218 |
| INTERNET:   barrett@cs.jhu.edu           |                                |
| COMPUSERVE: >internet:barrett@cs.jhu.edu | UUCP:   barrett@jhunix.UUCP    |
 \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\/////////////////////////////////////

andrew@teslab.lab.OZ (Andrew Phillips) (12/11/90)

In article <540@ssp9.idca.tds.philips.nl> dolf@idca.tds.philips.nl (Dolf Grunbauer) writes:
>In article <666@sheoak.bcae.oz> 737104@sheoak.bcae.oz (David Thiele) writes:
>>Is there a way to generate random numbers within a certain range in 
>>Lattice C??. ...
>
>...
>Random(range)
>int range;
>{
>	if range = 0
>		return(0);
>	else	return (rand() % range);
>}

This is not the best solution for two reasons.  First, unless range
is a divisor of the maximum value returned by rand() plus one then
the numbers will not be distributed evenly over the range.  Second,
even the best PRNG's are not very random in their least significant
bits, so you want values which use the most significant bits.

A simple portable solution would be to use drand48():

#define RANDOM(RANGE) ((int)(drand48()*(RANGE)))

If you don't want to use floating point numbers or need more speed
and know that longs are bigger than ints you could use (assuming
rand() returns a value between zero and MAXINT):

#define RANDOM(RANGE) ((int)(((long)rand()*(RANGE))/(MAXINT+1)))

Or else if you know range is never going to be bigger than say 256 use
something like:

#define RANDOM(RANGE) (((rand()/256)*(RANGE))/((MAXINT+1)/256))

Andrew.
-- 
Andrew Phillips (andrew@teslab.lab.oz.au) Phone +61 (Aust) 2 (Sydney) 289 8712

lshaw@ccwf.cc.utexas.edu (logan shaw) (12/13/90)

In article <666@sheoak.bcae.oz> 737104@sheoak.bcae.oz (David Thiele) writes:
>Is there a way to generate random numbers within a certain range in 
>Lattice C??. ...

Well, assuming you are already writing an amiga specific application and this
won't hurt portability, you could use the amiga.lib function rangerand().
You pass it a longword (with a value from 1 to 65535) and it returns a
random number between 0 and that number.

If you are being portable, use a macro.

Hope that helps...
-- 
=----------------Logan-Shaw---(lshaw@ccwf.cc.utexas.edu)----------------=
  "Trust in the Lord with all thine heart, and lean not on thine own
   understanding.  In all thy ways acknowledge Him and he shall direct
   thy paths"        - Proverbs 3:5-6

xanthian@zorch.SF-Bay.ORG (Kent Paul Dolan) (12/13/90)

andrew@teslab.lab.oz.au (Andrew Phillips) writes:

>If you don't want to use floating point numbers or need more speed
>and know that longs are bigger than ints you could use (assuming
>rand() returns a value between zero and MAXINT):

>#define RANDOM(RANGE) ((int)(((long)rand()*(RANGE))/(MAXINT+1)))
                                                      ^^^^^^^^probably not
>Or else if you know range is never going to be bigger than say 256 use
>something like:

>#define RANDOM(RANGE) (((rand()/256)*(RANGE))/((MAXINT+1)/256))
                                                 ^^^^^^^^nope

Your first example will overflow to MAXNEGINT if the compiler chooses
to do the promotion to long as late as possible, and your second one
is guaranteed to overflow.

Kent, the man from xanth.
<xanthian@Zorch.SF-Bay.ORG> <xanthian@well.sf.ca.us>