Home > Enterprise >  How to write a portable constexpr std::copysign()?
How to write a portable constexpr std::copysign()?

Time:09-22

In particular, it must work with NaNs as std::copysign does. Similarly, I need a constexpr std::signbit.

constexpr double copysign(double mag, double sgn)
{
    // how?
}

constexpr bool signbit(double arg)
{
    // how?
}

// produce the two types of NaNs
constexpr double nan_pos = copysign(std::numeric_limits<double>::quiet_NaN(),  1);
constexpr double nan_neg = copysign(std::numeric_limits<double>::quiet_NaN(), -1);

// must pass the checks
static_assert(signbit(nan_pos) == false);
static_assert(signbit(nan_neg) == true);

The story behind is that I need two types of NaNs at compile time, as well as ways to distinguish between them. The most straightforward way I can think of is to manipulate the sign bit of the NaNs. It does work at run time; now I just want to move some computations to compile time, and this is the last hurdle.

Notes: at the moment, I'm relying on GCC, as it has built-in versions of these functions and they are indeed constexpr, which is nice. But I want my codebase to compile on Clang and perhaps other compilers too.

CodePudding user response:

If you can use std::bit_cast, you can manipulate floating point types cast to integer types. The portability is limited to the representation of double, but if you can assume the IEEE 754 double-precision binary floating-point format, cast to uint64_t and using sign bit should work.

CodePudding user response:

Use of __builtin... is not really portable, but works in compilers that mentioned as target. __builtin_copysign is contexpr, but __builtin_signbit is apparently not on clang, so doing signbit with __builtin_copysign:

#include <limits>

constexpr double copysign(double mag, double sgn)
{
    return __builtin_copysign(mag, sgn);
}

constexpr bool signbit(double arg)
{
    return __builtin_copysign(1, arg) <  0;
}

// produce the two types of NaNs
constexpr double nan_pos = copysign(std::numeric_limits<double>::quiet_NaN(),  1);
constexpr double nan_neg = copysign(std::numeric_limits<double>::quiet_NaN(), -1);

// must pass the checks
static_assert(signbit(nan_pos) == false);
static_assert(signbit(nan_neg) == true);

int main() {}

https://godbolt.org/z/8Wafaj4a4

  • Related