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