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

How do I check and handle numbers very close to zero

本文关键字:接近 数字 非常 处理 检查和      更新时间:2023-10-16

我有一些数学(在c++中)似乎生成一些非常小的,接近零的数字(我怀疑三角函数调用是我真正的问题),但我想检测这些情况,以便我可以更详细地研究它们。

我目前正在尝试以下,它是正确的吗?

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

其次,数学的本质是三角函数(也就是使用大量的弧度/度转换和sin/cos/tan调用等),我可以做什么样的转换来避免数学错误?

显然对于乘法我可以使用对数变换-还有什么?

与普遍认为的相反,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大得多的数字,因此更大的阈值可能是明智的。

如果x是双精度,那么这种方法的一个问题是,您无法区分x是合法的零,而x是小于DBL_MIN的正值。因此,如果您知道x永远不会合法地为零,并且您想要查看何时发生下溢,则此操作将有效。

您还可以尝试捕获SIGFPE信号,该信号将在posix兼容的系统上触发任何数学错误,包括浮点下溢。参见:http://en.wikipedia.org/wiki/SIGFPE

EDIT:需要说明的是,DBL_MIN不是双精度体可以保存的最大的负值,它是双精度体可以保存的最小的正规范化值。所以你的方法是好的,只要值不能为零。

另一个有用的常量是DBL_EPSILON,它是可以添加到1.0而不返回1.0的最小双精度值。注意,这是一个比DBL_MIN大得多的值。但它可能对你们有用因为你们在做趋向于1的三角函数而不是趋向于0的三角函数

由于您使用的是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>的等效物)。

第一个if检查实际上只在您的值为零时为真。

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