Click here to Skip to main content
15,892,674 members
Articles / Programming Languages / C++

A Normal / Exponential Random Generator and Histogram Class

Rate me:
Please Sign up or sign in to vote.
4.73/5 (11 votes)
2 Dec 20024 min read 276.7K   8.1K   55  
A fast random generator with normal or exponential distribution + a histogram class
In this article, you will find a fast generator for Random Variable, namely normal and exponential distributions. It is based on George Marsaglia's and Wai Wan Tsang's work.
// Histogram.h: interface for the CHistogram class.
//
//////////////////////////////////////////////////////////////////////

#if !defined(AFX_HISTOGRAM_H__DF74A789_2878_4CB0_BAA9_125272F0E7E1__INCLUDED_)
#define AFX_HISTOGRAM_H__DF74A789_2878_4CB0_BAA9_125272F0E7E1__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include <valarray>

/*! \brief A histogram class

  This class computes the histogram of a vector.

  Moment function taken from Numerical recipies...
*/
template<class T>
class CHistogram  
{
public:
	//! \name Constructors
	//@{
	/*! Default constructor
	\param nCounters the number of histogram containers (default value is 10)
	*/
	CHistogram<T>(UINT nCounters = 10);
	virtual ~CHistogram<T>()				{ Clear();};
	//@}

	//! \name Histogram computation, update
	//@{
	/*! Computes histogram of vector v
	\param v vector to compute histogram
	\param bComputeMinMax set to true if min/max of v have to be used to get the histogram limits	
	
	This function computes the histogram of v and stores it internally.
	\sa Update, GetHistogram
	*/
	void Compute( const std::vector<T>& v, bool bComputeMinMax = true);
	//! Update histogram with the vector v
	void Update( const std::vector<T>& v);
	//! Update histogram with t
	void Update( const T& t);
	//@}

	//! \name Resetting functions
	//@{
	//! Resize the histogram. Warning this function clear the histogram.
	void Resize( UINT nCounters );
	//! Clears the histogram
	void Clear()						{ m_vCounters.clear();};
	//@}

	//! \name Setters
	//@{
	/*! This function sets the minimum of the histogram spectrum. 
	The spectrum is not recomputed, use it with care
	*/
	void SetMinSpectrum( const T& tMin )					{	m_tMin = tMin; ComputeStep();};
	/*! This function sets the minimum of the histogram spectrum. 
	The spectrum is not recomputed, use it with care
	*/
	void SetMaxSpectrum( const T& tMax )					{	m_tMax = tMax; ComputeStep();};
	//@}
	//! \name Getters
	//@{
	//! return minimum of histogram spectrum
	const T& GetMinSpectrum() const							{	return m_tMin;};
	//! return maximum of histogram spectrum
	const T& GetMaxSpectrum() const							{	return m_tMax;};
	//! return step size of histogram containers
	double GetStep() const									{	return m_dStep;};
	//! return number of points in histogram
	UINT GetSum() const;
	//! return number of containers
	UINT GetSize() const							{	return m_vCounters.size();};
	//! returns i-th counter
	UINT operator [] (UINT i) const					{	ASSERT( i < m_vCounters.size() ); return m_vCounters[i];};
	//! return the computed histogram
	const std::vector<UINT>& GetHistogram() const	{	return m_vCounters;};
	//! return the computed histogram, in doubles
	std::vector<double> GetHistogramD() const;
	//! return the computed histogram normalized to 1
	std::vector<double> GetNormalizedHistogram() const;
	//! returns left containers position
	std::vector<double> GetLeftContainers() const;
	//! returns center containers position
	std::vector<double> GetCenterContainers() const;
	//@}


private:
	//! Computes the step
	void ComputeStep()								{	m_dStep = (double)(((double)(m_tMax-m_tMin)) / (m_vCounters.size()-1));};
protected:
	std::vector<UINT> m_vCounters;
	T m_tMin;
	T m_tMax;
	double m_dStep;
};

template<class T>
CHistogram<T>::CHistogram<T>(UINT nCounters)
: m_vCounters(nCounters,0), m_tMin(0), m_tMax(0), m_dStep(0)
{

}

template<class T>
void CHistogram<T>::Resize( UINT nCounters )
{
	Clear();

	m_vCounters.resize(nCounters,0);

	ComputeStep();
}

template<class T>
void CHistogram<T>::Compute( const std::vector<T>& v, bool bComputeMinMax)
{
	using namespace std;
	UINT i;
	int index;

	if (m_vCounters.empty())
		return;

	if (bComputeMinMax)
	{
		m_tMax = m_tMin = v[0];
		for (i=1;i<v.size();i++)
		{
			m_tMax = __max( m_tMax, v[i]);
			m_tMin = __min( m_tMin, v[i]);
		}
	}

	ComputeStep();

	for (i = 0;i < v.size() ; i++)
	{
		index=(int) floor( ((double)(v[i]-m_tMin))/m_dStep ) ;

		if (index >= m_vCounters.size() || index < 0)
			return;

		m_vCounters[index]++;
	}
}

template<class T>
void CHistogram<T>::Update( const std::vector<T>& v)
{
	if (m_vCounters.empty())
		return;

	ComputeStep();

	double uSize = m_vCounters.size();

	int index;
	for (UINT i = 0;i < uSize ; i++)
	{
		index = (int)floor(((double)(v[i]-m_tMin))/m_dStep);

		if (index >= m_vCounters.size() || index < 0)
			return;

		m_vCounters[index]++;
	}
}

template<class T>
void CHistogram<T>::Update( const T& t)
{	
	int index=(int) floor( ((double)(t-m_tMin))/m_dStep ) ;

	if (index >= m_vCounters.size() || index < 0)
		return;

	m_vCounters[index]++;
};

template<class T>
std::vector<double> CHistogram<T>::GetHistogramD() const
{
	std::vector<double> v(m_vCounters.size());
	for (UINT i = 0;i<m_vCounters.size(); i++)
		v[i]=(double)m_vCounters[i];

	return v;
}

template <class T>
std::vector<double> CHistogram<T>::GetLeftContainers() const
{
	std::vector<double> vX( m_vCounters.size());

	for (UINT i = 0;i<m_vCounters.size(); i++)
		vX[i]= m_tMin + i*m_dStep;

	return vX;
}

template <class T>
std::vector<double> CHistogram<T>::GetCenterContainers() const
{
	std::vector<double> vX( m_vCounters.size());

	for (UINT i = 0;i<m_vCounters.size(); i++)
		vX[i]= m_tMin + (i+0.5)*m_dStep;

	return vX;
}

template <class T>
UINT CHistogram<T>::GetSum() const
{
	UINT uSum = 0;
	for (UINT i = 0;i<m_vCounters.size(); i++)
		uSum+=m_vCounters[i];

	return uSum;
}

template <class T>
std::vector<double> CHistogram<T>::GetNormalizedHistogram() const
{
	std::vector<double> vNormCounters( m_vCounters.size());
	double dSum = (double)GetSum();

	for (UINT i = 0;i<m_vCounters.size(); i++)
	{
		vNormCounters[i]= (double)m_vCounters[i]/dSum;
	}

	return vNormCounters;
}


#endif // !defined(AFX_HISTOGRAM_H__DF74A789_2878_4CB0_BAA9_125272F0E7E1__INCLUDED_)

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.


Written By
Engineer
United States United States
Jonathan de Halleux is Civil Engineer in Applied Mathematics. He finished his PhD in 2004 in the rainy country of Belgium. After 2 years in the Common Language Runtime (i.e. .net), he is now working at Microsoft Research on Pex (http://research.microsoft.com/pex).

Comments and Discussions