以C++显示浮点类型的二进制表示形式
Showing binary representation of floating point types in C++
考虑以下整型代码:
template <class T>
std::string as_binary_string( T value ) {
return std::bitset<sizeof( T ) * 8>( value ).to_string();
}
int main() {
unsigned char a(2);
char b(4);
unsigned short c(2);
short d(4);
unsigned int e(2);
int f(4);
unsigned long long g(2);
long long h(4);
std::cout << "a = " << +a << " " << as_binary_string( a ) << std::endl;
std::cout << "b = " << +b << " " << as_binary_string( b ) << std::endl;
std::cout << "c = " << c << " " << as_binary_string( c ) << std::endl;
std::cout << "d = " << c << " " << as_binary_string( d ) << std::endl;
std::cout << "e = " << e << " " << as_binary_string( e ) << std::endl;
std::cout << "f = " << f << " " << as_binary_string( f ) << std::endl;
std::cout << "g = " << g << " " << as_binary_string( g ) << std::endl;
std::cout << "h = " << h << " " << as_binary_string( h ) << std::endl;
std::cout << "nPress any key and enter to quit.n";
char q;
std::cin >> q;
return 0;
}
非常简单明了,效果很好,而且非常简单。
编辑
如何编写一个函数来在编译时提取任意浮点类型的二进制或位模式?
说到浮点数,我在我自己的知识的任何现有库中都没有找到类似的东西。我已经在谷歌上搜索了好几天寻找一个,所以后来我试图编写自己的函数,但没有任何成功。自从我最初问这个问题以来,我不再有可用的尝试代码,所以我无法准确地向您展示实现的所有不同尝试及其编译器 - 构建错误。我有兴趣尝试在编译时以通用方式为浮点数生成位模式,并希望将其集成到我现有的类中,该类可以无缝地对任何整型类型执行相同的操作。至于浮动类型本身,我已经考虑了不同的格式以及架构字节序。就我的一般目的而言,浮点类型的标准IEEE版本是我需要关注的全部内容。
当我最初问这个问题时,iBug 建议我编写自己的函数,而我正在尝试这样做。我理解二进制数,内存大小和数学,但是当试图将它们与浮点类型如何存储在一起时,它们的不同部分{符号位,基数和exp}是我遇到最多麻烦的地方。
从那时起,有了那些给出很好答案的建议 - 示例,我能够编写一个非常适合我已经存在的类模板的函数,现在它可以满足我的预期目的。
自己写一个怎么样?
static_assert(sizeof(float) == sizeof(uint32_t));
static_assert(sizeof(double) == sizeof(uint64_t));
std::string as_binary_string( float value ) {
std::uint32_t t;
std::memcpy(&t, &value, sizeof(value));
return std::bitset<sizeof(float) * 8>(t).to_string();
}
std::string as_binary_string( double value ) {
std::uint64_t t;
std::memcpy(&t, &value, sizeof(value));
return std::bitset<sizeof(double) * 8>(t).to_string();
}
您可能需要更改帮助程序变量t
以防浮点数的大小不同。
您也可以逐位复制它们。这较慢,但适用于任意任何类型的。
template <typename T>
std::string as_binary_string( T value )
{
const std::size_t nbytes = sizeof(T), nbits = nbytes * CHAR_BIT;
std::bitset<nbits> b;
std::uint8_t buf[nbytes];
std::memcpy(buf, &value, nbytes);
for(int i = 0; i < nbytes; ++i)
{
std::uint8_t cur = buf[i];
int offset = i * CHAR_BIT;
for(int bit = 0; bit < CHAR_BIT; ++bit)
{
b[offset] = cur & 1;
++offset; // Move to next bit in b
cur >>= 1; // Move to next bit in array
}
}
return b.to_string();
}
你说它不需要是标准的。所以,这是我的电脑上在clang中工作的方法:
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
char *result;
result=new char[33];
fill(result,result+32,'0');
float input;
cin >>input;
asm(
"mov %0,%%eaxn"
"mov %1,%%rbxn"
".intel_syntaxn"
"mov rcx,20hn"
"loop_begin:n"
"shr eaxn"
"jnc loop_endn"
"inc byte ptr [rbx+rcx-1]n"
"loop_end:n"
"loop loop_beginn"
".att_syntaxn"
:
: "m" (input), "m" (result)
);
cout <<result <<endl;
delete[] result;
return 0;
}
这段代码对计算机体系结构做出了一堆假设,我不确定它可以在多少台计算机上工作。
编辑:
我的电脑是64位Mac-Air。该程序基本上通过分配一个 33 字节的字符串并用'0'
填充前 32 个字节来工作(第 33 个字节将自动' '
)。
然后,它使用内联程序集将浮点数存储到 32 位寄存器中,然后反复将其向右移动一位。
如果寄存器中的最后一个位在移位前为 1,则它将被存储到进位标志中。
然后,程序集代码检查 carry 标志,如果它包含 1,则它将字符串中的相应字节增加 1。
由于它之前被初始化为'0'
,它将变成'1'
。
因此,实际上,当程序集中的循环完成时,浮点数的二进制表示形式将存储到字符串中。
此代码仅适用于 x64(它使用 64 位寄存器"rbx"
和"rcx"
来存储循环的指针和计数器),但我认为很容易调整它以在其他处理器上工作。
IEEE 浮点数如下所示
sign exponent mantissa
1 bit 11 bits 52 bits
请注意,尾数前有一个隐藏的 1,指数 是有偏差的,所以 1023 = 0,而不是 2 的补码。 通过 memcpy() 转换为 64 位无符号整数,您可以应用 AND 和 OR 掩码以获取位模式。安排可能是大端序 还是小端序。 您可以通过传递简单的数字轻松确定您的排列方式 如 1 或 2。
通常,人们要么使用std::hexfloat
要么将指向浮点值的指针转换为指向相同大小的无符号整数的指针,并以十六进制格式打印间接值。这两种方法都有助于以高效的方式对浮点进行位级分析。
您可以通过将浮点数/双精度数的地址转换为字符并以这种方式迭代它来滚动您的:
#include <memory>
#include <iostream>
#include <limits>
#include <iomanip>
template <typename T>
std::string getBits(T t) {
std::string returnString{""};
char *base{reinterpret_cast<char *>(std::addressof(t))};
char *tail{base + sizeof(t) - 1};
do {
for (int bits = std::numeric_limits<unsigned char>::digits - 1; bits >= 0; bits--) {
returnString += ( ((*tail) & (1 << bits)) ? '1' : '0');
}
} while (--tail >= base);
return returnString;
}
int main() {
float f{10.0};
double d{100.0};
double nd{-100.0};
std::cout << std::setprecision(1);
std::cout << getBits(f) << std::endl;
std::cout << getBits(d) << std::endl;
std::cout << getBits(nd) << std::endl;
}
我的机器上的输出(注意第三个输出中的符号翻转):
01000001001000000000000000000000
0100000001011001000000000000000000000000000000000000000000000000
1100000001011001000000000000000000000000000000000000000000000000
- 浮点数为 32 位和 64 位二进制表示形式
- 如何将uint8_t的二进制表示形式读取为数字
- 二进制表示,如何获得"相关位"?
- 了解浮点数的二进制表示形式
- 如何在 mfc c++ 中流式传输.zip文件夹的二进制表示形式
- 浮点逆二进制表示
- 以C++显示浮点类型的二进制表示形式
- 在二进制表示中将二进制 std::string 转换为 int
- 如何在计算机内存中打印长双重表示的二进制表示
- 将uint8_t转换为其二进制表示
- 与类型的二进制表示相关的技术词是什么?
- 以从 a 到 b 的数字的二进制表示形式计算 "1" 位数字的算法
- C++-如何获得十进制数的二进制表示
- 如何将一个数字的二进制表示中的所有1相加
- 涡轮 C 中的二进制表示
- 数据C++的二进制表示显示的数据不正确
- 二进制表示形式
- 打印有符号整数的二进制表示形式
- BigInt实现-将字符串转换为存储为无符号int的二进制表示
- 如何用非标准二进制表示法对数字进行算术运算