将 NaN 或 Inf 与 0 相乘并得到 0
Multiply NaN or Inf with 0 and get 0
我有一组值a[i]
。
然后我计算
for(...){
b[i] = log(a[i]);
}
那我总结一下
for(...){
s += c[i] * b[i];
}
目前没问题。
但对于某些 i
,我的 a[i]
可能为零并导致 b[i] = log(0) = -Inf
。对于这些 i
,c[i]
也是零——这些是一些无效的数据点。但是zero*-Inf
好像给了NaN
,我的求和就乱了...
有没有办法在 c[i]
= 0 时始终让 c[i] * b[i]
= 0?
我看到的唯一方法是将全零 a[i]
设置为一个小的非零值或检查零,但可能有更好的解决方案。
我使用 C++ 和 std
数学函数,但我正在寻找一种尽可能通用的方法。
分配 b[i]
时,可以使用以下结构:
b[i] = (a[i] == 0) ? 0 : log(a[i]);
或者在浮点比较的情况下(阅读为什么这个解决方案也适用于当前问题的评论,但可能根本不是一个好主意):
b[i] = (fabs(a[i]) < DBL_EPSILON) ? 0 : log(a[i]);
for (...) {
s += c[i] * (std::isinf(b[i]) ? 1 : b[i]);
}
for (...) {
s += (c[i] == 0 ? 0 : c[i] * b[i]);
}
你可以在cmath中使用这个数字无穷大的测试;类似于:
s += (c[i] == 0 && std::isinf(b[i])) ? 0 : c[i] * b[i];
简而言之:
for(...){
double tmp = c[i] * b[i];
s += (tmp == tmp) ? tmp : 0;
}
0 * Inf
根据定义(IEEE 754 标准)是 NaN
- 因此您无法更改该行为。
测试一个数是否为nan的'textbook'方法是与自身比较,例如:
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,我建议您自己编写
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 set
或 unknown
值的合适标记。
我有一组值a[i]
。
然后我计算
for(...){
b[i] = log(a[i]);
}
那我总结一下
for(...){
s += c[i] * b[i];
}
目前没问题。
但对于某些 i
,我的 a[i]
可能为零并导致 b[i] = log(0) = -Inf
。对于这些 i
,c[i]
也是零——这些是一些无效的数据点。但是zero*-Inf
好像给了NaN
,我的求和就乱了...
有没有办法在 c[i]
= 0 时始终让 c[i] * b[i]
= 0?
我看到的唯一方法是将全零 a[i]
设置为一个小的非零值或检查零,但可能有更好的解决方案。
我使用 C++ 和 std
数学函数,但我正在寻找一种尽可能通用的方法。
分配 b[i]
时,可以使用以下结构:
b[i] = (a[i] == 0) ? 0 : log(a[i]);
或者在浮点比较的情况下(阅读为什么这个解决方案也适用于当前问题的评论,但可能根本不是一个好主意):
b[i] = (fabs(a[i]) < DBL_EPSILON) ? 0 : log(a[i]);
for (...) {
s += c[i] * (std::isinf(b[i]) ? 1 : b[i]);
}
for (...) {
s += (c[i] == 0 ? 0 : c[i] * b[i]);
}
你可以在cmath中使用这个数字无穷大的测试;类似于:
s += (c[i] == 0 && std::isinf(b[i])) ? 0 : c[i] * b[i];
简而言之:
for(...){
double tmp = c[i] * b[i];
s += (tmp == tmp) ? tmp : 0;
}
0 * Inf
根据定义(IEEE 754 标准)是 NaN
- 因此您无法更改该行为。
测试一个数是否为nan的'textbook'方法是与自身比较,例如:
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,我建议您自己编写
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 set
或 unknown
值的合适标记。