随机数生成算法的C++实现

头文件:

/*
 * Copyright (c) 2008-2011 Zhang Ming (M. Zhang), [email protected]
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation, either version 2 or any later version.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details. A copy of the GNU General Public License is available at:
 * http://www.fsf.org/licensing/licenses
 */


/*****************************************************************************
 *                                    random.h
 *
 * Random Number Generator.
 *
 * The class Random can generate an "long int" random number. The default
 * initial state is set to 1, of cause it can be set to any integer through
 * routine "seed(int)".
 *
 * Based on the "Random" class, we can generate some usually used distributed
 * pseudorandom number or pseudorandom sequence. These distributions include:
 *      Uniform     Normal      Exponential     Rayleigh        Poisson
 *      Bernoulli
 *
 * Zhang Ming, 2010-10, Xi'an Jiaotong University.
 *****************************************************************************/


#ifndef RANDOM_H
#define RANDOM_H


#include <vector.h>


namespace splab
{

    class Random
    {

    public:

        explicit Random( long int initValue=1 );
        ~Random();

        void seed( long int value );
        long int random();
        long int getM() const;

    private:

        static const long int A = 48271;
        static const long int M = 2147483647;
        static const long int Q = 44488;
        static const long int R = 3399;

        long int state;

    };


    template<typename Type> Type randu( int, const Type&, const Type& );
    template<typename Type> Type randn( int, const Type&, const Type& );
    template<typename Type> Type rande( int, const Type& );
    template<typename Type> Type randr( int, const Type& );
    template<typename Type> int randp( int, const Type& );
    template<typename Type> int randb( int, const Type& );

    template<typename Type> Vector<Type> randu( int, const Type&,
                                                const Type&, int );
    template<typename Type> Vector<Type> randn( int, const Type&,
                                                const Type&, int );
    template<typename Type> Vector<Type> rande( int, const Type&, int );
    template<typename Type> Vector<Type> randr( int, const Type&, int );
    template<typename Type> Vector<int>  randp( int, const Type&, int );
    template<typename Type> Vector<int>  randb( int, const Type&, int );


    #include <random-impl.h>

}
// namespace splab


#endif
// RANDOM_H

实现文件:

/*
 * Copyright (c) 2008-2011 Zhang Ming (M. Zhang), [email protected]
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation, either version 2 or any later version.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details. A copy of the GNU General Public License is available at:
 * http://www.fsf.org/licensing/licenses
 */


/*****************************************************************************
 *                               random-impl.h
 *
 * Implementation for Random class and random generator.
 *
 * Zhang Ming, 2010-10, Xi'an Jiaotong University.
 *****************************************************************************/


/**
 * constructors and destructor
 */
Random::Random( long int initValue )
{
    if( initValue < 0 )
        initValue += M;

    state = initValue;
    if( state == 0 )
        state = 1;
}

Random::~Random()
{
}


/**
 * Set the internal state.
 */
inline void Random::seed( long int value )
{
    state = value;
}


/**
 * Return a pseudorandom int, and then change the internal state.
 */
long int Random::random()
{
    long int tmpState = A*( state%Q ) - R*( state/Q );

    if( tmpState >= 0 )
        state = tmpState;
    else
        state = tmpState + M;

    return state;
}


/**
 * Return M.
 */
inline long int Random::getM() const
{
    return M;
}


/**
 * Return an Uniform[low, high] distributed pseudorandom number.
 */
template <typename Type>
Type randu( int seed, const Type &low, const Type &high )
{
    static Random rg( seed );
    long double u_0_1 = rg.random() / (long double)rg.getM();

    return low + Type( u_0_1*(high-low) );
}


/**
 * Return a Normal~(mu, sigma) distributed pseudorandom number.
 */
template <typename Type>
Type randn( int seed, const Type &mu, const Type &sigma )
{
    static Random rg( seed );
    long double u_0_1 = 0.0;

    for( int i=0; i<12; ++i )
        u_0_1 += rg.random()/(long double)rg.getM();
    u_0_1 -= 6.0;

    return Type( sigma*u_0_1 + mu );
}


