Fast way to generate pseudo-random bits with a given probability of 0 or 1 for each bit
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
Generating pseudo-random bits with a controlled probability is the biased-coin version of ordinary random bit generation. The simplest method is comparing uniform random numbers against a threshold, but the best implementation depends on whether you need one bit, a large vector, or a packed bitstream. Performance usually comes from vectorization and batching, not from exotic probability math.
Use Thresholding on Uniform Random Values
If p is the probability of generating bit 1, then draw a uniform value in the interval from zero to one and compare it to p.
Simple Python example:
This is conceptually correct and often good enough for small workloads.
Vectorize for Speed with NumPy
For large bit arrays, Python loops are the main bottleneck. NumPy vectorization is much faster.
This produces a vector of zero and one values, and the sample mean should approach p_one as n grows.
Pack Bits When Memory Matters
If you need millions of bits and memory footprint matters, keep them packed instead of storing one byte per bit.
Packed storage is especially useful in simulations, compressed probabilistic models, and network-oriented workloads.
Generate Bits with Probability of Zero Instead
Some APIs define the probability of zero rather than one. The transformation is simple:
- '
P(1) = p' - '
P(0) = 1 - p'
If the caller provides p_zero, convert it:
Keep one internal convention to avoid subtle inversion bugs.
Validate the Distribution
Whenever this logic matters, verify the empirical distribution.
For one million trials, the result should be close to 0.25, though never exactly equal. This is the right way to confirm the generator behavior.
Avoid Per-Bit Heavyweight RNG Setup
The fast path is:
- initialize the PRNG once
- generate many random values in one call
- threshold them in a batch
The slow path is:
- repeated setup
- Python-level branching for every bit
- fragmented small allocations
That is why NumPy and other vectorized libraries dominate pure Python loops for this problem.
Use the Right Generator for the Job
For simulation or sampling, standard pseudo-random generators are usually fine. For security-sensitive tokens or adversarial settings, use a cryptographically secure source instead.
For example, Python secrets is designed for unpredictability, but it is slower and less suited to massive vectorized generation. Do not confuse statistical bias control with cryptographic strength.
Integer-Threshold Variant
If floating-point comparison is undesirable, you can compare against an integer threshold from a fixed range.
This can be useful in systems where integer arithmetic is preferred, though it is not usually faster in high-level Python.
Common Pitfalls
- Using Python loops for huge bit arrays when vectorization is available.
- Confusing probability of one with probability of zero.
- Expecting short samples to match the exact target probability closely.
- Using non-cryptographic PRNGs in security-sensitive contexts.
- Forgetting to validate distribution empirically after implementation changes.
Summary
- The standard solution is thresholding uniform random values.
- NumPy vectorization is the fastest common approach for large batches.
- Use
packbitswhen memory density matters. - Keep a single internal probability convention to avoid inversion errors.
- Choose the random source based on whether you need simulation speed or cryptographic strength.

