RandGaussQ.cc

Go to the documentation of this file.
00001 // $Id:$
00002 // -*- C++ -*-
00003 //
00004 // -----------------------------------------------------------------------
00005 //                             HEP Random
00006 //                          --- RandGaussQ ---
00007 //                      class implementation file
00008 // -----------------------------------------------------------------------
00009 
00010 // =======================================================================
00011 // M Fischler     - Created 24 Jan 2000
00012 // M Fischler     - put and get to/from streams 12/13/04
00013 // =======================================================================
00014 
00015 #include "CLHEP/Random/RandGaussQ.h"
00016 #include "CLHEP/Units/PhysicalConstants.h"
00017 #include <iostream>
00018 #include <cmath>        // for std::log()
00019 
00020 namespace CLHEP {
00021 
00022 std::string RandGaussQ::name() const {return "RandGaussQ";}
00023 HepRandomEngine & RandGaussQ::engine() {return RandGauss::engine();}
00024 
00025 RandGaussQ::~RandGaussQ() {
00026 }
00027 
00028 double RandGaussQ::operator()() {
00029   return transformQuick(localEngine->flat()) * defaultStdDev + defaultMean;
00030 }
00031 
00032 double RandGaussQ::operator()( double mean, double stdDev ) {
00033   return transformQuick(localEngine->flat()) * stdDev + mean;
00034 }
00035 
00036 void RandGaussQ::shootArray( const int size, double* vect,
00037                             double mean, double stdDev )
00038 {
00039   for( double* v = vect; v != vect + size; ++v )
00040     *v = shoot(mean,stdDev);
00041 }
00042 
00043 void RandGaussQ::shootArray( HepRandomEngine* anEngine,
00044                             const int size, double* vect,
00045                             double mean, double stdDev )
00046 {
00047   for( double* v = vect; v != vect + size; ++v )
00048     *v = shoot(anEngine,mean,stdDev);
00049 }
00050 
00051 void RandGaussQ::fireArray( const int size, double* vect)
00052 {
00053   for( double* v = vect; v != vect + size; ++v )
00054     *v = fire( defaultMean, defaultStdDev );
00055 }
00056 
00057 void RandGaussQ::fireArray( const int size, double* vect,
00058                            double mean, double stdDev )
00059 {
00060   for( double* v = vect; v != vect + size; ++v )
00061     *v = fire( mean, stdDev );
00062 }
00063 
00064 //
00065 // Table of errInts, for use with transform(r) and quickTransform(r)
00066 //
00067 
00068 // Since all these are this is static to this compilation unit only, the 
00069 // info is establised a priori and not at each invocation.
00070 
00071 // The main data is of course the gaussQTables table; the rest is all 
00072 // bookkeeping to know what the tables mean.
00073 
00074 #define Table0size   250
00075 #define Table1size  1000
00076 #define TableSize   (Table0size+Table1size)
00077 
00078 #define Table0step  (2.0E-6) 
00079 #define Table1step  (5.0E-4)
00080 
00081 #define Table0scale   (1.0/Table1step)
00082 
00083 #define Table0offset 0
00084 #define Table1offset (Table0size)
00085 
00086   // Here comes the big (5K bytes) table, kept in a file ---
00087 
00088 static const float gaussTables [TableSize] = {
00089 #include "CLHEP/Random/gaussQTables.cdat"
00090 };
00091 
00092 double RandGaussQ::transformQuick (double r) {
00093   double sign = +1.0;   // We always compute a negative number of 
00094                                 // sigmas.  For r > 0 we will multiply by
00095                                 // sign = -1 to return a positive number.
00096   if ( r > .5 ) {
00097     r = 1-r;
00098     sign = -1.0;
00099   } 
00100 
00101   register int index;
00102   double  dx;
00103 
00104   if ( r >= Table1step ) { 
00105     index = int((Table1size<<1) * r);   // 1 to Table1size
00106     if (index == Table1size) return 0.0;
00107     dx = (Table1size<<1) * r - index;           // fraction of way to next bin
00108     index += Table1offset-1;    
00109   } else if ( r > Table0step ) {
00110     double rr = r * Table0scale;
00111     index = int(Table0size * rr);               // 1 to Table0size
00112     dx = Table0size * rr - index;               // fraction of way to next bin
00113     index += Table0offset-1;    
00114   } else {                              // r <= Table0step - not in tables
00115     return sign*transformSmall(r);      
00116   }                             
00117 
00118   double y0 = gaussTables [index++];
00119   double y1 = gaussTables [index];
00120   
00121   return (float) (sign * ( y1 * dx + y0 * (1.0-dx) ));
00122 
00123 } // transformQuick()
00124 
00125 double RandGaussQ::transformSmall (double r) {
00126 
00127   // Solve for -v in the asymtotic formula 
00128   //
00129   // errInt (-v) =  exp(-v*v/2)         1     1*3    1*3*5
00130   //               ------------ * (1 - ---- + ---- - ----- + ... )
00131   //               v*sqrt(2*pi)        v**2   v**4   v**6
00132 
00133   // The value of r (=errInt(-v)) supplied is going to less than 2.0E-13,
00134   // which is such that v < -7.25.  Since the value of r is meaningful only
00135   // to an absolute error of 1E-16 (double precision accuracy for a number 
00136   // which on the high side could be of the form 1-epsilon), computing
00137   // v to more than 3-4 digits of accuracy is suspect; however, to ensure 
00138   // smoothness with the table generator (which uses quite a few terms) we
00139   // also use terms up to 1*3*5* ... *13/v**14, and insist on accuracy of
00140   // solution at the level of 1.0e-7.
00141 
00142   // This routine is called less than one time in a million firings, so
00143   // speed is of no concern.  As a matter of technique, we terminate the
00144   // iterations in case they would be infinite, but this should not happen.
00145 
00146   double eps = 1.0e-7;
00147   double guess = 7.5;
00148   double v;
00149   
00150   for ( int i = 1; i < 50; i++ ) {
00151     double vn2 = 1.0/(guess*guess);
00152     double s1 = -13*11*9*7*5*3 * vn2*vn2*vn2*vn2*vn2*vn2*vn2;
00153             s1 +=    11*9*7*5*3 * vn2*vn2*vn2*vn2*vn2*vn2;
00154             s1 +=      -9*7*5*3 * vn2*vn2*vn2*vn2*vn2;
00155             s1 +=         7*5*3 * vn2*vn2*vn2*vn2;
00156             s1 +=          -5*3 * vn2*vn2*vn2;
00157             s1 +=            3 * vn2*vn2    - vn2  +    1.0;
00158     v = std::sqrt ( 2.0 * std::log ( s1 / (r*guess*std::sqrt(CLHEP::twopi)) ) );
00159     if ( std::fabs(v-guess) < eps ) break;
00160     guess = v;
00161   }
00162   return -v;
00163 
00164 } // transformSmall()
00165 
00166 std::ostream & RandGaussQ::put ( std::ostream & os ) const {
00167   int pr=os.precision(20);
00168   os << " " << name() << "\n";
00169   RandGauss::put(os);
00170   os.precision(pr);
00171   return os;
00172 }
00173 
00174 std::istream & RandGaussQ::get ( std::istream & is ) {
00175   std::string inName;
00176   is >> inName;
00177   if (inName != name()) {
00178     is.clear(std::ios::badbit | is.rdstate());
00179     std::cerr << "Mismatch when expecting to read state of a "
00180               << name() << " distribution\n"
00181               << "Name found was " << inName
00182               << "\nistream is left in the badbit state\n";
00183     return is;
00184   }
00185   RandGauss::get(is);
00186   return is;
00187 }
00188 
00189 }  // namespace CLHEP

Generated on Mon May 27 17:50:33 2013 for Geant4 by  doxygen 1.4.7