/**
 * Return a Exponential~(beta) distributed pseudorandom number.
 */
template <typename Type>
Type rande( int seed, const Type &beta )
{
    static Random rg( seed );
    long double u_0_1 = rg.random()/(long double)rg.getM();

    return Type( -beta*log(u_0_1) );
}


/**
 * Return a Rayleigh~(sigma) distributed pseudorandom number.
 */
template <typename Type>
Type randr( int seed, const Type &sigma )
{
    static Random rg( seed );
    long double u_0_1  = rg.random() / (long double)rg.getM();

    return Type( sigma * sqrt(-2.0*log(u_0_1)) );
}


/**
 * Return a Poisson~(lambda) distributed pseudorandom number.
 */
template <typename Type>
int randp( int seed, const Type &lambda )
{
    static Random rg( seed );
    long double u_0_1 = 0.0,
                q = exp(-lambda),
                p = 1.0;
    int k = 0;

    while( p >= q )
    {
        u_0_1 = rg.random()/(long double)rg.getM();
        p *= u_0_1;
        k++;
    }
    return k-1;
}


/**
 * Return a Bernoulli~(p) distributed pseudorandom number.
 */
template <typename Type>
int randb( int seed, const Type &p )
{
    static Random rg( seed );
    long double u_0_1  = rg.random() / (long double)rg.getM();

    return ( Type(u_0_1) <= p ) ? 1 : 0;
}


/**
 * Return an Uniform[low, high] distributed pseudorandom sequence of size N.
 */
template <typename Type>
Vector<Type> randu( int seed, const Type &low, const Type &high, int N )
{
    long double u_0_1 = 0.0;
    Random rg( seed );
    Vector<Type> rs(N);

    for( int i=0; i<N; ++i )
    {
        u_0_1 = rg.random() / (long double)rg.getM();
        rs[i] = low + Type( u_0_1*(high-low) );
    }

    return rs;
}


/**
 * Return an Normal~(mu, sigma) distributed pseudorandom sequence of size N.
 */
template <typename Type>
Vector<Type> randn( int seed, const Type &mu, const Type &sigma, int N )
{
    long double u_0_1;
    Random rg( seed );
    Vector<Type> rs(N);

    for( int i=0; i<N; ++i )
    {
        u_0_1 = 0.0;
        for( int j=0; j<12; ++j )
            u_0_1 += rg.random()/(long double)rg.getM();
        u_0_1 -= 6.0;

        rs[i] = Type(sigma*u_0_1) + mu;
    }

    return rs;
}


/**
 * Return an Exponential~(beta) distributed pseudorandom sequence of size N.
 */
template <typename Type>
Vector<Type> rande( int seed, const Type &beta, int N )
{
    long double u_0_1 = 0.0;
    Random rg( seed );
    Vector<Type> rs(N);

    for( int i=0; i<N; ++i )
    {
        u_0_1 = rg.random() / (long double)rg.getM();
        rs[i] = Type( -beta*log(u_0_1) );
    }

    return rs;
}


/**
 * Return an Rayleigh~(sigma) distributed pseudorandom sequence of size N.
 */
template <typename Type>
Vector<Type> randr( int seed, const Type &sigma, int N )
{
    long double u_0_1 = 0.0;
    Random rg( seed );
    Vector<Type> rs(N);

    for( int i=0; i<N; ++i )
    {
        u_0_1 = rg.random() / (long double)rg.getM();
        rs[i] = Type( sigma * sqrt(-2.0*log(u_0_1)) );
    }

    return rs;
}


/**
 * Return a Poisson~(lambda) distributed pseudorandom sequence of size N.
 */
