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

时间:2011-08-08 12:36:26

标签: c++ math numeric numerical-stability

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

我目前正在尝试以下内容,这是正确的吗?

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

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

显然,对于乘法,我可以使用log transform - 还有什么?

4 个答案:

答案 0 :(得分: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是否为非规范化(也称为 subnormal )数字或±0.0。如果不了解您的具体情况,我无法判断该测试是否合适。非规范化数字可以是合理的计算结果,也可以是正确结果为0的舍入结果。当数学上正确的结果为0时,舍入产生的数量远大于DBL_MIN,因此a更大的门槛可能是明智的。

答案 1 :(得分:2)

如果x是双倍的,那么此方法的一个问题是,您无法区分x合法为零,x是小于{{的正值1}}。因此,如果您知道DBL_MIN永远不能合法地为零,并且您希望查看何时发生下溢,这将有效。

您还可以尝试捕获x信号,只要存在包含浮点下溢的数学错误,就会触发POSIX兼容系统。请参阅:http://en.wikipedia.org/wiki/SIGFPE

编辑:要明确,SIGFPE不是双倍可容纳的最大负值,而是最小正值normalized 双重可以持有的价值。所以只要值不能为零,你的方法就可以了。

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

答案 2 :(得分:2)

由于您使用的是C ++,因此最常用的是使用标题std::numeric_limits中的<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类型的最小正非经规范化值(等于FLT/DBL/LDBL_MIN中的<cfloat>),第二个是类型T的最小正值(没有<cfloat>等价物。

[如果您不熟悉浮点数表示,您可能会发现this document非常有用。]

答案 3 :(得分:0)

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

对于你的第二个问题,你意味着很多转换。相反,选择一个单位(deg或rad)并在该单位中完成所有计算操作。然后,如果需要,最后一次转换为另一个值。