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?
问题:
回答1:
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.
回答2:
#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);
}