template <typename Type>
Vector<int> randp( int seed, const Type &lambda, int N )
{
    Random rg( seed );
    Vector<int> rs(N);

    long double u_0_1 = 0.0,
                q = exp(-lambda),
                p = 1.0;
    int k = 0;

    for( int i=0; i<N; ++i )
    {
        k = 0;
        p = 1.0;
        while( p >= q )
        {
            u_0_1 = rg.random()/(long double)rg.getM();
            p *= u_0_1;
            k++;
        }
        rs[i] = k-1;
    }

    return rs;
}


/**
 * Return a Bernoulli~(p) distributed pseudorandom sequence of size N.
 */
template <typename Type>
Vector<int> randb( int seed, const Type &p, int N )
{
    long double u_0_1 = 0.0;
    Random rg( seed );
    Vector<int> rs(N);

    for( int i=0; i<N; ++i )
    {
        u_0_1 = rg.random() / (long double)rg.getM();
        rs[i] = ( Type(u_0_1) <= p ) ? 1 : 0;
    }

    return rs;
}

测试代码:

/*****************************************************************************
 *                               random_test.cpp
 *
 * Random number generator testing.
 *
 * Zhang Ming, 2010-10, Xi'an Jiaotong University.
 *****************************************************************************/


#include <iostream>
#include <iomanip>
#include <random.h>
#include <statistics.h>


using namespace std;
using namespace splab;


typedef double  Type;
const   int     N = 100;


int main()
{
    int seed = 37;
    int low = 0, high = 100;
    Type mu = 0.0, sigma = 1.0;
    Type beta = 2.0;
    Type lambda = 4.0;
    Type p = 0.5;

    Vector<Type> rs(N);
    Vector<int> irs(N);
    Vector<double> tmp(N);

//    Random rand(seed);
//    cout << "Random Number Generator:" << endl;
//    for( int i=0; i<N; ++i )
//    {
//        cout << rand.random() << "\t";
//        if( !((i+1)%4) )
//            cout << endl;
//    }
//    cout << endl << endl;

    cout << "Uniform distribution: U ~ ( " << low << ", " << high << " )" << endl;
    for( int i=0; i<N; ++i )
        cout << randu( seed, low, high ) << "\t";
    cout << endl;
    irs = randu( seed, low, high, N );
    cout << "mean     (theoretical   generated):   "
         << mean(irs) << "\t" << (high-low)/2 << endl;
    cout << "variance (theoretical   generated):   "
         << var(irs) << "\t" << (high-low)*(high-low)/12
         << endl << endl << endl;

    cout << "Normal distribution: N ~ ( " << mu << ", " << sigma << " )" << endl;
    cout << setiosflags(ios::fixed) << setprecision(4);
    for( int i=0; i<N; ++i )
        cout << randn( seed, mu, sigma ) << "\t\t";
    cout << endl;
    rs = randn( seed, mu, sigma, N );
    cout << "mean     (theoretical   generated):   "
         << mean(rs) << "\t" << mu << endl;
    cout << "variance (theoretical   generated):   "
         << var(rs) << "\t" << sigma*sigma
         << endl << endl << endl;

    cout << "Exponential distribution: E ~ ( " << beta << " )" << endl;
    cout << setiosflags(ios::fixed) << setprecision(4);
    for( int i=0; i<N; ++i )
        cout << rande( seed, beta ) << "\t\t";
    cout << endl;
    rs = rande( seed, beta, N );
    cout << "mean     (theoretical   generated):   "
         << mean(rs) << "\t" << beta << endl;
    cout << "variance (theoretical   generated):   "
         << var(rs) << "\t" << beta*beta
         << endl << endl << endl;

    cout << "Rayleigh distribution: R ~ ( " << sigma << " )" << endl;
    cout << setiosflags(ios::fixed) << setprecision(4);
    for( int i=0; i<N; ++i )
        cout << randr( seed, sigma ) << "\t\t";
    cout << endl;
    rs = randr( seed, sigma, N );
    cout << "mean     (theoretical   generated):   "
         << mean(rs) << "\t" << sigma*sqrt(PI/2.0) << endl;
    cout << "variance (theoretical   generated):   "
         << var(rs) << "\t" << (2-PI/2)*sigma*sigma
         << endl << endl << endl;

    cout << "Poisson distribution: B ~ ( " << p << " )" << endl;
    for( int i=0; i<N; ++i )
        cout << randp( seed, lambda ) << "\t\t";
    cout << endl;
    irs = randp( seed, lambda, N );
    for( int i=0; i<N; ++i )
        tmp[i] = irs[i];
    cout << "mean     (theoretical   generated):   "
         << mean(tmp) << "\t" << lambda << endl;
    cout << "variance (theoretical   generated):   "
         << var(tmp) << "\t" << lambda
         << endl << endl << endl;

    cout << "Bernoulli distribution: B ~ ( " << p << " )" << endl;
    for( int i=0; i<N; ++i )
        cout << randb( seed, p ) << "\t\t";
    cout << endl;
    irs = randb( seed, p, N );
    for( int i=0; i<N; ++i )
        tmp[i] = irs[i];
    cout << "mean     (theoretical   generated):   "
         << mean(tmp) << "\t" << p << endl;
    cout << "variance (theoretical   generated):   "
         << var(tmp) << "\t" << p*(1-p)
         << endl << endl;

    return 0;
}

