3

我想在某个间隔内生成随机整数。我不想使用 srand 的基本实现和 time(NULL) 作为种子,因为我已经读过它不是最“随机”的方式。

我看过很多描述如何在 C++11 中使用 std::uniform_int_distribution 的帖子,但不幸的是,我在一个仍然使用 g++ 4.4.5 的计算集群上工作,它没有这个功能。这个编译器有类似的东西吗?

4

4 回答 4

1
/* 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 */
于 2015-01-05T15:13:14.807 回答
1

我假设您需要这些随机数来进行统计而不是加密。只需使用 Merssenne Twister

于 2015-03-03T13:56:08.143 回答
0

您可以复制 Java.Random.nextInt(int n) 实现: http://docs.oracle.com/javase/7/docs/api/java/util/Random.html#nextInt(int)

于 2015-03-03T13:47:24.543 回答
0
/* 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 */
于 2015-01-05T15:17:45.677 回答