【问题标题】:Implement Matlab's eps(x) function in C++用 C++ 实现 Matlab 的 eps(x) 函数
【发布时间】:2013-11-23 23:09:12
【问题描述】:

我正在尝试在 C++ 中实现 Matlab 的 eps(x) 函数

例如在 Matlab 中:

>> eps(587.3888)
ans = 1.1369e-13
>> eps(single(587.3888))
ans = 6.1035e-05

但是,当我尝试在 C++ 中执行此操作时,我无法获得正确的单精度答案。

#include <limits>
#include <iostream>
#include <math.h>

#define DEBUG(x) do { std::cerr << x << std::endl; } while (0)
#define DEBUG2(x) do { std::cerr << #x << ": " << x << std::endl; } while (0)

int main() {

    float epsf = std::numeric_limits<float>::epsilon();
    DEBUG2(epsf);
    double epsd = std::numeric_limits<double>::epsilon();
    DEBUG2(epsd);

    float espxf = nextafter(float(587.3888), epsf) - float(587.3888);
    double espxd = nextafter(double(587.3888), epsd) - double(587.3888);
    DEBUG2(espxf);
    DEBUG2(espxd);

}

运行程序我得到以下输出:

$ ./a.out 
epsf: 1.19209e-07
epsd: 2.22045e-16
espxf: -1.13687e-13
espxd: -1.13687e-13

似乎出于某种原因,即使单精度和双精度的 eps 值是正确的,使用 nextafter 函数的输出也只输出双精度值。我对epsxf 的值应该是 6.1035e-05,就像在 Matlab 中一样。

有什么想法吗?

【问题讨论】:

  • MATLAB 的 eps 总是给出积极的结果。如果x 大于epsf,上述代码将给出否定结果。 Here的固定代码:double eps(float x) { float xp = std::abs(x); double x1 = std::nextafter(xp, xp + 1.0f); return x1 - xp; }

标签: c++ matlab epsilon


【解决方案1】:

包含&lt;cmath&gt; 并调用std::nextafter,只要您有C++11 编译器,您的代码就可以工作。

包括&lt;math.h&gt; 和调用::nextafter 调用函数的C 版本。 nextafter 的 C 实现显然不支持重载,因此 C 为单精度结果提供了 nextafterf,为四精度结果提供了 nextafterl。 (简单地用float 调用双精度nextafter 会失败,因为参数被转换为double。)如果你没有C++11 编译器,你可以通过调用::nextafterf 来修复你的代码。

【讨论】:

    【解决方案2】:

    使用库。 Matlab 的eps 函数在其他语言中称为ULP,用于最后的单元。根据ULP 上的维基百科文章,boost C++ library 中的以下函数可用于计算两个双精度数 ab 之间的浮点距离:

    boost::math::float_distance(a, b)
    

    float_distance 的文档是 here

    【讨论】:

    • 是的,谢谢我知道 boost 的实现,但是对于我们的班级,我们无法使用 boost 库。
    • 我真的很想知道这个答案到底是如何评价反对票的。我不仅解释了 ULP 的概念,而且还提出了一种适用于单精度和双精度的强大替代解决方案。 OP 没有表示他不想使用 boost。
    • 您可以通过 +1 来平衡 -1。感谢您提供有关 ULP 的背景信息。当我尝试在 Go 中实现这一点时有助于理解。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-06-27
    • 2015-11-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多