我有问题确定给定双变量eps
的最小值v
,以便
v+eps != v
请注意,这不是典型的问题表任务,因为eps
取决于任意
号码v
。
这不应该通过在for循环中寻找此值来完成。有没有快速的方法来做到这一点, 例如通过位移?独立于编译器,优化标志,平台......
感谢您的回答
答案 0 :(得分:3)
C99功能nextafter
正是您所需要的。或者,使用Boost.Math的nextafter
。这是定义定义的实现(它依赖于内存中double
的内部表示)。
在撰写本文时,为了比较答案中提供的所有方法,请参阅a live demo以了解其他解决方案是如何失败的。
作为参考,如果你想在我们自己的系统上运行它,这是测试代码:
#include <cmath>
#include <cfloat>
#include <limits>
#include <iostream>
using std::cout;
#include <iomanip>
using std::setprecision;
#include <boost/math/special_functions/next.hpp>
double
epsFor( double x )
{
union
{
double d;
unsigned long long i;
} tmp;
tmp.d = x;
++ tmp.i;
return tmp.d - x;
}
void test(double d)
{
double d1 = std::nextafter(d,DBL_MAX);
double d2 = d+std::numeric_limits<double>::epsilon() * d;
double d3 = d+epsFor(d);
double d4 = boost::math::nextafter(d, DBL_MAX);
cout << setprecision(40)
<< "For value of d = " << d << '\n'
<< " std::nextafter: " << d1 << '\n'
<< " Boost solution: " << d4 << '\n'
<< " undefined beh.: " << d3 << '\n'
<< " numeric_limits: " << d2 << '\n';
}
int main()
{
test(0.1);
test(986546357654.354687);
}
答案 1 :(得分:1)
我会使用类型惩罚:
double
epsFor( double x )
{
union
{
double d;
unsigned long long i;
} tmp;
tmp.d = x;
++ tmp.i;
double results = tmp.d - x;
return results;
}
(形式上,这是未定义的行为,但在实践中,我没有 知道现代编译器会失败。)
编辑:
请注意,C ++允许中间程度过高
表达式;因为我们关注的是确切的结果,所以
如果使用,最初发布的功能可能会给出错误的结果
它直接在表达式中,而不是分配给它
一个double
。我在函数中添加了一个要避免的赋值
这一点,但请注意,许多编译器不标准
在这方面,至少在默认情况下是符合的。 (g ++很好
您需要特殊选项的示例
符合行为,至少在打开优化时。
如果您使用的是g ++,则必须指定
如果您想要正确的结果,请-ffloat-store
选项。)
答案 2 :(得分:0)
eps = std::numeric_limits<double>::epsilon() * v;