【发布时间】:2013-12-01 05:22:52
【问题描述】:
我正在尝试用 C++ 编写一个函数,该函数将根据给定的概率返回真或假。因此,例如,如果给定的概率是 0.634,那么函数将在 63.4% 的时间返回 true。我尝试了一些不同的东西,但都失败了。有什么帮助吗?
【问题讨论】:
-
您究竟尝试了什么?
标签: c++ random numbers probability
我正在尝试用 C++ 编写一个函数,该函数将根据给定的概率返回真或假。因此,例如,如果给定的概率是 0.634,那么函数将在 63.4% 的时间返回 true。我尝试了一些不同的东西,但都失败了。有什么帮助吗?
【问题讨论】:
标签: c++ random numbers probability
如果您想在 C++11 中执行此操作,您可以使用它的各种随机数引擎,并结合 uniform_real_distribution 来提供良好的结果。以下代码演示:
#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;
}
或者,您可以使用bernoulli_distribution,它会以指定的概率直接为您提供bool。它所用的概率就是返回true的概率,所以正是你所需要的:
#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);
}
如果您的概率是固定的,那么您可以像这样将其移出函数:
#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 );
}
或者如果你想更漂亮,你可以把它们绑定在一起:
#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.
您可以将knuth_b 替换为任何标准引擎:
std::linear_congruential_enginestd::mersenne_twister_enginestd::subtract_with_carry_engine或更多,它们是上述版本,以各种方式参数化。我的参考文献列出了以下内容:
std::default_random_engine(已定义实现。)std::minstd_rand0std::minstd_randstd::mt19937std::mt19337_64std::ranlux24_basestd::ranlux48_basestd::ranlux24std::ranlux48std::knuth_b如果这还不够,还有一些标准适配器可以进一步扰乱随机数序列:
std::discard_block_engine 通过每次丢弃给定数量的生成值来适应引擎。std::independent_bits_engine 调整引擎以生成具有指定位数的随机值。 (对您的特定需求并不重要。)std::shuffle_order_engine 通过排列生成值的顺序来调整引擎。第二个列表中的生成器派生自第一个列表中的基本生成器,可以使用特定参数、适配器或两者兼有。例如,根据我的参考书,knuth_b 等同于shuffle_order_engine< linear_congruential_engine< uint32_t, 16807, 0, 2147483647>, 256>。 (C++ 标准库,第二版,作者 Nicolai Josuttis,一本很棒的参考书。)
您可以在网上找到更多信息,包括这里的简要介绍:http://en.wikipedia.org/wiki/C++11#Extensible_random_number_facility
这里有更多文档:http://en.cppreference.com/w/cpp/numeric/random
您可能需要修改上面rand_engine 的声明以提供种子。上面的示例使用默认种子。如果您想要不同的种子,请参阅 cppreference.com 了解如何播种。
【讨论】:
std::bernoulli_distribution 会比 std::uniform_real_distribution 做得更好。
uniform_zero_to_one(rand_engine) <= prob;。
#include <stdlib.h>
bool prob_true(double p){
return rand()/(RAND_MAX+1.0) < p;
}
逻辑:
rand() 返回一个介于0 和RAND_MAX(包括两者)之间的随机数,每个数字的概率相等。所以通过将结果除以RAND_MAX,我们得到一个介于0 和1 之间的随机数。这允许我们选择一个区域 - 在您的示例中,该部分的 63.4%,例如从0 到0.634 - 并检查结果是否落在该区域。
现在是棘手的部分:我们不想同时获得0 和1!为什么?因为我们希望概率0 永远不会为真,这就是为什么我们需要<p(而不是<=p)——这样当p=0 时你永远不会成为真的。
但是,如果您也可以将1 作为结果,那么在p=1 的情况下,您得到错误的可能性非常小!
这就是为什么不是除以MAX_RAND 而是除以MAX_RAND+1.0。另请注意,我添加了1.0 而不是1 将数字转换为双精度(否则如果MAX_RAND==INT_MAX 可能会溢出)
最后,这是一个没有除法的替代实现:
#include <stdlib.h>
bool prob_true(double p){
return rand() < p * (RAND_MAX+1.0);
}
【讨论】:
rand()吗?