How to determine the minimum noticeable change in double

I have a problem determining the smallest eps value for a given double variable v for which

 v+eps != v 

Note that this is not a typical task, since eps depends on an arbitrary number v .

This should not be done by looking for this value in a for loop. Is there a quick way to do this, for example by bit shift? Regardless of the compiler, optimization flags, platform ...

thank you for your responses

+7
floating point
source share
3 answers

The C99 nextafter function is what you need. Alternatively use Boost.Math nextafter . This is the implementation defined by the definition (it relies on the internal representation of double in memory).

For a comparison of all the methods presented in the answers here, at the time of writing, see a live demo to see how other solutions do not work.


For reference, here is the test code if you want to run it on our own system:

 #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); } 
+3
source share

I would use the punning type:

 double epsFor( double x ) { union { double d; unsigned long long i; } tmp; tmp.d = x; ++ tmp.i; double results = tmp.d - x; return results; } 

(Formally, this behavior is undefined, but in practice I don’t know about the modern compiler, where it will fail.)

EDIT:

Note that C ++ allows excessive precision in an intermediate expression; since we are dealing with exact results here, the originally published function may produce incorrect results if you used it directly in the expression, rather than assigning it a double . I added an assignment to the function to avoid this, but keep in mind that many compilers are not standard in this regard, at least by default. (g ++ is a good example of where you need a special version of compatible behavior, at least when optimization is turned on. If you use g ++, you must specify -ffloat-store if you want to get the correct results.)

+1
source share
 eps = std::numeric_limits<double>::epsilon() * v; 
0
source share

All Articles