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; } }
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 ); }