我实施了一个"增量平均值" (我只是伪装成.cpp文件)
#include "../hpp/CIncrementalMean.hpp"
IncrementalMean::IncrementalMean() : m_mean(0.0), m_cntr(0) {}
IncrementalMean::~IncrementalMean() {}
void IncrementalMean::addValueToMean(double valIn)
{
m_mean = (m_cntr * m_mean + valIn) / ++m_cntr;
}
int IncrementalMean::getCounter() const
{
return m_cntr;
}
double IncrementalMean::getMean() const
{
return m_mean;
}
当我构建它(gcc4.9 Ubuntu14.04)时,我收到以下警告:
warning: operation on ‘((IncrementalMean*)this)->IncrementalMean::m_cntr’ may be undefined [-Wsequence-point]
我不确定为什么显示它。有人可以给我一个建议吗?我要做什么
m_mean = (m_cntr * m_mean + valIn) / (m_cntr + 1);
m_cntr++;
代替?
但无论如何,有人可以向我解释警告吗?
答案 0 :(得分:4)
m_mean = (m_cntr * m_mean + valIn) / ++m_cntr;
^^^^^^^^^ ^^^^^^^^^^
READING WRITING
您正在读取和编写操作之间没有sequence point的变量。这可以由编译器重新排列,因此它是Undefined Behaviour:D
修改强>: 补充一点,如果你使用:
,你将有更少的浮点误差累积m_mean += (valIn - m_mean) / ++m_cntr;
(请参阅here) AND 您将避免未定义的行为。
答案 1 :(得分:3)
让我们简化您的代码以确定问题:
a = 0;
b = a / ++a;
在第2行完全执行了什么划分?你可能认为它一定是:
b = 0 / 1;
事实上,编译器可以先评估++a
,然后a
秒,给你:
b = 1 / 1;
那么代码是做什么的?技术术语是"未定义的行为",但您需要记住的是不要增加变量并在同一个表达式中再次使用#34;。
关于您的设计,拥有两个数据成员counter
和sum
可能更有意义,并将该部门推迟到名为calculateMean
的成员函数。然后,每次调用addValue
时,你都不必繁殖和分裂(我闻到精确问题!)。
答案 2 :(得分:2)
自4.6.3以来GNU编译器集合(GCC)在操作的顺序顺序不明确时发出警告。
由于您在分母中修改m_cntr并在分子计算中使用此值,因此不明确将要做什么(即,此分数的哪一部分将在先前计算)。因此,最好避免这种结构。