0

Is there a way to get the bits of a double as an int64_t in a constexpr function in C++?

I first tried the usual *reinterpret_cast<int64_t*>(&d), but that's not allowed in constexpr code, which makes some sense. Then, I tried the usual fallback, (which usually results in slower code, unfortunately for the cases where it's run at runtime, instead of compile time), of creating a struct with a union of double and int64_t, with a constexpr constructor that takes a double to initialize the double member. The constructor is accepted, and I've had other cases where constexpr code is okay with unions in structs, but if any code tries to read the int64_t member of the union, Visual Studio 2017 complains:

error C2131: expression did not evaluate to a constant
note: failure was caused by accessing a non-active member of a union
note: see usage of 'big_float::DoubleInt::i'

GCC complains:

error: accessing 'DoubleInt::<unnamed union>::i' member instead of initialized 'DoubleInt::<unnamed union>::d' member in constant expression

It's rather unfortunate to not be able to do this, particularly since I'm implementing a high-precision floating-point class, requiring access to the bits, and I'd like almost all of the functions to be able to run at compile-time if applicable. Does anyone have any workarounds that won't result in extremely slow runtime performance for the runtime case?

(P.S. Please don't ignore the question and only reply with something snarky like "the standard doesn't guarantee that double is 64 bits or that int64_t is 64 bits", because I really don't care about things that never happen. There seems to be an awful lot of that sort of snark on StackOverflow. Every compiler I care about on every platform I care about will always have that guarantee, else I'll stop using them. I would appreciate actual help for actual code, please. Thanks.)

Neil Dickson
  • 305
  • 1
  • 8
  • 1
    It's difficult to tone down the snark sometimes. It's impossible to do what you ask in a reasonable way in constexpr, since interpeting a double as an integer obviously violates a bunch of constexpr rules. Perhaps you should rethink your initial design - why you need to do this and what are some alternative approaches. – DeiDei May 14 '18 at 01:04
  • Take a look at https://stackoverflow.com/questions/9328235/how-to-check-a-doubles-bit-pattern-is-0x0-in-a-c11-constexpr – DeiDei May 14 '18 at 01:08
  • 1
    FWIW, The standard **does** guarantee that `int64_t` is 64 bits. I don't know if you consider that helpful or snarky. I'd consider that helpful, but it comes very close to your definition of snarky. – Drew Dormann May 14 '18 at 01:27
  • Considering that all ways to reinterpret the bits inevitably require an address, I would say that there's no way to do this in a constexpr. Incidentally, the only portable way to reinterpret bits like that is with memcpy - unions and reinterpret_cast violate strict-alias rules. – Lubo Antonov May 14 '18 at 01:32
  • 1
    Perhaps we need to rethink the design of C++ to stop pretending tons of false things like that doubles aren't actually composed of bits. If I'm implementing a high-precision floating point class, and I want to be able to convert from a double to the class type, either I need to jump through a ton of complicated hoops to prove bounds on how to implement it all using doubles, (which would be much more likely to hit platform/compiler differences), or I need access to the bits to implement it using integers. There's not really any way around that unless I just remove support for that conversion. – Neil Dickson May 14 '18 at 02:05
  • 2
    The classic fallback for generating compile-time constants that are not supported by the language is to execute programs at compile time that compute the necessary values and write them to source code, which is then compiled. It seems that may be required here. – Eric Postpischil May 14 '18 at 02:26
  • @EricPostpischil That makes sense. I'm hoping to avoid that, since constexpr should ideally provide a way to procompute things within the language, so that external setups aren't needed, and so that templates can be cleanly supported. I've thought of a possible workaround that's messy but viable, without sacrificing runtime performance, at the expense of the user of the class having to call separate functions for constexpr execution, and they'll have to provide the sign bit separately for 0 or NaN. I'll post an answer, possibly after some sleep. – Neil Dickson May 14 '18 at 03:41
  • 2
    I apologize for not knowing as much as I should about C++ `constexpr` programming to answer this question directly: is my linked C function `repr` written in the `constexpr` subset of C++? If it is, I can flesh it out into a mostly complete function to obtain the representation of a `double` at compile-time. https://godbolt.org/g/1wUDg7 – Pascal Cuoq May 14 '18 at 13:04

0 Answers0