简体   繁体   中英

Why does std::bitset only support integral data types? Why is float not supported?

On trying to generate the bit pattern of a float as follows:

std::cout << std::bitset<32>(32.5) << std::endl;

the compiler generates this warning:

warning: implicit conversion from 'double' to 'unsigned long long' changes value
  from 32.5 to 32 [-Wliteral-conversion]
 std::cout << std::bitset<32>(32.5) << std::endl;

Output on ignoring warning :) :

00000000000000000000000000100000

Why cannot bitset detect floats and correctly output bit sequence, when casting to char* and walking memory does show correct sequence? This works, but is machine dependent on byte ordering and mostly unreadable:

template <typename T>
  void printMemory(const T& data) {
    const char* begin = reinterpret_cast<const char*>(&data);
    const char* end = begin + sizeof(data);
    while(begin != end)
      std::cout << std::bitset<CHAR_BIT>(*begin++) << " ";
    std::cout << std::endl;
}

Output:

00000000 00000000 00000010 01000010 

Is there a reason not to support floats? Is there an alternative for floats?

What would you expect to appear in your bitset if you supplied a float? Presumably some sort of representation of an IEEE-7545 binary32 floating point number in big-endian format? What about platforms that don't represent their float s in a way that's even remotely similar to that? Should the implementation bend over backwards to (probably lossily) convert the float supplied to what you want?

The reason it doesn't is that there is no standard defined format for floats. They don't even have to be 32 bits. They just usually are on most platforms.

C++ and C will run on very tiny and/or odd platforms. The standard can't count on what's 'usually the case'. There were/are C/C++ compilers for 8/16 bit 6502 systems who's sorry excuse for a native floating point format was (I think) a 6-byte entity that used packed BCD encoding .

This is the same reason that signed integers are also unsupported. Two's complement is not universal, just almost universal. :-)

With all the usual warnings about floating point formats not being standardised, endianness, etc etc

Here is code that will probably work, at least on x86 hardware.

#include <bitset>
#include <iostream>
#include <type_traits>
#include <cstring>

constexpr std::uint32_t float_to_bits(float in)
{
    std::uint32_t result = 0;
    static_assert(sizeof(float) == sizeof(result), "float is not 32 bits");
    constexpr auto size = sizeof(float);
    std::uint8_t buffer[size] = {};
    // note - memcpy through a byte buffer to satisfy the
    // strict aliasing rule.
    // note that this has no detrimental effect on performance
    // since memcpy is 'magic'
    std::memcpy(buffer, std::addressof(in), size);
    std::memcpy(std::addressof(result), buffer, size);
    return result;
}

constexpr std::uint64_t float_to_bits(double in)
{
    std::uint64_t result = 0;
    static_assert(sizeof(double) == sizeof(result), "double is not 64 bits");
    constexpr auto size = sizeof(double);
    std::uint8_t buffer[size] = {};
    std::memcpy(buffer, std::addressof(in), size);
    std::memcpy(std::addressof(result), buffer, size);
    return result;
}


int main()
{
    std::cout << std::bitset<32>(float_to_bits(float(32.5))) << std::endl;
    std::cout << std::bitset<64>(float_to_bits(32.5)) << std::endl;
}

example output:

01000010000000100000000000000000
0100000001000000010000000000000000000000000000000000000000000000
#include <iostream>
#include <bitset>
#include <climits>
#include <iomanip>

using namespace std;

template<class T>
auto toBitset(T x) -> bitset<sizeof(T) * CHAR_BIT>
{
    return bitset<sizeof(T) * CHAR_BIT>{ *reinterpret_cast<unsigned long long int *>(&x) };
}

int main()
{
    double x;
    while (cin >> x) {
        cout << setw(14) << x << " " << toBitset(x) << endl;
    }

    return 0;
}

https://wandbox.org/permlink/tCz5WwHqu2X4CV1E

sadly this fails if argument type is bigger than size of unsigned long long , for example it will fail for long double . This is limit of bitset constructor.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM