3

Trying to create a constexpr capable class that reinterprets the bits of an IEEE double. Example:

constexpr double pi = 3.14159265358979323846;
constexpr fixedpoint a(pi);

However, running into the problem that reinterpret_cast is not a constant subexpression.

I am using this in the constexpr fixedpoint& operator=(double rhs) :

  uint64_t fraction = *reinterpret_cast<const uint64_t*>(&rhs) & 0x000F'FFFF'FFFF'FFFFull;

but the compiler flags that statement as a non-constant subexpression.

Tried type punning but that ran into the constraint that in C++ only a single field can be active.

Any one have a solution that allows me to reinterpret the bits of that double that is valid constexpr code?

Ravenwater
  • 735
  • 1
  • 5
  • 14
  • Does this answer your question? [constexpr and initialization of a static const void pointer with reinterpret cast, which compiler is right?](https://stackoverflow.com/questions/24398102/constexpr-and-initialization-of-a-static-const-void-pointer-with-reinterpret-cas) – Waqar Jun 06 '20 at 19:27
  • 3
    `reinterpret_cast` is *almost always* a bug. Be *very* sure that it does what you want and that it has well defined behaviour before reaching for it. – Jesper Juhl Jun 06 '20 at 19:31
  • @JesperJuhl what is the 'right' way to extract the bits of a double? – Ravenwater Jun 06 '20 at 19:34
  • @Ravenwater the bitwise representation of a IEEE-754 double is *complicated*. There's no way you can just cast and get something sensible. – Jesper Juhl Jun 06 '20 at 19:37
  • 2
    The `double` layout is [well documented](https://en.wikipedia.org/wiki/Double-precision_floating-point_format#IEEE_754_double-precision_binary_floating-point_format:_binary64): you could write a function to work out the bits. If you find you need some `constexpr` maths support, there are options e.g. [here](https://github.com/kthohr/gcem). (If you just have a couple specific values, you can write throwaway code to do non-`constexpr` conversions, then cut-paste the output into your source.) – Tony Delroy Jun 06 '20 at 20:06
  • 3
    @JesperJuhl It's not really, and the OP clearly does know what they're doing. They're extracting the `xxxxxx` in `pi = (-1)^s * 1.xxxxxx * 2^yyyyyy` (the mantissa, or `fraction`). However, do note that C++ doesn't actually require `double` to be the IEEE floating point `binary64`. That's probably why this wasn't allowed in `constexpr` before C++20, because compile-time computation is generally meant to be "abstract", and bit munging a `double` is the opposite of that. – HTNW Jun 06 '20 at 20:07
  • @Waqar thanks for the pointer, but that answer pertains to pointer types. In the particular problem at hand here, we need to take a double and 'project' the value with proper rounding to a user defined fixed-point type. – Ravenwater Jun 06 '20 at 20:32

1 Answers1

5

Yes, use std::bit_cast, which is in header <bit>:

#include <bit>
#include <cstdint>
constexpr double pi = 3.14159265358979323846;
constexpr auto fraction = std::bit_cast<std::uint64_t>(pi) & 0x000F'FFFF'FFFF'FFFFull;

You'll need a compiler with C++20 support. Currently there aren't any, but from Clang 9 you can at least use the builtin that will be used to implement bit_cast in future:

#if __clang__
constexpr auto fraction = __builtin_bit_cast(std::uint64_t, pi) & 0x000F'FFFF'FFFF'FFFFull;
#endif

Example.

ecatmur
  • 152,476
  • 27
  • 293
  • 366
  • quickly tried it, but clearly I don't have a C++20 compatible compiler yet.... is there a backward compatible way to do this? C++14/17ish? – Ravenwater Jun 06 '20 at 19:36
  • 1
    @Ravenwater no, that's why `bit_cast` was added to the Standard - it requires compiler magic to perform the operations in `constexpr`. – ecatmur Jun 06 '20 at 19:37
  • thank you for the insight, need to figure out how to deal with that constraint (besides not using constexpr fixed-points).... – Ravenwater Jun 06 '20 at 20:26