double librandom::GammaRandomDev::unscaled_gamma( RngPtr r ) const { // algorithm depends on order a if ( a == 1 ) return -std::log( r->drandpos() ); else if ( a < 1 ) { // Johnk's rejection algorithm, see [1], p. 418 double X; double Y; double S; do { X = std::pow( r->drand(), ju ); Y = std::pow( r->drand(), jv ); S = X + Y; } while ( S > 1 ); if ( X > 0 ) return -std::log( r->drandpos() ) * X / S; else return 0; } else { // Best's rejection algorithm, see [1], p. 410 bool accept = false; double X = 0.0; do { const double U = r->drand(); if ( U == 0 || U == 1 ) continue; // accept guaranteed false const double V = r->drand(); const double W = U * ( 1 - U ); // != 0 const double Y = std::sqrt( bc / W ) * ( U - 0.5 ); X = bb + Y; if ( X > 0 ) { const double Z = 64 * W * W * W * V * V; accept = Z <= 1 - 2 * Y * Y / X; if ( !accept ) accept = std::log( Z ) <= 2 * ( bb * std::log( X / bb ) - Y ); } } while ( !accept ); return X; } }
unsigned long librandom::BinomialRandomDev::uldev(RngPtr rng) const { assert(rng.valid()); // BP algorithm (steps numbered as in Fishman 1979) // Steps 1-7 are in init_() unsigned long X; double V; long Y; bool not_finished = 1; while (not_finished) { //8,9 X = n_+1; while( X > n_) { X = poisson_dev_.uldev(rng); } //10 V = exp_dev_(rng); //11 Y = n_ - X; //12 if ( V < static_cast<double>(m_-Y)*phi_ - f_[m_+1] + f_[Y+1] ) { not_finished = 1; } else { not_finished = 0; } } if (p_ <= 0.5) { return X; } else { return static_cast<unsigned long>(Y); } }
double librandom::NormalRandomDev::operator()( RngPtr r ) const { // Box-Muller algorithm, see Knuth TAOCP, vol 2, 3rd ed, p 122 // we waste one number double V1; double V2; double S; do { V1 = 2 * r->drand() - 1; V2 = 2 * r->drand() - 1; S = V1 * V1 + V2 * V2; } while ( S >= 1 ); if ( S != 0 ) S = V1 * std::sqrt( -2 * std::log( S ) / S ); return mu_ + sigma_ * S; }
double librandom::LognormalRandomDev::operator()( RngPtr r ) const { // We could forward here to a NormalRandomDev, but that would // require keeping such an object. Given that the Box-Muller code // is short, we just duplicate it here. // Box-Muller algorithm, see Knuth TAOCP, vol 2, 3rd ed, p 122 // we waste one number double V1; double V2; double S; do { V1 = 2 * r->drand() - 1; V2 = 2 * r->drand() - 1; S = V1 * V1 + V2 * V2; } while ( S >= 1 ); if ( S != 0 ) S = V1 * std::sqrt( -2 * std::log( S ) / S ); return std::exp( mu_ + sigma_ * S ); }
long librandom::PoissonRandomDev::ldev( RngPtr r ) const { // make sure we have an RNG assert( r.valid() ); // the result for lambda == 0 is well defined, // added the following two lines of code // Diesmann, 26.7.2002 if ( mu_ == 0.0 ) return 0; unsigned long K = 0; // candidate if ( mu_ < 10.0 ) { // Case B in Ahrens & Dieter: table lookup double U = ( *r )(); K = 0; // be defensive while ( U > P_[ K ] && K != n_tab_ ) ++K; return K; // maximum value: K == n_tab_ == 46 } else { // Case A in Ahrens & Dieter // Step N ****************************************************** // draw normal random number /* Ratio method (Kinderman-Monahan); see Knuth v2, 3rd ed, p130 */ /* K+M, ACM Trans Math Software 3 (1977) 257-260. */ double U, V, T; do { V = ( *r )(); do { U = ( *r )(); } while ( U == 0 ); /* Const 1.715... = sqrt(8/e) */ T = 1.71552776992141359295 * ( V - 0.5 ) / U; } while ( T * T > -4.0 * std::log( U ) ); /* maximum for T at this point: T*T <= -4 ln U ~ -4 * ln 1e-308 ~ 2837 => |T| < 54 */ double G = mu_ + s_ * T; if ( G >= 0 ) { K = static_cast< unsigned long >( std::floor( G ) ); // Step I ****************************************************** // immediate acceptance if ( K >= L_ ) { return K; } // Step S ****************************************************** // squeeze acceptance U = ( *r )(); if ( d_ * U >= std::pow( mu_ - K, 3 ) ) { return K; } // Step P : see init ****************************************** // Step Q **************************************************** double px, py, fx, fy; proc_f_( K, px, py, fx, fy ); // re-use U from step S, okay since we only apply tighter // squeeze criterium if ( fy * ( 1 - U ) <= py * std::exp( px - fx ) ) { return K; } // fall through to E } // Step E ****************************************************** double critH; do { double E; do { U = ( *r )(); E = -std::log( ( *r )() ); U = U + U - 1; T = U >= 0 ? 1.8 + E : 1.8 - E; } while ( T <= -0.6744 ); /* maximum for T at this point: 0 < E < - ln 1e-308 ~ 709 => |T| < 710 */ // Step H ****************************************************** K = static_cast< unsigned long >( std::floor( mu_ + s_ * T ) ); double px, py, fx, fy; proc_f_( K, px, py, fx, fy ); critH = py * std::exp( px + E ) - fy * std::exp( fx + E ); } while ( c_ * std::abs( U ) > critH ); return K; } // mu < 10 }