运行结果:

Uniform distribution: U ~ ( 0, 100 )
0       14      25      98      81      1       5       72      72      50
31      73      54      95      90      93      43      81      86      76
99      76      28      16      35      57      9       74      55      87
64      34      41      5       63      22      49      13      91      46
55      99      18      26      21      59      65      9       27      87
10      70      81      42      35      62      23      24      62      71
35      6       84      38      86      82      76      45      34      38
65      29      42      94      45      46      80      42      6       11
46      65      20      21      2       88      71      74      58      43
56      94      17      5       32      0       66      54      97      40

mean     (theoretical   generated):   49        50
variance (theoretical   generated):   840       833


Normal distribution: N ~ ( 0, 1 )
-0.7148         2.4179          -0.4947         -0.4264         0.0118
0.2321          -0.7548         -0.5397         -0.6533         -1.2043
1.8746          0.7539          0.0210          0.3340          0.2786
-1.8528         -0.7200         1.1448          -0.7554         -1.0937
0.1583          -2.9330         0.3818          -0.0193         -1.3456
1.4424          1.8424          -0.6886         1.6361          0.9801
1.2555          0.1753          1.6852          0.4694          -0.2241
-2.2454         -1.3620         -0.2316         -2.3769         1.0066
-0.3988         0.5761          -0.2895         -0.2019         -0.6050
-0.4084         -0.4072         -1.2768         0.9203          -0.0252
-0.5463         -0.3924         -1.2157         -0.9195         -0.2086
0.0866          0.3005          0.2995          0.8217          1.5764
0.5863          2.6818          0.4002          -0.3112         -1.5317
-1.0913         0.4349          0.7805          1.3383          0.4580
-0.8948         0.1357          -0.1333         0.7235          0.7452
-0.2743         1.0441          -0.5881         -0.1807         1.8741
0.4193          -0.1397         0.7841          0.8995          1.7939
1.0729          -1.0523         -1.0604         0.1780          -1.8157
0.8338          -0.2278         0.7157          0.8513          0.7649
0.4494          -1.6238         0.5206          -0.0174         0.1020

mean     (theoretical   generated):   0.0480    0.0000
variance (theoretical   generated):   1.0853    1.0000


