Mersenne Twister

Introducción

Mirando ecuaciones para generar números aleatorios me encontré con esta implementación de Mersenne Twister. Evidentemente el código fuente estaba en C y yo a partir de él generé una clase en C++.

Es necesario saber que a diferencia de otros algoritmos, este utiliza un buffer de almacenamiento un poco grande y puede ser pesado para las aplicaciones si generamos muchas clases iguales en el código.

Código

Código *.h

#ifndef _CRANDOM_H_
#define _CRANDOM_H_
 
#define IL_RANDOM_M                397
#define IL_RANDOM_N                624
#define IL_RANDOM_MATRIX_A        0x9908b0dfU
#define IL_RANDOM_UPPER_MASK    0x80000000U
#define IL_RANDOM_LOWER_MASK    0x7fffffffU
#define IL_RANDOM_MAX            0xffffffffU
 
class CRandom 
{
    private:
 
                    unsigned int    m_vCache[IL_RANDOM_N];
                    unsigned int    m_iNext;
 
    protected:
 
                            void    SeedGen        (unsigned int inSeed);
                    unsigned int    RandGen        ();
 
    public:
 
                                    CRandom        (unsigned int inSeed = 1); 
                                    ~CRandom    ();
 
                             float    Uniform        ();
                    unsigned int    Uniform        (unsigned int inHi);
                    unsigned int    Uniform        (unsigned int inLo, unsigned int inHi);
};
#endif

Código *.cpp

#include "CRandom.h"
 
//-------------------------------------------------------------------------------------------------------
/// \brief Constructor por parametros de la clase
/// \param[in] inSeed Semilla inicial
//-------------------------------------------------------------------------------------------------------
CRandom::CRandom(unsigned int inSeed)
{
    m_iNext = 0;
    SeedGen(inSeed);
}
 
//-------------------------------------------------------------------------------------------------------
/// \brief Destructor de la clase
//-------------------------------------------------------------------------------------------------------
CRandom::~CRandom()
{
}
 
//-------------------------------------------------------------------------------------------------------
/// \brief Inicia la cache de numeros pseudoaleatorios
/// \param[in] inSeed Semilla inicial
//-------------------------------------------------------------------------------------------------------
void CRandom::SeedGen(unsigned int inSeed)
{
    m_vCache[0] = inSeed & IL_RANDOM_MAX;
 
    for(unsigned int i = 1; i < IL_RANDOM_N; i++) 
    {
        m_vCache[i] = (1812433253U * (m_vCache[i - 1] ^ (m_vCache[i - 1] >> 30)) + i);
        m_vCache[i] &= IL_RANDOM_MAX;
    }
}
 
//-------------------------------------------------------------------------------------------------------
/// \brief Generador de valores pseudo-aleatorios mediante Mersenne Twister generator
/// \ret unsigned int Valor Pseudo-aleatorio
//-------------------------------------------------------------------------------------------------------
unsigned int CRandom::RandGen()
{
    unsigned int iRnd;
    int a;
 
    iRnd = (m_vCache[m_iNext] & IL_RANDOM_UPPER_MASK) | m_vCache[(m_iNext + 1) % IL_RANDOM_N] & IL_RANDOM_LOWER_MASK;
    a = (iRnd & 0x1U) ? IL_RANDOM_MATRIX_A : 0x0U;
    m_vCache[m_iNext] = m_vCache[(m_iNext + IL_RANDOM_M) % IL_RANDOM_N] ^ (iRnd >> 1) ^ a;
 
     iRnd = m_vCache[m_iNext++];
    if(m_iNext >= IL_RANDOM_N)
    {
        m_iNext = 0;
    }
 
    iRnd ^= (iRnd >> 11);
    iRnd ^= (iRnd << 7) & 0x9d2c5680U;
    iRnd ^= (iRnd << 15) & 0xefc60000U;
    iRnd ^= (iRnd >> 18);
 
    return (iRnd);
}
 
//-------------------------------------------------------------------------------------------------------
/// \brief Devuelve un valor aleatorio entre el rango 0.0f y 1.0f
/// \ret float Valor pseudo-aleatorio
//-------------------------------------------------------------------------------------------------------
float CRandom::Uniform()
{
    return (RandGen() * (1.0f / (IL_RANDOM_MAX + 1.0f)));
}
 
//-------------------------------------------------------------------------------------------------------
/// \brief Devuelve un valor aleatorio entre el rango 0 y inHi
/// \param[in] inHi Valor maximo devuelto por esta funcion (limite superior)
/// \ret unsigned int Valor pseudo-aleatorio
//-------------------------------------------------------------------------------------------------------
unsigned int CRandom::Uniform(unsigned int inHi)
{
    return (static_cast<unsigned int>(Uniform() * inHi));
}
 
//-------------------------------------------------------------------------------------------------------
/// \brief Devuelve un valor aleatorio entre el rango inLo y inHi
/// \param[in] inLo Valor minimo devuelto por esta funcion (limite inferior)
/// \param[in] inHi Valor maximo devuelto por esta funcion (limite superior)
/// \ret unsigned int Valor pseudo-aleatorio
//-------------------------------------------------------------------------------------------------------
unsigned int CRandom::Uniform(unsigned int inLo, unsigned int inHi)
{
    return (inLo + Uniform(inHi - inLo));
}

Links

Wikipedia: Mersenne Twister

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License