开发者

using bitset with floating types

Can you have bitset container of floating data types? Example:

bitset<sizeof(float)*sizeof(char)> second(5.5f);
cout << second.to_string() << endl;

It doesn't work correctly. what i'm trying to do is get the bit representati开发者_开发问答on.


bitset only takes a unsigned long as its constructor argument. In your example the float is converted to unsigned long and then used as the argument.

To get what you desire use something along the lines of:

float f = 5.5f;
std::bitset<sizeof(float)*CHAR_BIT> foo(*reinterpret_cast<unsigned long*>(&f));

This reinterprets the "memory" the float is in as memory containing an unsigned long and thus "tricks" the constructor.


In order to build a bitset from a float in a well-defined manner, you should:

  1. ensure your types have compatible sizes;
  2. copy the representation of your float into a compatible integer;
  3. build a bitset from that integer.

Here is a minimal example:

#include <bitset>
#include <cstring>

float f = 1.618;
static_assert(sizeof(float) <= sizeof(long long unsigned int), "wrong sizes"); // 1.
long long unsigned int f_as_int = 0;
std::memcpy(&f_as_int, &f, sizeof(float)); // 2.
std::bitset<8*sizeof(float)> f_as_bitset{f_as_int}; // 3.

But, this won't work as expected on a big endian target whose long long unsigned int is larger than float, because the bitset constructor always pick the least significant bits of the argument, regardless of the endianness. And this sucks.

So, if we want to be complete, we need to address this. To do so, one can copy the float to an integer of the same size (2.), then cast (3.) it to a long long unsigned int, resulting to a endianness-agnostic representation. But yeah, an endianness-agnostic solution is tedious:

#include <bitset>
#include <cstring>
#include <cstdint>
#include <iostream>

namespace details
{
    template<unsigned nbits> struct uint {};
    template<> struct uint<8>  { using type = uint8_t; };
    template<> struct uint<16> { using type = uint16_t; };
    template<> struct uint<32> { using type = uint32_t; };
    template<> struct uint<64> { using type = uint64_t; };
}

template<class T>
using unsigned_integer_of_same_size = typename details::uint<sizeof(T)*8>::type;

int main()
{
    float f = -1./0.;
    static_assert(sizeof(float) <= sizeof(long long unsigned int), "wrong sizes"); // 1.
    unsigned_integer_of_same_size<float> f_as_uint = 0;
    std::memcpy(&f_as_uint, &f, sizeof(float)); // 2.
    std::bitset<8*sizeof(float)> f_as_bitset{f_as_uint}; // 3. && 4.

    std::cout << f_as_bitset << "\n";
}

(live demo)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