NormalDistribution.hpp
Go to the documentation of this file.
00001 /**
00002  * \file NormalDistribution.hpp
00003  * \brief Header for NormalDistribution
00004  *
00005  * Compute normal deviates.
00006  *
00007  * Written by Charles Karney <charles@karney.com> and licensed under the LGPL.
00008  * For more information, see http://randomlib.sourceforge.net/
00009  **********************************************************************/
00010 
00011 #if !defined(NORMALDISTRIBUTION_HPP)
00012 #define NORMALDISTRIBUTION_HPP "$Id: NormalDistribution.hpp 6723 2010-01-11 14:20:10Z ckarney $"
00013 
00014 #include <cmath>                // for std::log
00015 
00016 namespace RandomLib {
00017   /**
00018    * \brief Normal deviates
00019    *
00020    * Sample from the normal distribution.
00021    *
00022    * This uses the ratio method; see Knuth, TAOCP, Vol 2, Sec. 3.4.1.C,
00023    * Algorithm R.  Unlike the Box-Muller method which generates two normal
00024    * deviates at a time, this method generates just one.  This means that this
00025    * class has no state that needs to be saved when checkpointing a
00026    * calculation.  Original citation is\n A. J. Kinderman, J. F. Monahan,\n
00027    * Computer Generation of Random Variables Using the Ratio of Uniform
00028    * Deviates,\n ACM TOMS 3, 257-260 (1977).
00029    *
00030    * Improved "quadratic" bounds are given by\n J. L. Leva,\n A Fast Normal
00031    * Random Number Generator,\n ACM TOMS 18, 449-453 and 454-455 (1992).
00032    *
00033    * The log is evaluated 1.369 times per normal deviate with no bounds, 0.232
00034    * times with Knuth's bounds, and 0.012 times with the quadratic bounds.
00035    * Time is approx 0.3 us per deviate (1GHz machine, optimized, RealType =
00036    * float).
00037    *
00038    * Example
00039    * \code
00040    *   #include "RandomLib/NormalDistribution.hpp"
00041    *
00042    *   RandomLib::Random r;
00043    *   std::cout << "Seed set to " << r.SeedString() << std::endl;
00044    *   RandomLib::NormalDistribution<double> normdist;
00045    *   std::cout << "Select from normal distribution:";
00046    *   for (size_t i = 0; i < 10; ++i)
00047    *       std::cout << " " << normdist(r);
00048    *   std::cout << std::endl;
00049    * \endcode
00050    **********************************************************************/
00051   template<typename RealType = double> class NormalDistribution {
00052   public:
00053     /**
00054      * The type returned by NormalDistribution::operator()(Random&)
00055      **********************************************************************/
00056     typedef RealType result_type;
00057     /**
00058      * Return a sample of type RealType from the normal distribution with mean
00059      * \a mu and standard deviation <i>sigma</i>.
00060      *
00061      * For \a mu = 0 and \a sigma = 1 (the defaults), the distribution is
00062      * symmetric about zero and is nonzero.  The maximum result is less than 2
00063      * sqrt(log(2) \e p) where \e p is the precision of real type RealType.
00064      * The minimum positive value is approximately 1/2<sup><i>p</i>+1</sup>.
00065      * Here \e p is the precision of real type RealType.
00066      **********************************************************************/
00067     template<class Random>
00068     RealType operator()(Random& r, RealType mu = RealType(0),
00069                         RealType sigma = RealType(1)) const throw();
00070   };
00071 
00072   template<typename RealType> template<class Random> inline RealType
00073   NormalDistribution<RealType>::operator()(Random& r, RealType mu,
00074                                            RealType sigma) const throw() {
00075     // N.B. These constants can be regarded as "exact", so that the same number
00076     // of sig. figs. are used in all versions.  (They serve the "bracket" the
00077     // real boundary specified by the log expression.)
00078     const RealType
00079       m =  RealType( 1.7156  ), // sqrt(8/e) (rounded up)
00080       s  = RealType( 0.449871), // Constants from Leva
00081       t  = RealType(-0.386595),
00082       a  = RealType( 0.19600 ),
00083       b  = RealType( 0.25472 ),
00084       r1 = RealType( 0.27597 ),
00085       r2 = RealType( 0.27846 );
00086     RealType u, v, Q;
00087     do {                        // This loop is executed 1.369 times on average
00088       // Pick point P = (u, v)
00089       u =  r.template FixedU<RealType>(); // Sample u in (0,1]
00090       v = m * r.template FixedS<RealType>(); // Sample v in (-m/2, m/2); avoids 0.
00091       // Compute quadradric form Q
00092       const RealType x = u - s;
00093       const RealType y = (v < 0 ? -v : v) - t; // Sun has no long double abs!
00094       Q = x*x + y * (a*y - b*x);
00095     } while ( Q >= r1 &&        // accept P if Q < r1
00096               ( Q > r2 ||       // reject P if Q > r2
00097                 v*v > - 4 * u*u * std::log(u) ) ); // accept P if v^2 <= ...
00098     return mu + sigma * (v / u); // return the slope of P (note u != 0)
00099   }
00100 } // namespace RandomLib
00101 
00102 #endif // NORMALDISTRIBUTION_HPP