Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get true or false with a given probability

I'm trying to write a function in c++ that will return true or false based on a probability given. So, for example if the probability given was 0.634 then, 63.4% of the time the function would return true. I've tried a few different things, and failed. Any help?

like image 894
user2317084 Avatar asked Dec 01 '13 05:12

user2317084


2 Answers

If you'd like to do this in C++11, you can use its various random number engines, combined with the uniform_real_distribution to provide a good result. The following code demonstrates:

#include <random>

std::knuth_b rand_engine;  // replace knuth_b with one of the engines listed below
std::uniform_real_distribution<> uniform_zero_to_one(0.0, 1.0);

bool random_bool_with_prob( double prob )  // probability between 0.0 and 1.0
{
    return uniform_zero_to_one(rand_engine) >= prob;
}

Alternately, you can use the bernoulli_distribution, which directly gives you a bool with the specified probability. The probability it takes is the probability of returning true, so it is exactly what you need:

#include <random>

std::knuth_b rand_engine;  // replace knuth_b with one of the engines listed below

bool random_bool_with_prob( double prob )  // probability between 0.0 and 1.0
{
    std::bernoulli_distribution d(prob);
    return d(rand_engine);
}

If your probability is fixed, then you can move it out of the function like so:

#include <random>

std::knuth_b rand_engine;  // replace knuth_b with one of the engines listed below
std::bernoulli_distribution random_bool_generator( prob );  // replace "prob" with your probability

bool random_bool()
{
    return random_bool_generator( rand_engine );
}

Or if you want to get fancier still, you can bind them together:

#include <random>
#include <functional>

std::knuth_b rand_engine;  // replace knuth_b with one of the engines listed below
std::bernoulli_distribution random_bool_generator( prob );  // replace "prob" with your probability

auto random_bool = std::bind( random_bool_generator, rand_engine )

// Now call random_bool() to get your random boolean with the specified probability.

You can replace knuth_b with any of the standard engines:

  • std::linear_congruential_engine
  • std::mersenne_twister_engine
  • std::subtract_with_carry_engine

or many more, which are versions of the above, parameterized various ways. My reference lists the following:

  • std::default_random_engine (Implementation defined.)
  • std::minstd_rand0
  • std::minstd_rand
  • std::mt19937
  • std::mt19337_64
  • std::ranlux24_base
  • std::ranlux48_base
  • std::ranlux24
  • std::ranlux48
  • std::knuth_b

And if that isn't enough, there are some standard adaptors that can further perturb the random number sequence:

  • std::discard_block_engine which adapts an engine by discarding a given number of generated values each time.
  • std::independent_bits_engine which adapts an engine to produce random values with a specified number of bits. (Not important to your particular need.)
  • std::shuffle_order_engine which adapts an engine by permutation of the order of their generated values.

The generators in the second list are derived from the base generators in the first list, either with specific parameters, adaptors or both. For example, knuth_b is equivalent to shuffle_order_engine< linear_congruential_engine< uint32_t, 16807, 0, 2147483647>, 256>, according to my reference book. (The C++ Standard Library, Second Edition, by Nicolai Josuttis, a great reference work.)

You can find more information online, including this brief introduction here: http://en.wikipedia.org/wiki/C++11#Extensible_random_number_facility

There's more documentation here: http://en.cppreference.com/w/cpp/numeric/random

You will probably want to modify the declaration of rand_engine above to provide a seed. The example above uses the default seed. See cppreference.com for how to seed it if you want a different seed.

like image 70
Joe Z Avatar answered Oct 23 '22 05:10

Joe Z


#include <stdlib.h>
bool prob_true(double p){
    return rand()/(RAND_MAX+1.0) < p;
}

Logic:

rand() returns a random number between 0 and RAND_MAX (including both), with equal probability for each number. So by dividing the result by RAND_MAX we get a random number between 0 and 1. This allows us to choose a area of - in your example 63.4% of this segment, e.g. from 0 to 0.634 - and check if the result fell in that area.

Now comes the tricky part: we don't want to get both 0 and 1! Why? Because we want probability 0 to never be true, that's why we need the <p (rather than the <=p) - so that when p=0 you'll never get true.

However, if you can also have 1 as the result, then in the case where p=1 there is a very small chance you get false!

That's why instead of dividing by MAX_RAND you divide by MAX_RAND+1.0. Also note that I added 1.0 instead of 1 to turn the number into a double (otherwise I might get an overflow if MAX_RAND==INT_MAX)

Finally, here's an alternate implementation without the division:

#include <stdlib.h>
bool prob_true(double p){
    return rand() < p * (RAND_MAX+1.0);
}
like image 4
rabensky Avatar answered Oct 23 '22 07:10

rabensky