我有一些数学(在C ++中)似乎生成一些非常小的,接近零的数字(我怀疑trig函数调用是我真正的问题),但我想检测这些案例,以便我可以更详细地研究它们。
我目前正在尝试以下内容,这是正确的吗?
if ( std::abs(x) < DBL_MIN ) {
log_debug("detected small num, %Le, %Le", x, y);
}
其次,数学的本质是三角函数(也就是使用了很多弧度/度数转换和sin
/ cos
/ tan
调用等),什么样的我可以做些转换以避免数学错误吗?
显然,对于乘法,我可以使用log transform - 还有什么?
答案 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)并在该单位中完成所有计算操作。然后,如果需要,最后一次转换为另一个值。