C++11中的STL具有内置的随机数生成方法,这些方法比rand()
更优秀。您可以通过一个随机整数来模拟一个随机布尔值,该整数为0或1:
#include <iostream>
#include <random>
int main(int argc, char *argv[]) {
auto gen = std::bind(std::uniform_int_distribution<>(0,1),std::default_random_engine());
const unsigned int N = 100;
unsigned int numTrue = 0;
unsigned int numFalse = 0;
for (int i = 0; i < 100; ++i) {
bool b = gen();
if (b) ++ numTrue;
else ++numFalse;
}
std::cout << numTrue << " TRUE, " << numFalse << " FALSE" << std::endl;
}
您可以在标准的C++参考文献中找到有关此库的更多详细信息。例如,如果您想要除了“真”和“假”之外的其他值的50/50比率,那么您可以创建一个介于0和1之间的随机浮点数,并将小于某个阈值z的值设置为真,否则为假。
关于出现长时间连续相同布尔值的原因
我还没有解释为什么您的代码会出现30个“真”或“假”的连续值。虽然rand()不应再使用,并且您的代码中似乎存在一些不必要的加减一和零,但不应该出现这样的问题。但是,我现在意识到您问题中的文本含义不明确。如果您连续运行并退出程序30次,则应该预期看到重复的值-即使使用我的代码也是如此。大多数随机数生成器实际上是伪随机数生成器。每次运行程序时,它们都将产生相同的随机数字序列;这对于结果的一致性非常重要。但是,在程序运行时(例如将您的randomBool()放入循环中),您不应该看到如此长的连续段,因为它们将非常不可能。
长时间连续相同布尔值的不可能性
我很惊讶收到评论表示不同意我的观点,即随机布尔值的30个“真”或“假”的连续段是不可能的(当真或假等概率时)。我意识到人们对概率的一个常见误解是“运气”会尝试平衡事物,所以如果硬币抛掷已经连续出现几次正面朝上,则宇宙将尝试纠正这一点,并使反面更有可能。由于这种误解,人们低估了得到所有正面或所有反面的连续段的可能性,我认为这个答案和主要问题的评论的动机是纠正这个常见错误。
然而,存在一个真正的原因,长时间的连续段(特别是30个)越来越不可能。使用随机无偏硬币投掷的术语,每个独立同分布的硬币投掷只有50%的机会与前一个相同。因此,长连续段的概率随着连续段长度的增加呈指数级下降。对于长度为L的连续段,全是正面朝上的概率是2^L;任一类型的连续段概率是2^L或1/2^(L-1)。以下是一些示例代码:
#include <iostream>
#include <random>
#include <map>
bool randomBool() {
static auto gen = std::bind(std::uniform_int_distribution<>(0,1),std::default_random_engine());
return gen();
}
int main(int argc, char *argv[]) {
const unsigned int N = 1e8;
std::map<unsigned int,unsigned int> histogram;
bool current = randomBool();
unsigned int currentLength = 1;
for (int i = 0; i < N; ++i) {
bool b = randomBool();
if (b == current) {
++currentLength;
} else {
auto it = histogram.find(currentLength);
if (it != histogram.end())
it->second += 1;
else
histogram.insert(std::make_pair(currentLength,1));
currentLength = 1;
}
current = b;
}
for (auto pair : histogram)
std::cout << "STREAK LENGTH " << pair.first << " OCCURS " << pair.second << " TIMES" << std::endl;
}
输出的直方图为:
STREAK LENGTH 1 OCCURS 25011106 TIMES
STREAK LENGTH 2 OCCURS 12503578 TIMES
STREAK LENGTH 3 OCCURS 6249056 TIMES
STREAK LENGTH 4 OCCURS 3125508 TIMES
STREAK LENGTH 5 OCCURS 1560812 TIMES
STREAK LENGTH 6 OCCURS 781206 TIMES
STREAK LENGTH 7 OCCURS 390143 TIMES
STREAK LENGTH 8 OCCURS 194748 TIMES
STREAK LENGTH 9 OCCURS 97816 TIMES
STREAK LENGTH 10 OCCURS 48685 TIMES
STREAK LENGTH 11 OCCURS 24327 TIMES
STREAK LENGTH 12 OCCURS 12176 TIMES
STREAK LENGTH 13 OCCURS 6149 TIMES
STREAK LENGTH 14 OCCURS 3028 TIMES
STREAK LENGTH 15 OCCURS 1489 TIMES
STREAK LENGTH 16 OCCURS 811 TIMES
STREAK LENGTH 17 OCCURS 383 TIMES
STREAK LENGTH 18 OCCURS 193 TIMES
STREAK LENGTH 19 OCCURS 104 TIMES
STREAK LENGTH 20 OCCURS 43 TIMES
STREAK LENGTH 21 OCCURS 20 TIMES
STREAK LENGTH 22 OCCURS 14 TIMES
STREAK LENGTH 23 OCCURS 4 TIMES
STREAK LENGTH 24 OCCURS 3 TIMES
在进行N次翻转时,计算长度为L的连续投掷次数的期望比较困难,因为存在许多重叠的长度为L的区间,这些区间都可能存在连续投掷次数。然而,需要注意的是,该直方图遵循大致指数分布,每个条目大约是前一个条目的一半。
最长连续投掷次数是24 [注:之前版本中有一个错误,将其计算为23]。在任意独立的24次投掷中出现这种长度的连续投掷的概率为1/2^(24-1),约为800万分之1。由于在1e8次投掷中有约1e8/24 ~ 430万个这样的独立区间,我们预计会出现很少这样的连续投掷,因此这似乎是正确的[但需要注意的是,精确计算期望比较困难]。与此同时,长度为30的连续投掷在任意独立的30次投掷中出现的概率为537百万分之1,甚至比长度为24的连续投掷更不可能发生。
(1 - 0 + 1)
这部分。如果他们的目标是“最奇怪的表示2的方式”,他们也可以写成(232783 - 232782 + 1)
:P - Kenny83