我想在某个间隔内生成随机整数。我不想使用 srand 的基本实现和 time(NULL) 作为种子,因为我已经读过它不是最“随机”的方式。
我看过很多描述如何在 C++11 中使用 std::uniform_int_distribution 的帖子,但不幸的是,我在一个仍然使用 g++ 4.4.5 的计算集群上工作,它没有这个功能。这个编译器有类似的东西吗?
/* rand31pmc.h (cX) 2015 adolfo.dimare@gmail.com */
/** \file rand31pmc.h
\brief Park && Miller && Carta 32 bit random number generator.
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
This is the Park-Miller "minimal standard"
Linear Congruential Generator (LCG):
(seed * 16807 mod(2^31 - 1))
\see http://www.firstpr.com.au/dsp/rand31/
\see http://www.di-mare.com/adolfo/p/src/rand31pmc.zip
*/
#ifndef rand31pmc_h
#define rand31pmc_h /**< Used to avoid multiple inclusion */
#include <stdint.h> /* int32_t [available since C99] */
/* #include <cstdint> // requires compiling with option '-std=c++11' [GCC] */
#ifdef __cplusplus /* C++ wrap for C language routines */
extern "C" {
#endif
/* This is the C language implementation */
void pm_seed( int32_t * SEED , int32_t new_seed );
int32_t pm_next( int32_t * SEED );
int32_t pmc_next( int32_t * SEED );
int32_t pm_range( int32_t * SEED , int32_t n , int32_t(*next)(int32_t*) );
#ifdef __cplusplus /* C++ wrap for C language routines */
} /* extern "C" */
#endif
#ifdef __cplusplus /* __cplusplus -> This is the C++ implementation */
/// Trick to avoid using a 'rand31pmc.cpp' file
template <class T> class rand31pmc;
/*
This is a template specialization for 'rand31pmc<>'. As the C++ compiler
requires template implementations to be in the header file, there is no
need to use file 'rand31pmc.cpp' to implement class methods. This means
that using the directive '#include "rand31pmc.h"' (to include this
header file) is all that needs to be done to use this random number
generator.
*/
// Park && Miller && Carta 32 bit random number generator.
// (seed * 16807 mod(2^31 - 1)) Linear Congruential Generator (LCG)
// http://www.firstpr.com.au/dsp/rand31/
template <> class rand31pmc<int32_t> {
private: int32_t m_seed; ///< Used to generate next random number.
/// Constructor.
public: rand31pmc( int32_t sd=1 ) : m_seed(1) {
seed( sd );
}
/** Sets the seed value used by this generator.
- This generator must be initialized by assigning seed a
value between 1 and 2147483646.
- Neither 0 nor 2^31-1 are valid seed values.
*/
public: void seed( int32_t sd=1 ) {
if ( 0<sd && sd<2147483647 ) {
m_seed = sd;
}
}
/// Return next random number in range [0..n-1].
/// - Returns range(n).
public: int32_t nextRange(int32_t n) {
return range(n);
}
private: enum {
a = 16807, ///< 16807
m = 2147483647, ///< 2^31-1
q = m / a, ///< 127773
r = m % a ///< 2836
};
/** Returns next random number in range [1..2^31-2].
- This is a "full-period-multiplier".
- This is the original Parker && Miller implementation
<code> (seed * 16807 mod(2^31 - 1)) </code>
*/
public: int32_t pm_next();
/** Returns next random number in range [1..2^31-2].
- This is a "full-period-multiplier".
- Carta's improvement yields an implementation that
does not use division.
<code> (seed * 16807 mod(2^31 - 1)) </code>
\see http://www.firstpr.com.au/dsp/rand31/
*/
public: int32_t pmc_next();
// Return next random number in range [0..n-1].
public: int32_t range(int32_t n);
/// Informal test to verify this implementation against the original.
public: static bool test_rand31pmc();
}; // class rand31pmc<int32_t>
// template<> not used for a member of a specialization
int32_t rand31pmc<int32_t>::pm_next() {
int32_t lo, hi, test;
hi = m_seed / q;
lo = m_seed % q;
test = a * lo - r * hi;
m_seed = ( test>0 ? test : test+m );
return m_seed;
}
// template<> not used for a member of a specialization
/* *** Carta's no division implementation *** */
int32_t rand31pmc<int32_t>::pmc_next() {
uint32_t lo, hi;
lo = 16807 * (m_seed & 0xFFFF);
hi = 16807 * (m_seed >> 16);
lo += (hi & 0x7FFF) << 16;
lo += hi >> 15;
if (lo > 0x7FFFFFFF) lo -= 0x7FFFFFFF;
return ( m_seed = lo );
}
/* Original Park && Miller 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 rand31pmc is correct
on any system for which maxint is 2^31 - 1 or larger.
First declare var seed : integer and then use
function rand31pmc : 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;
rand31pmc := seed / m
end;
*/
/** Converts the next random into range [0..n-1]==[0..n[.
- Returns cero when (n<=0).
- Uses 'pmc_next()' to get random numbers.
- 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.
- Translated from Java class Random.
\see http://docs.oracle.com/javase/7/docs/api/java/util/Random.html#nextInt%28int%29
*/
int32_t rand31pmc<int32_t>::range(int32_t n) {
if (n <= 0)
{ return 0; }
if ((n & -n) == n) // i.e., n is a power of 2
return (int32_t)((n * (int64_t)(pmc_next())) >> 31);
int32_t bits, val;
do {
bits = pmc_next();
val = bits % n;
} while (bits - val + (n-1) < 0);
return val;
}
bool rand31pmc<int32_t>::test_rand31pmc() {
/* Pascal implementation from Park && Miller pp 1195
seed := 1;
for n := 1 to 10000 do
u := rand31pmc;
Writeln('The current value of seed is : ', seed);
produces 1043618065.
*/
{
/* Check Carta's implementation for all values */
rand31pmc<int32_t> pm,carta;
pm.seed(1), carta.seed(1);
for ( int32_t i=1; i<2147483647; ++i ) {
int32_t pmN = pm.pm_next();
int32_t pmcN = carta.pmc_next();
if ( pmN != pmcN ) {
return false; // abort!
}
}
return true;
}
{{ // Example -> rand31pmc<>
int32_t u=-1; // seed should be in range [1..2^31-2]
rand31pmc<int32_t> rand(u); // 'seed' for 'rand' is 1
rand.seed(1); // redundant
for ( int32_t i=0; i<10000; ++i ) {
u = rand.pmc_next(); // pmc-> Park && Miller && Carta
}
return (u==1043618065);
}}
}
/** \class rand31pmc<int32_t>
\brief Park && Miller && Carta 32 bit random number generator.
(seed * 16807 mod(2^31 - 1)) Linear Congruential Generator (LCG)
\see http://www.firstpr.com.au/dsp/rand31/
\dontinclude rand31pmc.h
\skipline Example -> rand31pmc<>
\until }}
*/
#endif
#endif /* rand31pmc_h */
/*
Source code available here:
http://www.di-mare.com/adolfo/p/src/rand31pmc.zip
*/
/* http://stackoverflow.com/questions/22999513/ */
/* EOF: rand31pmc.h */
我假设您需要这些随机数来进行统计而不是加密。只需使用 Merssenne Twister
您可以复制 Java.Random.nextInt(int n) 实现: http://docs.oracle.com/javase/7/docs/api/java/util/Random.html#nextInt(int)
/* 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 */