我怀疑性能问题出在您的carbon()
、hydrogen()
、nitrogen()
、oxygen()
和sulfur()
函数的主体中。您应该展示他们如何产生随机数据。
或者它可能在if (sum < threshold) {} else {}
代码中。
我想继续设置种子,这样结果就不会是确定性的(更接近真正的随机)
由于您使用的是time(0)
作为种子的结果,因此无论哪种方式都不会得到特别随机的结果。
而不是使用srand()
,rand()
您应该查看<random>
库并选择具有满足您需求的性能/质量特征的引擎。如果您的实现支持它,您甚至可以从中获取不确定的随机数据std::random_device
(生成种子或作为引擎)。
此外<random>
还提供了预制的分布,例如,std::uniform_real_distribution<double>
这可能比普通程序员从rand()
.
好的,这就是如何从代码中消除内部循环并大大加快它的速度(在 Java 或 C++ 中)。
你的代码:
double carbon() {
if (rand() % 10000 < 107)
return 13.0033548378;
else
return 12.0;
}
选择具有特定概率的两个值之一。大概您打算在 10000 次中选择第一个值约 107 次(尽管使用%
withrand()
并不能完全满足您的要求)。当您在循环中运行它并将结果求和时,如下所示:
for (int i = 0; i < composition[0]; i++) sum += carbon();
你基本上会得到sum += X*13.0033548378 + Y*12.0;
X 是随机数保持在阈值以下的次数,而 Y 是(试验-X)。碰巧您可以模拟运行一堆试验并使用二项分布计算成功次数,并且<random>
恰好提供了二项分布。
给定一个函数sum_trials()
std::minstd_rand0 eng; // global random engine
double sum_trials(int trials, double probability, double A, double B) {
std::binomial_distribution<> dist(trials, probability);
int successes = dist(eng);
return successes*A + (trials-successes)*B;
}
您可以替换carbon()
循环:
sum += sum_trials(composition[0], 107.0/10000.0, 13.003354378, 12.0); // carbon trials
我没有您使用的实际值,但您的整个循环看起来像:
for (int i = 0; i < 100000000; i++) {
double sum = 0;
sum += sum_trials(composition[0], 107.0/10000.0, 13.003354378, 12.0); // carbon trials
sum += sum_trials(composition[1], 107.0/10000.0, 13.003354378, 12.0); // hydrogen trials
sum += sum_trials(composition[2], 107.0/10000.0, 13.003354378, 12.0); // nitrogen trials
sum += sum_trials(composition[3], 107.0/10000.0, 13.003354378, 12.0); // oxygen trials
sum += sum_trials(composition[4], 107.0/10000.0, 13.003354378, 12.0); // sulfur trials
if (sum > threshold) {
} else {
}
}
现在要注意的一件事是,在函数内部,我们使用相同的数据一遍又一遍地构建分布。我们可以通过用函数对象替换函数来提取它sum_trials()
,我们在循环之前用适当的数据构造一次,然后重复使用函子:
struct sum_trials {
std::binomial_distribution<> dist;
double A; double B; int trials;
sum_trials(int t, double p, double a, double b) : dist{t, p}, A{a}, B{b}, trials{t} {}
double operator() () {
int successes = dist(eng);
return successes * A + (trials - successes) * B;
}
};
int main() {
int threshold = 5;
int composition[5] = { 10, 10, 10, 10, 10 };
sum_trials carbon = { composition[0], 107.0/10000.0, 13.003354378, 12.0};
sum_trials hydrogen = { composition[1], 107.0/10000.0, 13.003354378, 12.0};
sum_trials nitrogen = { composition[2], 107.0/10000.0, 13.003354378, 12.0};
sum_trials oxygen = { composition[3], 107.0/10000.0, 13.003354378, 12.0};
sum_trials sulfur = { composition[4], 107.0/10000.0, 13.003354378, 12.0};
for (int i = 0; i < 100000000; i++) {
double sum = 0;
sum += carbon();
sum += hydrogen();
sum += nitrogen();
sum += oxygen();
sum += sulfur();
if (sum > threshold) {
} else {
}
}
}
代码的原始版本花了我的系统大约一分 30 秒。这里的最后一个版本需要 11 秒。
这是一个使用两个 binomial_distributions 生成氧和的函子。也许其他发行版之一可以一次性做到这一点,但我不知道。
struct sum_trials2 {
std::binomial_distribution<> d1;
std::binomial_distribution<> d2;
double A; double B; double C;
int trials;
double probabilty2;
sum_trials2(int t, double p1, double p2, double a, double b, double c)
: d1{t, p1}, A{a}, B{b}, C{c}, trials{t}, probability2{p2} {}
double operator() () {
int X = d1(eng);
d2.param(std::binomial_distribution<>{trials-X, p2}.param());
int Y = d2(eng);
return X*A + Y*B + (trials-X-Y)*C;
}
};
sum_trials2 oxygen{composition[3], 17.0/1000.0, (47.0-17.0)/(1000.0-17.0), 17.9999, 16.999, 15.999};
如果您可以计算总和低于您的概率,则可以进一步加快速度threshold
:
int main() {
std::minstd_rand0 eng;
std::bernoulli_distribution dist(probability_sum_is_over_threshold);
for (int i=0; i< 100000000; ++i) {
if (dist(eng)) {
} else {
}
}
}
除非其他元素的值可以为负,否则总和大于 5 的概率为 100%。在这种情况下,您甚至不需要生成随机数据;执行代码的“if”分支 100,000,000 次。
int main() {
for (int i=0; i< 100000000; ++i) {
//execute some code
}
}