@ -27,7 +27,16 @@
namespace absl {
namespace absl {
namespace base_internal {
namespace base_internal {
// The algorithm generates a random number between 0 and 1 and applies the
// inverse cumulative distribution function for an exponential. Specifically:
// Let m be the inverse of the sample period, then the probability
// distribution function is m*exp(-mx) so the CDF is
// p = 1 - exp(-mx), so
// q = 1 - p = exp(-mx)
// log_e(q) = -mx
// -log_e(q)/m = x
// log_2(q) * (-log_e(2) * 1/m) = x
// In the code, q is actually in the range 1 to 2**26, hence the -26 below
int64_t ExponentialBiased : : GetSkipCount ( int64_t mean ) {
int64_t ExponentialBiased : : GetSkipCount ( int64_t mean ) {
if ( ABSL_PREDICT_FALSE ( ! initialized_ ) ) {
if ( ABSL_PREDICT_FALSE ( ! initialized_ ) ) {
Initialize ( ) ;
Initialize ( ) ;
@ -63,47 +72,6 @@ int64_t ExponentialBiased::GetStride(int64_t mean) {
return GetSkipCount ( mean - 1 ) + 1 ;
return GetSkipCount ( mean - 1 ) + 1 ;
}
}
// The algorithm generates a random number between 0 and 1 and applies the
// inverse cumulative distribution function for an exponential. Specifically:
// Let m be the inverse of the sample period, then the probability
// distribution function is m*exp(-mx) so the CDF is
// p = 1 - exp(-mx), so
// q = 1 - p = exp(-mx)
// log_e(q) = -mx
// -log_e(q)/m = x
// log_2(q) * (-log_e(2) * 1/m) = x
// In the code, q is actually in the range 1 to 2**26, hence the -26 below
int64_t ExponentialBiased : : Get ( int64_t mean ) {
if ( ABSL_PREDICT_FALSE ( ! initialized_ ) ) {
Initialize ( ) ;
}
uint64_t rng = NextRandom ( rng_ ) ;
rng_ = rng ;
// Take the top 26 bits as the random number
// (This plus the 1<<58 sampling bound give a max possible step of
// 5194297183973780480 bytes.)
// The uint32_t cast is to prevent a (hard-to-reproduce) NAN
// under piii debug for some binaries.
double q = static_cast < uint32_t > ( rng > > ( kPrngNumBits - 26 ) ) + 1.0 ;
// Put the computed p-value through the CDF of a geometric.
double interval = bias_ + ( std : : log2 ( q ) - 26 ) * ( - std : : log ( 2.0 ) * mean ) ;
// Very large values of interval overflow int64_t. To avoid that, we will cheat
// and clamp any huge values to (int64_t max)/2. This is a potential source of
// bias, but the mean would need to be such a large value that it's not likely
// to come up. For example, with a mean of 1e18, the probability of hitting
// this condition is about 1/1000. For a mean of 1e17, standard calculators
// claim that this event won't happen.
if ( interval > static_cast < double > ( std : : numeric_limits < int64_t > : : max ( ) / 2 ) ) {
// Assume huge values are bias neutral, retain bias for next call.
return std : : numeric_limits < int64_t > : : max ( ) / 2 ;
}
int64_t value = std : : max < int64_t > ( 1 , std : : round ( interval ) ) ;
bias_ = interval - value ;
return value ;
}
void ExponentialBiased : : Initialize ( ) {
void ExponentialBiased : : Initialize ( ) {
// We don't get well distributed numbers from `this` so we call NextRandom() a
// We don't get well distributed numbers from `this` so we call NextRandom() a
// bunch to mush the bits around. We use a global_rand to handle the case
// bunch to mush the bits around. We use a global_rand to handle the case