Exponential distribution: E ~ ( 2.0000 )
14.1841         3.8456          2.7722          0.0209          0.4107
7.9776          5.8336          0.6396          0.6362          1.3468
2.3214          0.6173          1.2231          0.0943          0.2085
0.1379          1.6627          0.4015          0.2789          0.5368
0.0145          0.5387          2.5359          3.6533          2.0613
1.1008          4.7209          0.5873          1.1839          0.2580
0.8894          2.1468          1.7691          5.9504          0.9212
3.0099          1.3934          3.9596          0.1688          1.5344
1.1923          0.0128          3.3930          2.6764          3.0453
1.0373          0.8570          4.6297          2.5929          0.2703
4.4738          0.6858          0.4023          1.6962          2.0739
0.9469          2.8776          2.8258          0.9276          0.6701
2.0931          5.4628          0.3361          1.8864          0.2925
0.3967          0.5345          1.5645          2.1240          1.9347
0.8492          2.4460          1.7180          0.1191          1.5695
1.5185          0.4214          1.7257          5.5630          4.2447
1.5262          0.8318          3.2001          3.0868          7.5201
0.2372          0.6579          0.5884          1.0777          1.6624
1.1570          0.1181          3.4733          5.8509          2.2530
9.7065          0.8140          1.1978          0.0423          1.8098

mean     (theoretical   generated):   2.0445    2.0000
variance (theoretical   generated):   5.0310    4.0000


Rayleigh distribution: R ~ ( 1.0000 )
3.7662          1.9610          1.6650          0.1445          0.6409
2.8245          2.4153          0.7997          0.7976          1.1605
1.5236          0.7857          1.1060          0.3070          0.4566
0.3714          1.2895          0.6336          0.5281          0.7326
0.1203          0.7340          1.5924          1.9114          1.4357
1.0492          2.1728          0.7664          1.0881          0.5080
0.9431          1.4652          1.3301          2.4393          0.9598
1.7349          1.1804          1.9899          0.4108          1.2387
1.0919          0.1133          1.8420          1.6360          1.7451
1.0185          0.9257          2.1517          1.6103          0.5199
2.1151          0.8281          0.6343          1.3024          1.4401
0.9731          1.6964          1.6810          0.9631          0.8186
1.4468          2.3373          0.5798          1.3735          0.5408
0.6299          0.7311          1.2508          1.4574          1.3909
0.9215          1.5640          1.3107          0.3452          1.2528
1.2323          0.6492          1.3137          2.3586          2.0603
1.2354          0.9120          1.7889          1.7569          2.7423
0.4871          0.8111          0.7671          1.0381          1.2893
1.0756          0.3436          1.8637          2.4189          1.5010
3.1155          0.9022          1.0944          0.2056          1.3453

mean     (theoretical   generated):   1.2553    1.2533
variance (theoretical   generated):   0.4735    0.4292


Poisson distribution: B ~ ( 0.5000 )
0               4               3               11              2
5               2               3               5               3
3               5               3               7               5
3               3               2               5               1
0               6               1               4               3
4               6               9               4               5
6               5               4               5               4
4               3               4               3               3
1               8               4               6               3
4               1               5               2               3
6               2               3               1               2
7               3               5               4               3
1               3               6               7               9
1               1               2               5               7
6               7               8               5               3
6               7               7               1               5
1               6               2               3               1
3               3               2               4               4
5               2               1               3               3
1               3               4               6               5

mean     (theoretical   generated):   3.9000    4.0000
variance (theoretical   generated):   4.6566    4.0000


Bernoulli distribution: B ~ ( 0.5000 )
1               1               1               0               0
1               1               0               0               0
1               0               0               0               0
0               1               0               0               0
0               0               1               1               1
0               1               0               0               0
0               1               1               1               0
1               1               1               0               1
0               0               1               1               1
0               0               1               1               0
1               0               0               1               1
0               1               1               0               0
1               1               0               1               0
0               0               1               1               1
0               1               1               0               1
1               0               1               1               1
1               0               1               1               1
0               0               0               0               1
0               0               1               1               1
1               0               0               0               1

mean     (theoretical   generated):   0.5100    0.5000
variance (theoretical   generated):   0.2524    0.2500


Process returned 0 (0x0)   execution time : 0.203 s
Press any key to continue.

你可能感兴趣的:(随机数生成算法的C++实现)