在C++中实现Matlab的eps(x)函数

7

我希望你能够帮助将Matlab的eps(x)函数实现到C++中。

例如,在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中一样。有什么想法吗?

1
MATLAB的eps总是给出正结果。如果x大于epsf,上述代码将给出负结果。这里是修复后的代码:double eps(float x) { float xp = std::abs(x); double x1 = std::nextafter(xp, xp + 1.0f); return x1 - xp; } - legends2k
2个回答

8

包含<cmath>并调用std::nextafter,如果您有C++11编译器,则代码将正常工作。

包含<math.h>并调用::nextafter将调用函数的C版本。 nextafter的C实现显然不支持重载,因此C提供了单精度结果的nextafterf以及四倍精度的nextafterl。(仅使用float调用双精度nextafter会失败,因为参数会转换为double。)如果您没有C++11编译器,则可以通过调用::nextafterf来修复您的代码。


3

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

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

这里是float_distance的文档,可以在这里查看。


是的,谢谢。我知道boost实现的方法,但是对于我们的课程,我们不能使用boost库。 - kyle
我真的很想知道这个答案怎么会被踩。我不仅解释了ULP的概念,还提出了一个强大的替代方案,适用于单精度和双精度。OP没有表明他不想使用boost。 - horchler
1
这里有一个+1来抵消-1。感谢您提供关于ULP的背景信息。在我尝试在Go中实现它时非常有帮助。 - Nathaniel Jones

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接