我可以写 const expression double 是两个 ulp 小于 -0.5

Can I write const expression double that is two ulps less than -0.5

我有一组基于通过 json 数据包接收到的数字的浮点计算。在计算结束时,我要求其中一个数字 >= -0.5。我发现有时我有一个未通过测试的值,因为它比阈值低 ULP。反正有没有写一个constexpression,意思是

constexpr auto threshold = -0.5 - 2*ULP;

或者我必须求助于

auto threshold = -0.5;
threshold = std::nexttoward(threshold, -2.0);
threshold = std::nexttoward(threshold, -2.0);

您应该能够通过 epsilon 达到所需的阈值,例如

constexpr auto threshold = -0.5 - std::numeric_limits<double>::epsilon();

如果您认为确实需要,可以添加 *2,但由于 epsilon 是为值 1.0 定义的,因此它可能正好适合您 [=16] =].


或者,不要将其用作 constexpr。除非它是一些对性能非常敏感的代码中的一些内部循环,否则差异应该可以忽略不计:

const auto threshold = std::nexttoward(std::nexttoward( -0.5, -2.0), -2.0);

也许像这样的东西可以做到(它需要以 2 为基数的浮点表示,并且不适用于非正规化):

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();

它是如何工作的(我描述它时考虑的是 IEEE754)?

当数字在 [1.0;2.0) 范围内时,Epsilon 表示 1 ULP。我们需要缩放 epsilon,所以它总是意味着 1 ULP。比例基于浮点数的指数部分。如果数字是[1.0;2.0),那么比例必须是1。如果数字是[2.0;4.0),那么比例必须是2,对于[4.0;8.0),它必须是4,等等。所以,我们需要找到最近的、小于或等于 2 的幂:它是 2^floor(log2(number))。我们需要处理负数,这就是公式中 abs(num<0?-1:1) 的原因。