【问题标题】:Multiply NaN or Inf with 0 and get 0将 NaN 或 Inf 与 0 相乘得到 0
【发布时间】:2016-01-03 07:45:09
【问题描述】:

我有一组值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] = 0 时,有没有办法让c[i] * b[i] = 0?

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

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

【问题讨论】:

  • 浏览数组并将所有NaN替换为0?

标签: c++ nan


【解决方案1】:

简而言之:

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

0 * Inf 根据定义(IEEE 754 标准)是 NaN - 所以你不能改变这种行为。

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

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

这取决于NaN 不等于任何东西,包括它自己。 (同样根据定义)。

C++11 引入了is_nan 更易读,如果你没有 C++11 我建议你自己写个like

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

事实上,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;

这种令人惊讶的行为 (see this question) 背后的原因是能够使用上述条件进行编码以过滤掉 NaN 使得代码非常简单,并且还使 NaN 成为 not setunknown 值。

【讨论】:

    【解决方案2】:
    for (...) {
      s += c[i] * (std::isinf(b[i]) ? 1 : b[i]);
    }
    
    for (...) {
      s += (c[i] == 0 ? 0 : c[i] * b[i]);
    }
    

    【讨论】:

    • 要完整回答这个问题,你需要 isinf,而不是 isnan
    • 你说得对,我解决了这个问题。我还添加了另一个不需要 isinf 的选项 :-)
    • 第二个选项只是绕过问题。不错。
    • 只要 c[i] 是一个整数,我假设(尽管没有明确说明)它就是。
    • c[i] 可以是浮点数 - 没问题 - 只要它不是计算的结果。 (如果是计算结果可能非常接近零但不完全相等,这可能不是所需要的)。由于 OP 声明 c[i] == 0 表示缺少数据,因此似乎零可能是从文件中读取的(例如),或者以其他方式我们可以确定它完全为零。
    【解决方案3】:

    您可以对 cmath 中无限的数字进行测试;类似:

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

    【讨论】:

    • 要完整回答这个问题,你需要 isinf,而不是 isnan
    【解决方案4】:

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

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

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

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

    【讨论】:

    • 您可能误解了 DBL_EPSILON 是什么。无论如何,与 DBL_EPSILON 进行比较是一个非常糟糕的主意。与零的原始比较很好。但是对于最初的问题,比较 c[i] 与 0 比比较 a[i] 更有意义,因为当 a[i]==0 &amp;&amp; c[i]!=0 时结果不正确,您可能需要 NaN 或 INF。
    • 这符合提问者的要求(c[i] * b[i] = 0c[i] is = 0)但可能不是他们想要的:正如指出的那样,如果b[i]nanc[i] 应该为零但不是'不是由于舍入错误,总和仍将是nan。使用DBL_EPSILON 不会解决这个问题,因为浮点计算中的错误可能会根据计算任意大。请注意,如果您知道 c[i] 将为零(因为它被设置为零,而不是由于可能仅接近于零的计算结果)这个答案很好。
    猜你喜欢
    • 2012-10-05
    • 2021-05-11
    • 2017-04-13
    • 2020-03-08
    • 2015-02-03
    • 2021-03-13
    • 2018-12-23
    • 2015-11-27
    • 1970-01-01
    相关资源
    最近更新 更多