1

My question is similar to this question which deals with positive floating point values.

In my case, I'm dealing with both positive and negative float values, and want to store it in an int64_t type.

NOTE: I wish to use memcpy rather than relying on a union (which is UB in C++).

François Andrieux
  • 28,148
  • 6
  • 56
  • 87
jeffreyveon
  • 13,400
  • 18
  • 79
  • 129
  • 1
    Are you sure that's a good idea? Have you checked `sizeof(float)` and `sizeof(int64_t)`? – Ted Lyngmo Mar 04 '20 at 16:14
  • I'm aware of the gotchas. Only need to support X86_64. – jeffreyveon Mar 04 '20 at 16:18
  • 1
    @jeffreyveon: Did you actually want `double` like I answered it for? I assumed that because you said `int64_t`. But if you're using `float` the int type should be `int32_t`. – R.. GitHub STOP HELPING ICE Mar 04 '20 at 17:53
  • @R..GitHubSTOPHELPINGICE: Or you'd want to put the bits at the top of an int64_t, or sign-extend, if for some reason you need to put 32-bit floats into 64-bit integers. That might be more efficient than converting to double, especially if you want to get the `float` bit-pattern back out more efficiently (just broadcast the sign bit, logical right shift by 1, and XOR the low 31 bits. Without needing to also do double->float FP conversion.) – Peter Cordes Mar 04 '20 at 22:34
  • @PeterCordes I'm actually dealing with floats so essentially do a `float -> double` conversion prior. If you can add a quick answer with a code snippet of doing this without that conversion, I will be happy to upvote and others who stumble on this question might also benefit. – jeffreyveon Mar 05 '20 at 02:09
  • Actually, instead of doing the `float -> double` conversion, I just ended up using `int32_t` and then storing that value as `int64_t`. – jeffreyveon Mar 05 '20 at 02:22
  • @jeffreyveon: yeah, you need a sign-extension at some point. You might be able to get it for free by loading a 32-bit float bit-patterns into an int64_t temporary and flipping the low 31 bits of that based on the sign. – Peter Cordes Mar 05 '20 at 02:40

1 Answers1

2

As described in my comment on the linked question about a 32-bit variant:

...basically you can either use a signed int32 and invert the low 31 bits if the sign bit is set. A similar approach works if you want unsigned but you have to add the 0x80000000 bias.

As code, adapted to 64-bit:

int64_t order_preserving_repr(double x)
{
    int64_t k;
    memcpy(&k, &x, sizeof k);
    if (k<0) k ^= INT64_MAX;
    return k;
}
R.. GitHub STOP HELPING ICE
  • 208,859
  • 35
  • 376
  • 711
  • 2
    Just to make sure that you don't accidentally have UB on exotic systems, I would recommend `static_assert(sizeof x == sizeof k)` – eerorika Mar 04 '20 at 16:39
  • Yes, the question was about storing a `float` in an `int64_t` so the `sizeof` test would probably fail on most platforms. – Ted Lyngmo Mar 04 '20 at 16:52
  • @eerorika: The whole question makes no sense if you're not assuming Annex F and IEEE floating point representation, which guarantees sizes match. – R.. GitHub STOP HELPING ICE Mar 04 '20 at 17:52
  • 1
    @R..GitHubSTOPHELPINGICE Then perhaps go as far as `static_assert(std::numeric_limits:: is_iec559())` to make sure that the function makes sense. – eerorika Mar 04 '20 at 17:55