Abseil Random

By Andy Soffer, Engineer

We are happy to announce the arrival of the Abseil Random library, providing simple tools for generating random numbers and testing code that uses random numbers.

Abseil now includes a random number generation library, which can be found in absl/random/. The library includes

  • Drop-in replacements for some distributions available through the standard library <random> header, with some modest performance improvements.
  • Two good default bit generators for users without the domain expertise to make meaningful choices amongst the many options available in the standard.
  • Distribution functions that provide a simple interface for generating random values.
  • A bit-generator (absl::MockingBitGen) that, with GoogleTest, enables deterministic testing of application code.

This blog post discusses how to get started using this library. For a more detailed explanation on the design of the helper functions and testing facilities provided by this library, take a look at our design note.

Happy sampling!

Bit Generation

We provide several bit generators:

  • absl::BitGen: A general-purpose random bit generator whose default constructor is seeded correctly.
  • absl::InsecureBitGen: A fast bit generator for performance-sensitive use cases when the computational cost of absl::BitGen is prohibitively expensive.
  • absl::MockingBitGen: A bit generator to be used only in unit tests. For details, see the design note.
  • absl::BitGenRef: A type-erased reference to a bit generator. Used primarily as a means of swapping bit generators at run-time.

For the bit generator, we recommend using absl::BitGen unless you have specific performance requirements and have thoroughly vetted absl::InsecureBitGen for your use case. Neither absl::BitGen nor absl::InsecureBitGen are guaranteed to be cryptographically secure.

Bit generators are well-seeded by default, so default constructing an absl::BitGen is a correct and intended usage. All of our bit generators provide no stability guarantees. The implementation may change at any time, and the sequence of variates produced need not be the same, even between two invocations of the same process.

Distribution Function Templates

Distribution function templates are thin wrappers around distribution objects that provide a straightforward API for getting randomness. A generator should be passed to a distribution function as in the examples below:

// Using the C++ standard <random> facilities
std::random_device rd;
std:mt19937 gen(rd());

int die_roll = std::uniform_int_distribution<>(1, 6)(gen);
bool fair_coin_landed_heads = std::bernoulli_distribution(0.5)(gen);

// Using Abseil Random
absl::BitGen gen;

int die_roll = absl::Uniform(absl::IntervalClosedClosed, gen, 1, 6);
bool fair_coin_landed_heads = absl::Bernoulli(gen, 0.5);

The full list of distribution functions provided can be seen in distributions.h.

Testing Facilities

For testing functions that require randomness, we provide absl::MockingBitGen, a bit generator that enables a test author to specify the result of a call to a distribution. As you will notice in the code-snippet below, this is not done via a deterministic bit generator (for reasons discusesd in the design note). Rather, absl::MockingBitGen allows the user to specify the result not of the bit generator, but of the entire random sample. The design note goes into detail about why we believe this is a maintainable approach to testing code with random behavior. These testing facilities rely on GoogleTest.

using ::testing::_;
using ::testing::Lt;
using ::testing::Return;

int ComputeValue(absl::BitGenRef gen) {
  if (absl::Bernoulli(gen, 0.00001)) {
    return 10
  } else {
    return 0;
  }
}

TEST(ComputeValueTest, UnlikelyCase) {
  absl::MockingBitGen gen;
  ON_CALL(absl::MockBernoulli(), Call(gen, Lt(0.01))
      .WillByDefault(Return(true));

  EXPECT_EQ(ComputeValue(gen), 10);
}

Subscribe to the Abseil Blog