为什么 std::bitset 只支持整型数据类型?为什么不支持浮点数?
Why does std::bitset only support integral data types? Why is float not supported?
尝试生成浮点数的位模式时,如下所示:
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
有理由不支持浮动吗?有没有浮子的替代品?
如果您提供了浮点数,您希望在位集中显示什么?大概是大端格式的 IEEE-7545 二进制 32 浮点数的某种表示形式?那些不以与此相近的方式代表其float
的平台呢?实现是否应该向后弯曲以(可能损失地)将提供的浮点数转换为您想要的?
它没有的原因是浮点数没有标准定义的格式。它们甚至不必是 32 位。它们通常只是在大多数平台上。
C++ 和 C 将在非常小和/或奇怪的平台上运行。标准不能指望"通常情况"。8/16 位 6502 系统的 C/C++ 编译器很抱歉,原生浮点格式是(我认为)使用打包 BCD 编码的 6 字节实体。
这与signed
整数也不受支持的原因相同。二的补码不是普遍的,只是几乎是普遍的。:-)
所有关于浮点格式未标准化、字节序等的常见警告
以下是可能有效的代码,至少在 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
#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
限制。
相关文章:
- 为什么 std::cout 打印浮点数、双精度和长双精度到相同的小数精度?
- 为什么将两个浮点数相加会得到一个整数C++?
- 为什么浮点数的矢量化比双精度更有效?
- 为什么C++在将浮点数转换为字符时没有显示缩小转换错误?
- 为什么编译器接受具有长双精度文本的浮点数的初始化?
- 为什么我不能在不进行任何转换的情况下将浮点数放入任何类型的 ptr 中?
- 分配给浮点数的积分文字除法 - 为什么结果是错误的?
- 浮点数比较为什么没有相等的函数
- 当没有浮点数据类型时,为什么此代码会出现浮点异常
- 为什么我的函数不返回浮点数?
- 为什么 int 和浮点数的总和是 int?
- 为什么自动推断这个变量为双精度而不是浮点数?
- 为什么这种类型是双精度而不是浮点数
- 为什么我无法从 std::stringstream 二进制流中获得全精度(双精度、浮点数)
- 为什么我的函数返回一个整数,尽管我已经将答案指定为浮点数
- 为什么 std::setprecision 显示不存在的精度位以及如何查看实际浮点数
- 为什么 numeric_limits<float>::min() 实际上没有给出尽可能小的浮点数?
- 为什么 std::bitset 只支持整型数据类型?为什么不支持浮点数?
- 为什么浮点数和 int 具有如此不同的最大值,即使它们是相同的位数?
- 为什么浮点数是"unexpected type"