【问题标题】:Returning NaN or throwing an exception?返回 NaN 还是抛出异常?
【发布时间】:2011-11-09 17:41:28
【问题描述】:

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

我的第一个想法是在这个 sn-p 中抛出一个异常:

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;
}

但我认为另一种解决方案可能是返回 NaN:

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,我喜欢返回“特殊”双精度以表示意外发生的可能性。

还有其他方法可以处理空向量吗? 谢谢。

【问题讨论】:

  • 2 小技巧:通过引用传递向量 (&) 并使用 Kahan 求和。
  • @ybungalobill +1 第一个提示(我忘了 & 我通常写的)。对于第二个技巧,我有一个问题:您是否见过真正的代码行为不端并使用 Kahan 求和解决问题?
  • 定义“行为不端”。浮点计算不会“行为不端”(通常),它们只是逐渐降低精度。是的,将 100 个数字相加并得到一个远离无限精度的结果是很常见的,因此它可以在输出中看到。
  • 我对与数值分析相关的直接经验(或“战争故事”)很好奇,您正在编写的代码是否发生过这种情况? “足够远”是多少?
  • @uvts_cvs:作为一个新问题提出这个问题(带有浮点标签)。

标签: c++ statistics numeric nan


【解决方案1】:

我会留下未定义的行为。

只需为非空情况编写代码,让调用者考虑正确使用它。可能你无论如何都不会为空向量调用它,因为空输入的检查可能会更早完成。

【讨论】:

【解决方案2】:

我会抛出,只是为了安全起见,并确保立即检测到错误,而不是像你说的那样在一段时间后检测到错误。

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

我们通常做的是在进入方法后立即验证参数,以防我们抛出 ArgumentNullException 或 OutOfRangeException,如果该方法确实设计为仅使用非 null 和正确填充的参数调用。

【讨论】:

  • 我想我不能说“0 是什么都没有的平均值”:-),例如 0 是 {-1,+1} 的平均值
【解决方案3】:

我确实认为在数学上NaN 会更正确。最后是0.0/0。如果是直接划分,会发生什么?

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

【讨论】:

  • 我在这里看不到战争。前两个答案只有得票的人都同意。例外是好的(这完全取决于情况和用法)。
  • @Tux-D 你应该看看 OP 链接的页面。最后,C++ 在其库和语言中并不完全是“异常友好”或“异常统一”。遗憾的是,这是一项附加功能。
【解决方案4】:

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

在这种情况下,假设如果您返回 NaN,那么每次调用函数 average() 时,您都必须确保您进行了额外的检查以处理 NaN 场景。

[注意:除此之外,请确保条件(sz == 0) 不是非常频繁发生的情况。 IMO,如果经常抛出异常,我不会使用它们。]

【讨论】:

  • +1 我同意不使用经常抛出的异常
  • “每次调用函数 average() 时,你必须确保,你正在做一个额外的检查来处理 NaN 场景” - 调用者很可能会确保输入向量是非-empty(可能不需要任何代码——在很多情况下它会被认为是真的),因此不必检查 NaN。
猜你喜欢
  • 2011-04-27
  • 2010-12-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-02
  • 1970-01-01
  • 2012-12-22
相关资源
最近更新 更多