我正在使用OMNeT 5.1.1模拟器 . 我一直在看bernoulli()函数的一些奇怪的行为,所以我 Build 了一个MWE来看看发生了什么 .
MWE通过创建具有单个节点的网络并在t = 0处设置一个计时器(自身消息)来工作 . 当计时器熄灭时,模拟运行一些n次伯努利试验,成功概率为p . 值n和p是通过我使用Register_PerRunConfigOption()宏定义的每个运行配置选项指定的 .
这是我的代码:
#include <math.h>
#include <omnetpp.h>
using namespace omnetpp;
Register_PerRunConfigOption(CFGID_NUM_TRIALS, "num-trials", CFG_INT,
"0", "The number of Bernoulli trials to run");
Register_PerRunConfigOption(CFGID_BERNOULLI_MEAN, "bernoulli-mean",
CFG_DOUBLE, "0.0", "The mean of the Bernoulli experiments");
class Test : public cSimpleModule {
private:
int nTrials, nSuccess;
double p;
cMessage *timer;
protected:
virtual void initialize() override;
virtual void handleMessage(cMessage *msg) override;
};
Define_Module(Test);
void Test::initialize()
{
nTrials = getEnvir()->getConfig()->getAsInt(CFGID_NUM_TRIALS);
p = getEnvir()->getConfig()->getAsDouble(CFGID_BERNOULLI_MEAN);
timer = new cMessage("timer");
scheduleAt(0.0, timer);
}
void Test::handleMessage(cMessage *msg)
{
int trial;
printf("\n\n");
for (int n = 0; n < nTrials; n++) {
trial = bernoulli(p);
if (trial)
nSuccess++;
}
double mean = nTrials * p;
double variance = mean * (1.0 - p);
double stddev = std::sqrt(variance);
printf("nTrials: %12d(%.3e)\n", nTrials, (double) nTrials);
printf("nSuccess: %12d(%.3e)\n", nSuccess, (double) nSuccess);
printf("Pct.: %12.5f\n", 100.0 * (double) nSuccess / nTrials);
printf("nStdDevs: %12.2f\n", (nSuccess - mean) / stddev);
printf("\n\n");
delete msg;
}
这段代码就像我想象的那样简单(我是OMNeT的新手) . 这是.ned文件:
simple Test
{
gates:
}
network Bernoulli
{
submodules:
node: Test;
}
这是omnetpp.ini文件:
[General]
network = Bernoulli
bernoulli-mean = 0.05
num-trials = 10000000
rng-class = "cMersenneTwister"
seed-0-mt = ${seed=0,1,2,3,4,5,6,7,8,9}
我正在使用以下命令运行代码: ./exe_file -u Cmdenv -r 3
(我故意挑选第三次运行) . 当我使用上面的omnetpp.ini文件执行此操作时,我获得了大约532,006次成功(尽管这个数字在每次运行时都会轻微改变?) . 对于10 ^ 7次运行,这与平均值相比约为46个标准偏差(使用二项式分布的均值和方差计算) .
此外,如果我注释掉第 rng-class="cMersenneTwister"
行,那么这个数字会跳跃到大约531,793个成功,每次都会略微改变(但不是根本上) .
此外,如果我注释掉 seed-0-mt=...
线,那么突然模拟开始产生0.06标准的值 . 开发 . 的意思!尽管OMNeT手册确保使用cMersenneTwister算法意味着您可以随机选择种子,因为这段时间非常大 .
为什么会这样?我希望(1)因为cMersenneTwister是默认值,包括omnetpp.ini文件中的它不应该改变任何东西,以及(2)因为我每次都选择相同的种子(即种子3),我应该得到相同的结果 . 但我不是!这让我感到困惑,因为OMNeT手册指出:
对于cMersenneTwister随机数生成器,由于RNG的序列非常长,因此选择种子以使生成的序列不重叠很容易 . RNG从32位种子值seed = runNumber * numRngs rngNumber初始化 .
谢谢!
1 回答
在使用它之前应该将
nSuccess
初始化为零,因为在C++
中,默认情况下不会初始化基类型(int,float等)的类成员 .此外,我强烈建议您在
OMNeT++
中使用参数机制 - 它是控制模拟的标准方法 . 要使用它你应该:NED
文件中添加参数定义,例如:omnetpp.ini
中设置值:笔记:
禁止在参数名称中使用"-" .
在
omnetpp.ini
中,简单模块的每个实例都有自己的参数值 . 但是,要为所有模块分配相同的值,可以使用wildcard patterns,例如**