将NaN或Inf乘以0并得到0

时间:2015-10-06 11:47:43

标签: c++ nan

我有一组值a[i]

然后我计算

for(...){
  b[i] = log(a[i]);
}

然后我总结了

for(...){
  s += c[i] * b[i];
}

到目前为止没问题。

但是对于某些i,我的a[i]可能为零并导致b[i] = log(0) = -Inf。对于这些ic[i]也为零 - 这些是一些无效的数据点。但是zero*-Inf似乎给了NaN,我的总和搞砸了......

c[i] * b[i] = 0时,有没有办法让c[i] = 0?

我看到的唯一方法是将所有零a[i]设置为一个小的非零值或检查零,但可能有更好的解决方案。

我使用C ++和std数学函数,但我正在寻找一种尽可能通用的方法。

4 个答案:

答案 0 :(得分:4)

for (...) {
  s += c[i] * (std::isinf(b[i]) ? 1 : b[i]);
}

for (...) {
  s += (c[i] == 0 ? 0 : c[i] * b[i]);
}

答案 1 :(得分:3)

简而言之:

where
根据定义,

wherefor(...){ double tmp = c[i] * b[i]; s += (tmp == tmp) ? tmp : 0; } (IEEE 754标准) - 所以你无法改变这种行为。

测试数字是否为nan的'教科书'方法是与自身进行比较,例如:

0 * Inf

这取决于NaN不等于任何事物的事实,包括它自己。 (再次按定义)。

C ++ 11引入了is_nan,它更具可读性,如果你没有C ++ 11,我建议你自己编写

if (x != x)
    std::cout << "x is nan" << std::endl;
else
    std::cout << "x is not nan" << std::endl;

事实上,NaN并不能与任何事物进行真实比较,因此以下各项都有效:

bool isnan(double arg) { return arg != arg; }

这种令人惊讶的行为背后的原因(see this question)是能够使用上述条件进行编码以过滤掉NaN,这使代码非常简单,同时也使if (x < y) std::cout << "x is not nan" << std::endl; if (x > y) std::cout << "x is not nan" << std::endl; if (x <= y) std::cout << "x is not nan" << std::endl; if (x >= y) std::cout << "x is not nan" << std::endl; 成为合适的代码NaNNaN值的哨兵。

答案 2 :(得分:2)

分配b[i]时,您可以使用以下构造:

b[i] = (a[i] == 0) ? 0 : log(a[i]);

或者在浮点比较的情况下(阅读评论为什么这个解决方案也适用于当前问题,但可能根本不是好主意):

b[i] = (fabs(a[i]) < DBL_EPSILON) ? 0 : log(a[i]);

答案 3 :(得分:2)

你可以在cmath中使用测试数量为无限;类似的东西:

s += (c[i] == 0 && std::isinf(b[i])) ? 0 : c[i] * b[i];