/* rand31pmc.c (cX) 2015 adolfo.dimare@gmail.com */
/** \file rand31pmc.c
\brief C language Implementation file for \c rand31pmc.h.
\see http://www.di-mare.com/adolfo/p/src/rand31pmc.zip
*/
/* Park && Miller 32 bit random number generator */
#include "rand31pmc.h"
#include <stdint.h> /* int32_t [available since C99] */
/** Set *SEED to generate further random numbers.
- This generator must be initialized by assigning seed a
value between 1 and 2147483646.
- Neither 0 nor 2^31-1 are valid seed values.
*/
void pm_seed( int32_t * SEED , int32_t new_seed ) {
if ( 0<(new_seed) && (new_seed) < 2147483647 ) {
*SEED = new_seed;
}
}
/** Returns the next random value in range [1..2^31-2].
- This is the Park && Miller 32 bit random number generator.
- This is a "full-period-multiplier".
- Carta's improvement yields an implementation that
does not use division.
\see http://www.firstpr.com.au/dsp/rand31/
\see http://www.firstpr.com.au/dsp/rand31/rand31-park-miller-carta-souce-no-comments.png
*/
int32_t pmc_next( int32_t * SEED ) {
uint32_t lo, hi;
lo = 16807 * (*SEED & 0xFFFF);
hi = 16807 * (*SEED >> 16);
lo += (hi & 0x7FFF) << 16;
lo += hi >> 15;
if (lo > 0x7FFFFFFF) lo -= 0x7FFFFFFF;
return ( *SEED = lo );
}
/** Returns the next random value in range [1..2^31-2].
- This is the Park && Miller 32 bit random number generator.
- This is a "full-period-multiplier".
*/
int32_t pm_next( int32_t * SEED ) {
enum {
a = 16807,
m = 2147483647, /* 2^31-1 */
q = m / a, /* 127773 */
r = m % a /* 2836 */
};
{
int32_t lo, hi, test;
hi = *SEED / q;
lo = *SEED % q;
test = a * lo - r * hi;
*SEED = ( test>0 ? test : test+m );
return *SEED;
}
/* Original Pascal Implementation:
***************************************************************
* Park, Stephen K. && Miller, Keith W.: *
* "Random Number Generators Good Ones Are Hard To Find", *
* Computing Practices, Communications of the ACM, *
* Volume 31 Number 10, pp 1192-1201, October 1988 *
***************************************************************
The following integer version of Random32 is correct
on any system for which maxint is 2^31 - 1 or larger.
First declare var seed : integer and then use
function Random32 : real;
(* Integer Version 2 *)
const
a = 16807;
m = 2147483647;
q = 127773; (* m div a *)
r = 2836; (* m mod a *)
var
lo, hi, test : integer;
begin
hi := seed div q;
lo := seed mod q;
test := a * lo - r * hi;
if test > 0 then
seed := test
else
seed := test + m;
Random32 := seed / m
end;
*/
}
#ifndef NDEBUG
/** Informal test to verify this implementation against the original. */
int test_Random32() {
/* Implementation -> Pascal de Park && Miller pp 1195
seed := 1;
for n := 1 to 10000 do
u := Random32;
Writeln('The current value of seed is : ', seed);
produces 1043618065.
*/
int32_t u,i, SEED = -1;
pm_seed(&SEED,1);
for ( i=0; i<10000; ++i ) {
u = pm_next(&SEED);
}
return (u==1043618065);
}
#endif
/** Converts the next random 'SEED' into range [0..n-1]==[0..n[.
- Returns cero when (n<=0).
- Uses 'next(SEED)' to get a new random number.
- Uses 64 bit multiplication and 32 bit division.
- This algorithm rejects values that would result in an uneven
distribution; the expected number of rejections before is 2.
- Copied from Java v7 class Random.
\see http://docs.oracle.com/javase/7/docs/api/java/util/Random.html#nextInt%28int%29
\code
int32_t seed = 12, next, i;
assert( "Example usage for random numbers in range [0..32[" );
for ( i=0; i<10000; ++i ) {
next = pm_range( &seed, 32, &pmc_next );
assert( next < 32 );
printf( "\n next==%d%", next );
}
\endcode
*/
int32_t pm_range( int32_t * SEED , int32_t n , int32_t (*next)( int32_t * ) ) {
int32_t bits, val;
if (n <= 0)
{ return 0; }
if ((n & -n) == n) /* i.e., n is a power of 2 */
return (int32_t)((n * (int64_t)( (*next)(SEED) ) ) >> 31);
do {
bits = pmc_next(SEED);
val = bits % n;
} while (bits - val + (n-1) < 0);
return val;
/*
Translated from Java class Random:
http://docs.oracle.com/javase/7/docs/api/java/util/Random.html#nextInt%28int%29
*/
/*
public int nextInt(int n)
Returns a pseudorandom, uniformly distributed int value between 0
(inclusive) and the specified value (exclusive), drawn from this random
number generator's sequence. The general contract of nextInt is that one
int value in the specified range is pseudorandomly generated and
returned. All n possible int values are produced with (approximately)
equal probability. The method nextInt(int n) is implemented by class
Random as if by:
public int nextInt(int n) {
if (n <= 0)
throw new IllegalArgumentException("n must be positive");
if ((n & -n) == n) // i.e., n is a power of 2
return (int)((n * (long)next(31)) >> 31);
int bits, val;
do {
bits = next(31);
val = bits % n;
} while (bits - val + (n-1) < 0);
return val;
}
The hedge "approximately" is used in the foregoing description only
because the next method is only approximately an unbiased source of
independently chosen bits. If it were a perfect source of randomly
chosen bits, then the algorithm shown would choose int values from the
stated range with perfect uniformity.
The algorithm is slightly tricky. It rejects values that would result in
an uneven distribution (due to the fact that 2^31 is not divisible by
n). The probability of a value being rejected depends on n. The worst
case is n=2^30+1, for which the probability of a reject is 1/2, and the
expected number of iterations before the loop terminates is 2.
The algorithm treats the case where n is a power of two specially: it
returns the correct number of high-order bits from the underlying
pseudo-random number generator. In the absence of special treatment, the
correct number of low-order bits would be returned. Linear congruential
pseudo-random number generators such as the one implemented by this
class are known to have short periods in the sequence of values of their
low-order bits. Thus, this special case greatly increases the length of
the sequence of values returned by successive calls to this method if n
is a small power of two.
Parameters:
n - the bound on the random number to be returned. Must be positive.
Returns:
the next pseudorandom, uniformly distributed int value between 0
(inclusive) and n (exclusive) from this random number generator's
sequence
*/
}
/*
Source code available here:
http://www.di-mare.com/adolfo/p/src/rand31pmc.zip
*/
/* http://stackoverflow.com/questions/22999513/ */
/* EOF: rand31pmc.c */