Maybe something like this can do this (it requires a base 2 floating point view, and it does not work for denormals):
constexpr double num = -0.5; constexpr double threshold = num + 2.0 * (num < 0 ? -1 : 1) * std::pow(2.0, std::floor(std::log(std::abs(num)) / std::log(2.0))) * std::numeric_limits<double>::epsilon();
How does it work (I describe it considering IEEE754)?
Epsilon means 1 ULP when the number is in the range of [1.0; 2.0]. We need to scale epsilon, so it always means 1 ULP. The scale is based on the exponential part of the floating point number. If the number is [1.0; 2.0), then the scale should be 1. If the number is [2.0; 4.0], then the scale should be equal to 2, for [4.0; 8.0) it should be 4, etc. So, we need to find the nearest, lesser or equal power of 2: this is 2^floor(log2(number)) . And we need to take care of negative numbers, why abs and (num<0?-1:1) in the formula.
source share