如何检查和处理非常接近于零的数字
我有一些数学(在 C++ 中),似乎生成一些非常小的、接近零的数字(我怀疑三角函数调用是我真正的问题),但我想检测这些情况以便我可以更详细地研究它们。
我目前正在尝试以下内容,它是否正确?
if ( std::abs(x) < DBL_MIN ) {
log_debug("detected small num, %Le, %Le", x, y);
}
其次,数学的本质是三角函数(又名使用大量弧度/度数转换和 sin
/cos
/tan
调用,等),我可以做什么样的转换来避免数学错误?
显然,对于乘法,我可以使用 对数变换 - 还有什么?
I have some math (in C++) which seems to be generating some very small, near zero, numbers (I suspect the trig function calls are my real problem), but I'd like to detect these cases so that I can study them in more detail.
I'm currently trying out the following, is it correct?
if ( std::abs(x) < DBL_MIN ) {
log_debug("detected small num, %Le, %Le", x, y);
}
Second, the nature of the mathematics is trigonometric in nature (aka using a lot of radian/degree conversions and sin
/cos
/tan
calls, etc), what sort of transformations can I do to avoid mathematical errors?
Obviously for multiplications I can use a log transform - what else?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
与普遍看法相反,
DBL_MIN
不是最小的正double
值,而是最小的正标准化double
值。通常 - 对于 64 位 ieee754double
- 为 2-1022,而最小正double
值为 2-1074 sup>。所以可能会得到肯定的答案。该条件检查
x
是否是非规范化(也称为次正规)数字或±0.0。在不了解您的具体情况的情况下,我无法判断该测试是否合适。非规范化数字可以是合法的计算结果,也可以是四舍五入的结果,其中正确的结果为 0。当数学上正确的结果为 0 时,四舍五入产生的数字也可能远大于DBL_MIN
,因此更大的阈值可能是明智的。Contrary to widespread belief,
DBL_MIN
is not the smallest positivedouble
value but the smallest positive normalizeddouble
value. Typically - for 64-bit ieee754doubles
- it's 2-1022, while the smallest positivedouble
value is 2-1074. Thereforemay have an affirmative answer. The condition checks whether
x
is a denormalized (also called subnormal) number or ±0.0. Without knowing more about your specific situation, I cannot tell if that test is appropriate. Denormalized numbers can be legitimate results of calculations or the consequence of rounding where the correct result would be 0. It is also possible that rounding produces numbers of far greater magnitude thanDBL_MIN
when the mathematically correct result would be 0, so a much larger threshold could be sensible.如果
x
是双精度数,那么这种方法的一个问题是您无法区分x
是合法的零,还是x
是一个小于DBL_MIN
的正值。因此,如果您知道 x 永远不可能合法地为零,并且您想查看何时发生下溢,那么这将起作用。您还可以尝试捕获
SIGFPE
信号,只要出现包括浮点下溢在内的数学错误,该信号就会在符合 POSIX 标准的系统上触发。请参阅:http://en.wikipedia.org/wiki/SIGFPE编辑:需要明确的是,
DBL_MIN
不是 double 可以容纳的最大负值,它是最小的正值 双精度值可以保存的标准化值。因此,只要该值不能为零,您的方法就可以。另一个有用的常量是 DBL_EPSILON,它是可以与 1.0 相加而不会返回 1.0 的最小双精度值。请注意,该值比
DBL_MIN
大得多。但它可能对你有用,因为你正在做的三角函数可能趋向于 1 而不是趋向于 0。If
x
is a double, then one problem with this approach is that you can't distinguish betweenx
being legitimately zero, andx
being a positive value smaller thanDBL_MIN
. So this will work if you knowx
can never be legitimately zero, and you want to see when underflow occurs.You could also try catching the
SIGFPE
signal, which will fire on a POSIX-compliant system any time there's a math error including floating-point underflow. See: http://en.wikipedia.org/wiki/SIGFPEEDIT: To be clear,
DBL_MIN
is NOT the largest negative value that a double can hold, it is the smallest positive normalized value that a double can hold. So your approach is fine as long as the value can't be zero.Another useful constant is
DBL_EPSILON
which is the smallest double value that can be added to 1.0 without getting 1.0 back. Note that this is a much larger value thanDBL_MIN
. But it may be useful to you since you're doing trigonometric functions that may tend toward 1 instead of tending toward 0.由于您使用的是 C++,最惯用的做法是使用标头
中的std::numeric_limits
。例如:
实际使用的容差在很大程度上取决于您的问题。请用具体的用例来完成您的问题,以便我可以增强我的答案。
还有
std::numeric_limits::min()
和std::numeric_limits::denorm_min()
可能有用。第一个是T
类型的最小正非标准化值(等于
中的FLT/DBL/LDBL_MIN
),第二个是T
类型的最小正值(没有
等价物)。[您可能会找到此文档如果您不熟悉浮点数表示,那么阅读起来很有用。]
Since you are using C++, the most idiomatic is to use
std::numeric_limits
from header<limits>
.For instance:
The actual tolerance to be used heavily depends on your problem. Please complete your question with a concrete use case so that I can enhance my answer.
There is also
std::numeric_limits<T>::min()
andstd::numeric_limits<T>::denorm_min()
that may be useful. The first one is the smallest positive non-denormalized value of typeT
(equal toFLT/DBL/LDBL_MIN
from<cfloat>
), the second one is the smallest positive value of typeT
(no<cfloat>
equivalent).[You may find this document useful to read if you aren't at ease with floating point numbers representation.]
实际上,只有当您的值为零时,第一个
if
检查才会为 true。对于你的第二个问题,你暗示了很多转化。相反,选择一个单位(度或弧度)并以该单位进行所有计算操作。然后,如果需要,最后进行一次到其他值的转换。
The first
if
check will actually only be true when your value is zero.For your second question, you imply lots of conversions. Instead, pick one unit (deg or rad) and do all your computational operations in that unit. Then at the very end do a single conversion to the other value if you need to.