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

发布于 2024-11-28 05:19:29 字数 541 浏览 1 评论 0原文

我有一些数学(在 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

初心 2024-12-05 05:19:29

与普遍看法相反,DBL_MIN 不是最小的正 double 值,而是最小的正标准化 double 值。通常 - 对于 64 位 ieee754 double - 为 2-1022,而最小正 double 值为 2-1074 sup>。所以

我目前正在尝试以下操作,它是否正确?

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

可能会得到肯定的答案。该条件检查x是否是非规范化(也称为次正规)数字或±0.0。在不了解您的具体情况的情况下,我无法判断该测试是否合适。非规范化数字可以是合法的计算结果,也可以是四舍五入的结果,其中正确的结果为 0。当数学上正确的结果为 0 时,四舍五入产生的数字也可能远大于 DBL_MIN ,因此更大的阈值可能是明智的。

Contrary to widespread belief, DBL_MIN is not the smallest positive double value but the smallest positive normalized double value. Typically - for 64-bit ieee754 doubles - it's 2-1022, while the smallest positive double value is 2-1074. Therefore

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);
}

may 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 than DBL_MIN when the mathematically correct result would be 0, so a much larger threshold could be sensible.

冷清清 2024-12-05 05:19:29

如果 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 between x being legitimately zero, and x being a positive value smaller than DBL_MIN. So this will work if you know x 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/SIGFPE

EDIT: 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 than DBL_MIN. But it may be useful to you since you're doing trigonometric functions that may tend toward 1 instead of tending toward 0.

硪扪都還晓 2024-12-05 05:19:29

由于您使用的是 C++,最惯用的做法是使用标头 中的 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::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:

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

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() and std::numeric_limits<T>::denorm_min() that may be useful. The first one is the smallest positive non-denormalized value of type T (equal to FLT/DBL/LDBL_MIN from <cfloat>), the second one is the smallest positive value of type T (no <cfloat> equivalent).

[You may find this document useful to read if you aren't at ease with floating point numbers representation.]

你与清晨阳光 2024-12-05 05:19:29

实际上,只有当您的值为零时,第一个 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文