为什么std :: bitset只支持整数数据类型?为什么不支持浮动?

时间:2017-10-20 20:34:38

标签: c++ std-bitset

尝试按如下方式生成浮点的位模式:

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

编译器生成此警告:

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;

忽略警告输出:):

00000000000000000000000000100000

为什么无法bitset检测浮点数并正确输出位序列,在转换为char *时,行走内存确实显示正确的顺序? 这是有效的,但机器依赖于字节顺序,并且几乎不可读:

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;
}

输出:

00000000 00000000 00000010 01000010 

有没有理由不支持花车?浮筒有替代品吗?

3 个答案:

答案 0 :(得分:3)

如果您提供浮动,您希望在您的bitset中出现什么?大概是以big-endian格式表示IEEE-7545 binary32浮点数的某种表示形式?那些不能代表float以及甚至远程类似的平台的平台呢?如果实现向后弯曲到(可能是有损)将提供的浮动转换为你想要的?

它没有的原因是浮动没有标准的定义格式。他们甚至不必是32位。它们通常位于大多数平台上。

C ++和C将在非常小的和/或奇怪的平台上运行。该标准无法依靠通常的情况&#39;。有8/16位6502系统的C / C ++编译器,对于原生浮点格式而言,遗憾的是(我认为)使用packed BCD encoding的6字节实体。

这与signed整数也不受支持的原因相同。两个补语不是普遍的,几乎是普遍的。 : - )

答案 1 :(得分:2)

关于浮点格式的所有常见警告都没有标准化,字节顺序等等

以下代码可能工作,至少在x86硬件上。

#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;
}

示例输出:

01000010000000100000000000000000
0100000001000000010000000000000000000000000000000000000000000000

答案 2 :(得分:1)

#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

遗憾的是,如果参数类型大于unsigned long long的大小,则会失败,例如long double将失败。这是bitset构造函数的限制。