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