设置“epsilon”值以避免零除法错误是否有任何最佳实践或注意事项?[关闭]

Are there any best practices or considerations for setting "epsilon" values ​to avoid zero-division errors? [closed]

提问人:starriet 提问时间:3/24/2023 最后编辑:starriet 更新时间:3/25/2023 访问量:472

问:


想改进这个问题吗?更新问题,以便可以通过编辑这篇文章用事实和引文来回答。

8个月前关闭。

我正在考虑在分母上添加一个接近 0 的值,即所谓的“epsilon”,以防止零除法错误,例如:

double EPS = DBL_MIN;
double no_zerodivision_error = 0.0 / (0.0 + EPS);

设置此 epsilon 值时,是否有任何一般的最佳实践或注意事项来防止将来出现问题?

另外,如果我在 和 之间进行选择,两者之间是否有首选值?DBL_MINDBL_EPSILON

我以为任何小数字都没问题,但我担心将来可能会遇到一个难以发现的无声问题。

编辑1)在我的应用程序中,有许多正常情况,分母可以为零。这就是为什么我不考虑抛出异常。

编辑2)在某些情况下,这样的“epsilon”被添加到分母中,例如一些深度学习计算。例如,

# eps: term added to the denominator to improve numerical stability (default: 1e-8)
torch.optim.Adam(..., eps=1e-08, ...)

还有诸如此类的 SO 问题和答案。

C++ 除以零 epsilon

评论

1赞 j6t 3/24/2023
没有一般的答案。像这样的方法是否可行始终取决于应用程序。
0赞 Alessandro Teruzzi 3/24/2023
我不确定您使用自定义 eplison 实现什么,IEEE 已经处理了返回 +Inf/-Inf 或 NaN stackoverflow.com/questions/4745311/c-division-by-0 的情况。它们不适合您的应用吗?我想你想停止除以零的计算,而不是在没有通知的情况下继续进行。
0赞 nielsen 3/24/2023
我看不出你想完成什么。如果你有一些可能为 0 的除数,难道它也恰好有值吗(所以加法可能仍然会导致除以 0)?如果除数的数值小于某个定义的容差,则抛出异常(或任何有意义的值)似乎更可靠。x-EPSEPS
0赞 Adrian Mole 3/24/2023
唯一会导致“除以零”错误的除数是零。其他小数字可能会导致浮点溢出,但这是一个不同的错误......“限额”将取决于股息的价值。例如,如果它等于(或非常接近),则任何除以数字 < 1 都会导致溢出。DBL_MAX
0赞 Adrian Mole 3/24/2023
在你给出的例子中,如果被除数实际上为零,那么没有有限除数会导致错误,结果将始终为零。

答:

1赞 Red.Wave 3/24/2023 #1
#include <limits>
using double_meta=std::numeric_limits<double>;

现在,您可以简单地检查是否需要执行以下技巧:

constexpr double inline zero(double const zr) noexcept {
    if constexpr(double_meta::is_iec559)
        return zr;
    else if (abs(zr)==0.0) 
        return double_meta::denorm_min();
    else
        return zr;
};

如果平台支持 iec559,则定义浮点除以零以返回正确签名的版本。否则,是可表示的最小正值,除以导致的值远高于大得多的值(作为最小的正值,其与 1 相加导致值大于 1)。double_meta::infinity()double_meta::denorm_min()doubledouble_meta::epsilon()

顺便说一句,使用并不完全相同。除法可能导致无 NaN 数。因此,代码将依赖于平台,如果浮点除以零是代码的有效部分,这是不可避免的。double::denorm_min()0.0

更好的办法是守卫师本身;但我无法给出具体的结果常数,因为任何 std 常量的可用性都依赖于 iec559 合规性(在这种情况下,浮点除以零会自动产生无穷大)。

评论

1赞 Turtlefight 3/24/2023
小错别字:应该是 - is_iec559 是静态数据成员,而不是函数。还有一个小问题,即使 - 除以零在技术上仍然是未定义的行为,并且在常量表达式中不允许未定义的行为。因此,在 constexpr 上下文中不可能除以零,即使它是真的,例如:godboltdouble_meta::is_iec559()double_meta::is_iec559is_iec559 == trueis_iec559
0赞 Red.Wave 3/25/2023
我在 OP 中没有看到 constexpr 要求。但我必须纠正错别字。OP 使用宏作为编译常量。所以我会在评论中保留提示。但是 1+。constexper
1赞 Eric Postpischil 3/24/2023 #2

设置“epsilon”值以避免零除法错误是否有任何最佳实践或注意事项?

不,没有最佳实践。

这通常是一个坏主意,应该避免。在无法避免的情况下,该怎么做取决于应用程序和情况。