如何检查和处理非常接近零的数字

10

我在C++中进行一些数学计算,看起来会生成一些非常接近于零的小数(我怀疑三角函数调用可能是我的真正问题),但我希望能够检测这些情况,以便更详细地研究它们。

我目前正在尝试以下内容,它正确吗?

if ( std::abs(x) < DBL_MIN ) {
     log_debug("detected small num, %Le, %Le", x, y);
}

其次,数学的性质是三角函数(即使用大量弧度/度数转换和 sin/cos/tan 函数等),那么我可以采取什么样的变换来避免数学错误?

显然,对于乘法,我可以使用对数变换 - 还有其他哪些方法吗?


我们能否请看一下这种数学的例子,以便我们可以设计出优雅的东西?我脑海中想到的是像 cos x - 1 这样的东西,当你在零附近得到缓慢变化的结果时,必须仔细选择公差。 - Alexandre C.
1
关于避免下溢的转换,最直接的方法是对表达式进行泰勒展开,并使用小参数的结果。例如,对于小于某个截止值的x,可以使用x*x/2代替1-cos(x) - ev-br
4个回答

5
与普遍认为的相反,DBL_MIN 不是最小的正 double 值,而是最小的正规化 double 值。通常情况下 - 对于 64 位 ieee754 doubles - 它是 2-1022,而最小的正 double 值是 2-1074。因此,

我目前正在尝试以下内容,是否正确?

if ( std::abs(x) < DBL_MIN ) {
     log_debug("detected small num, %Le, %Le", x, y);
}

可能会有一个肯定的答案。该条件检查x是否为非规范化(也称为次标准)数字或±0.0。如果不了解您特定情况的更多信息,我无法确定该测试是否合适。非规范化数字可以是计算结果的合法结果,也可以是四舍五入的结果,正确的结果应该是0。当数学上正确的结果为0时,舍入也可能产生比DBL_MIN大得多的数字,因此更大的阈值可能是明智的。


感谢您对此的输入-问题仍在继续,但我还没有时间回去处理它。我可能会尝试在某个时候发布一个更明智的问题。 - Petriborg

2

由于您正在使用C ++,最惯用的方法是使用标头<limits>中的std :: numeric_limits

例如:

template <typename T>
bool is_close_to_zero(T x)
{
    return std::abs(x) < std::numeric_limits<T>::epsilon();
}

实际容忍度在很大程度上取决于您的问题。请提供具体的用例,以便我可以增强我的答案。
此外,还有std::numeric_limits<T>::min()std::numeric_limits<T>::denorm_min()可能会有用。第一个是类型T的最小正非规范化值(等于<cfloat>中的FLT / DBL / LDBL_MIN),第二个是类型T的最小正数值(没有<cfloat>等效项)。
[如果您对浮点数表示不太熟悉,您可能会发现此文档很有用。]

可能在今天晚些时候,等我找出方程中哪一部分引起了问题后再处理。感谢提供 C++ 的小技巧! - Petriborg
DBL_MIN是最小的正规化double值,因此它对应于min()而不是denorm_min() - Daniel Fischer

2
如果 x 是一个双精度数,那么这种方法的一个问题是你无法区分 x 是否真正为零,或者是否为一个比 DBL_MIN 小的正值。因此,如果你知道 x 绝不会真正为零,并且想要查看下溢时的情况,那么这种方法就可行。
你也可以尝试捕获 SIGFPE 信号,在符合 POSIX 标准的系统上,任何时候都会发生包括浮点数下溢在内的数学错误。参见:http://en.wikipedia.org/wiki/SIGFPE 编辑:需要明确的是,DBL_MIN 不是双精度数可以容纳的最大负值,而是双精度数可以容纳的最小正值。因此,只要该值不为零,你的方法就是可行的。
另一个有用的常量是DBL_EPSILON,它是可以添加到1.0而不会得到1.0的最小双精度值。请注意,这个值比DBL_MIN大得多。但是如果你正在进行可能趋向于1而不是趋向于0的三角函数运算,它可能对你有用。

0

第一个if检查只有在你的值为零时才会为真。

对于你的第二个问题,你暗示了很多转换。相反,选择一个单位(度或弧度),并在该单位上进行所有的计算操作。然后在最后如果需要的话,进行一次单独的转换到另一个值。


DBL_MIN是最小的正规化双精度浮点数,虽然还有更小的正数double - Daniel Fischer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接