2011-09-03 89 views
3

我有一个函数获取样本(一个std::vector<double>)作为输入并计算样本的平均值:处理空输入向量情况的最佳方法是什么?返回NaN还是抛出异常?

我的第一个想法是在这个片段抛出一个异常,如:

double average(const std::vector<double>& sample) 
{ 
    size_t sz = sample.size(); 
    if (sz==0) throw std::exception("unexpected empty vector"); 

    double acc = 0; 
    for (size_t i=0; i<sz; ++i) acc += sample[i]; 
    return acc/sz; 
} 

但我认为另一个解决办法是回到楠:

double average(const std::vector<double>& sample) 
{ 
    size_t sz = sample.size(); 
    if (sz==0) return std::numeric_limits<double>::quiet_NaN(); 

    double acc = 0; 
    for (size_t i=0; i<sz; ++i) acc += sample[i]; 
    return acc/sz; 
} 

我喜欢的异常,因为它显示了问题发生的时候,如果我在一个长计算的最终结果中得到一个NaN,我将更难以理解NaN的出生地点。无论如何,NaN我喜欢返回一个“特殊”双倍的可能性,以表示意外事件发生。

是否有任何其他方式来应付空载体? 谢谢。

+4

2提示:通过引用(&)传递向量并使用Kahan求和。 – ybungalobill

+0

@ybungalobill +1第一个提示(我忘了&我通常写)。对于第二个提示,我有一个问题:你有没有看到真正的代码行为不正常,并用Kahan求和来解决问题? –

+0

定义“行为不端”。浮点计算不会“不正常”(通常),它们只是逐渐放宽精度。是的,将100个数字相加是很常见的,并且可以从无限精度的结果中获得足够的结果,以便在输出中看到它。 – ybungalobill

回答

3

我觉得数学NaN会更正确。最后它是0.0/0。如果是直接分裂,会发生什么?

请注意,关于C++和例外是圣战。例如阅读:To throw or not to throw exceptions?

+0

我在这里看不到战争。前两个答案是唯一一个同意票的人。例外情况良好(这一切取决于情况和使用情况)。 –

+0

@ Tux-D你应该看看由OP链接的页面。最后,C++在库和语言中并不完全是“例外友好”或“异常统一”。可悲的是它是一个附加功能。 – xanatos

1

您对使用异常的理解是正确的,您应该继续使用该方法。例外是为了这个目的(throw当异常情况发生时)。

在这种情况下,假设您返回NaN,那么每次调用函数average()时都必须确保您正在进行额外的检查,其中包含NaN方案。

[注意:最重要的是,确保条件(sz == 0)不是一个非常频繁发生的情况。国际海事组织,我不会使用例外,如果他们经常抛出。]

+2

+1我同意不经常使用异常 –

+1

“每次调用函数average()时,都必须确保您正在进行额外的支持NaN场景的检查” - 最有可能的是调用者会确保输入向量不是空的(这可能不需要任何代码 - 在很多情况下它将被认为是真实的),因此不必检查NaN。 –

1

我会抛出,只是为了保持安全的一面,并确保错误被​​立即检测到,而不是,如你所说,一段时间后。

实际上,在这个特定的用例中,如果说0是“无”的平均值,那么可以返回0。

我们通常在我们进入方法的时候验证参数,如果我们抛出ArgumentNullException或OutOfRangeException,如果真的该方法被设计为只能用非null和正确填充的参数来调用。

+0

我认为我不能说“0是没有什么的平均数”:-),例如0是{-1,+ 1}的平均值 –

2

我会离开行为未定义。

只是为非空的情况编码并让调用者考虑正确使用它。无论如何,你可能不会将它称为空载体,因为检查空输入可能会提前完成。

+0

undefined?你的函数返回什么值? –

+2

@uvts:参见[undefined behavior](http://stackoverflow.com/questions/2397984/undefined-unspecified-and-implementation-defined-behavior) – ybungalobill